如今許多網際網路應用系統都重度依賴快取來提高讀操作的效能,對於這些系統來說如何正確地使用快取至關重要。本文從快取讀取這個視角來討論快取架構設計上的一些思路。重點關注如何防止快取雪崩。
引入快取後,讀資料的流程如下:
在正常情況下,一旦miss就去查db是沒有問題的。但是如果大量快取集中在某一時間段失效,將導致所有請求都去訪問後端的db,db壓力會很大,甚至被壓垮,造成雪崩。
電商系統的某個大促活動的首頁,首頁有很多新上架的商品。活動開始前,技術團隊對快取做了預熱,由於是指令碼化預熱,這些商品的cache資料幾乎都是同時建立好,並且過期時間都設定為5分鐘。這就會導致這大量的商品資料在5分鐘後集中失效。
cache系統剛上線(或者剛從崩潰中恢復過來),沒有對cache進行預熱。cache中什麼也沒有,這時瞬時大流量過來也會產生雪崩。
針對上面的場景一,可以對cache的過期時間做乙個均勻分布的處理。比如1-5分鐘內,隨機分布。
針對場景二,可以考慮使用排斥鎖(mutex)。即第乙個執行緒過來讀取cache,發現沒有,就去訪問db。後續執行緒再過來就需要等待第乙個執行緒讀取db成功,cache裡的value變得可用,後續執行緒返回新的value。偽**如下:
public object getcachevalue(string key, int expiredtime) else else
}} finally
return cachevalue;}}
方案細節:排斥鎖方案對快取過期是零容忍的:cache一旦過期,後續所有讀操作就必須返回新的value。如果我們稍微放寬點限制:在cache過期時間t到達後,允許短時間內部分讀請求返回舊值,我們就能提出兼顧吞吐率的方案。實際上既然用了cache,系統就默許了容忍cache和db的資料短時間的不一致。
限制放寬後,下面我們提出乙個優化思路。時間t到達後,cache中的key和value不會被清掉,而只是被標記為過期(邏輯上過期,物理上不過期),然後程式非同步去重新整理cache。而後續部分讀執行緒在前面的執行緒重新整理cache成功之前,暫時獲取cache中舊的value返回。一旦cache重新整理成功,後續所有執行緒就能直接獲取cache中新的value。可以看到,這個思路很大程度上減少了排斥鎖的使用(雖然並沒有完全消除排斥鎖)。
下面先看下偽**:
public object getcachevalue(string key, int expiredtime) else } }
} catch (exception ex) finally
});return cachevalue;
}}// 判斷快取標記是否過期
private
boolean
i***pired(string signkey)
return
false;
}// 設定signkey的過期時間
private
void
setsign(string key, int expiredseconds)
方案細節本文討論了防止快取雪崩的三個方案:
前兩個方案各自有適用的場景。第三個方案具備一定的通用性。也適用於方案一二的場景。是我推薦的方案
Redis快取設計之快取穿透 快取雪崩
提高系統響應速度,加速讀寫,redis將數全都存放在記憶體中,響應速度更快。降低了後台的負載,減少了對後端的直接訪問 資料一致性問題,快取層的資料與儲存層的資料可能存在不一致的問題 維護複雜度高了,加入快取後要同時處理快取曾和持久層的 邏輯 快取穿透就是指查詢乙個根本不存在的資料,導致很多請求直接穿...
快取穿透 快取雪崩
一 快取穿透 描述 快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷發起請求,如發起為id為 1 的資料或id為特別大不存在的資料。這時的使用者很可能是攻擊者,攻擊會導致資料庫壓力過大。解決方案 1 介面層增加校驗,如使用者鑑權校驗,id做基礎校驗,id 0的直接攔截 2 從快取取不到的資料,在...
快取之快取擊穿 穿透 雪崩
redis高頻面試題 快取穿透 概念 有乙個查詢介面,頻繁接受到資料庫中並不存在的查詢條件,每次根據key查詢快取中都查不到,則這些查詢請求紛紛落到資料庫上,請求量大,造成資料庫頻繁io最終宕機。例如介面是根據id獲取使用者,查詢引數為 1 2這種資料庫根本沒有的資料。解決方案 1.在redis中快...