欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

c# 如何用lock解决缓存击穿

程序员文章站 2022-03-19 14:57:52
背景缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。解决方案1、设置热点数据...

背景

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

解决方案

1、设置热点数据永远不过期。

2、加互斥锁,互斥锁参考代码如下:

2.1、根据key生成object()

private static object getmemorycachelockobject(string key)
    {
      string cachelockkey = string.format(memorycachelockobjectformat, key);
      lock (cacheobject)
      {
        var lockobject = cacheobject[cachelockkey];
        if (lockobject == null)
        {
          // 取得每個 key專屬的 lock object;若同時有多個 thread要求相同資料,只會(到資料庫)查第一次,剩下的從 cache讀取
          lockobject = new object();
          cacheobject.set(
            cachelockkey,
            lockobject,
            new system.runtime.caching.cacheitempolicy()
            {
              absoluteexpiration = datetimeoffset.utcnow.addminutes(10)
            }
          );
        }

        return lockobject;
      }
    }

2.2、lock住getmemorycachelockobject(key)

public t get<t>(string key, func<t> getdatawork, timespan absoluteexpiretime, bool forcerefresh = false, bool returncopy = true) where t : class
    {
      try
      {
        lock (getmemorycachelockobject(key))
        {
          /*
system.argumentnullexception: value cannot be null.
at system.threading.monitor.enter(object obj)
at bqoolcommon.helpers.cache.memorycachelayer.get[t](string key, func`1 getdatawork, timespan absoluteexpiretime, boolean forcerefresh, boolean returncopy) in d:\source\bqoolcommon\bqoolcommon.helpers\cache\memorycachelayer.cs:line 46
           */
          t result = cacheobject[key] as t;

          if (result != null && forcerefresh)
          {// 是否清除cache,強制重查
            result = null;
          }

          if (result == null)
          {
            //執行取得資料的委派作業
            result = getdatawork();

            if (result != null)
            {
              set(key, result, absoluteexpiretime);
            }
          }

          if (returncopy)
          {
            //複製一份新的參考
            string serialize = jsonconvert.serializeobject(result);
            return jsonconvert.deserializeobject<t>(serialize);
          }
          else
          {
            return result;
          }
        }
      }
      catch
      {
        return getdatawork();
      }
    }

总结说明

1、缓存中有数据,直接走下述代码就返回结果了

 t result = cacheobject[key] as t;

2、缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前,其他并行进入的线程会等待,再重新去缓存取数据。这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现。

try
      {
        lock (getmemorycachelockobject(key))
        {
          /*
system.argumentnullexception: value cannot be null.
at system.threading.monitor.enter(object obj)
at bqoolcommon.helpers.cache.memorycachelayer.get[t](string key, func`1 getdatawork, timespan absoluteexpiretime, boolean forcerefresh, boolean returncopy) in d:\source\bqoolcommon\bqoolcommon.helpers\cache\memorycachelayer.cs:line 46
           */
          t result = cacheobject[key] as t;

3、取得每个 key专有的 lock object;若同时有多个 thread要求相同资料,只会(到数据库)查第一次,剩下的从 cache读取。

string cachelockkey = string.format(memorycachelockobjectformat, key);
      lock (cacheobject)
      {
        var lockobject = cacheobject[cachelockkey];
        if (lockobject == null)
        {
          // 取得每個 key專屬的 lock object;若同時有多個 thread要求相同資料,只會(到資料庫)查第一次,剩下的從 cache讀取
          lockobject = new object();

以上就是c# 如何用lock解决缓存击穿的详细内容,更多关于c# lock解决缓存击穿的资料请关注其它相关文章!