背景
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
解决方案
1、设置热点数据永远不过期。
2、加互斥锁,互斥锁参考代码如下:
2.1、根据key生成object()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
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、缓存中有数据,直接走下述代码就返回结果了
1
|
T result = CacheObject[key] as T; |
2、缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前,其他并行进入的线程会等待,再重新去缓存取数据。这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现。
1
2
3
4
5
6
7
8
9
10
|
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读取。
1
2
3
4
5
6
7
8
|
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解决缓存击穿的资料请关注服务器之家其它相关文章!
原文链接:https://www.cnblogs.com/lyl6796910/p/14354503.html