c# 如何用lock解決緩存擊穿
背景
緩存擊穿是指緩存中沒有但數據庫中有的數據(一般是緩存時間到期),這時由於並發用戶特別多,同時讀緩存沒讀到數據,又同時去數據庫去取數據,引起數據庫壓力瞬間增大,造成過大壓力。
解決方案
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解決緩存擊穿的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- .NET並發編程之函數閉包
- Js中安全獲取Object深層對象的方法實例
- 詳解Redis分佈式鎖的原理與實現
- Go singleflight使用以及原理
- 一文瞭解Java讀寫鎖ReentrantReadWriteLock的使用