如何處理快取一致性,快取穿透,快取雪崩,快取併發解決方案

最近在做架構使用redis做快取,碰到了一些問題,考慮資料量很大的時候,會遇到的幾個問題:

如何處理快取一致性,快取穿透,快取雪崩,快取併發解決方案

1。 關於快取一致性

當我們更新了資料庫的資料,先刪除快取,然後在更新資料庫,如果刪除快取失敗,那就不要更新資料庫,如果說刪除快取成功,而更新資料庫失敗,那查詢的時候只是從資料庫裡查了舊的資料而已,這樣就能保持資料庫與快取的一致性。要求高的場景下,使用實時更新策略-即資料有變化時,更新的執行緒直接同步快取資料如果允許,可以單獨架設第三方方案,來同步快取資料,常見的有釋出訂閱/MQ(例如rabbitmq)方式容忍度較高的場景,可使用快取過期策略 ——- 允許資料短期不一致,定時任務,適合資料變化特別不頻繁的情況。

2。快取穿透的情況

快取穿透查詢一個數據庫中不存在的資料,每次都會訪問DB,如果有人惡意破壞,很可能直接對DB造成過大地壓力, 快取被穿透。在流量大時,可能DB就掛掉了。

方案:第一如果一個查詢返回的資料為空,不管是資料不存在還是系統故障,我們仍然把這個結果進行快取,但是它的過期時間會很短,最長不超過5分鐘。第二是根據key獲取value值為空時,鎖上,從資料庫中load資料後再釋放鎖。若其它執行緒獲取鎖失敗,則等待一段時間後重試。這裡要注意,分散式環境中要使用分散式鎖,單機的話可以使用普通的鎖(synchronized、Lock)。第三是使用BloomFilter,是一個佔用記憶體空間比較小而且效率很高的隨機資料結構,它由一個bit陣列和一組Hash演算法構成。在java中可以使用guava中的bloom Filter,它可以用於判斷一個元素是否在一個集合中。

3。快取雪崩的情況

快取雪崩是指在我們設定快取時採用了相同的過期時間,導致快取在某一時刻同時失效,請求全部轉發到DB,DB瞬時壓力過重雪崩。和快取擊穿不同的是,快取擊穿指併發查同一條資料,快取雪崩是不同資料都過期了,很多資料都查不到從而查資料庫。在同一時間內大量鍵過期(失效),接著來的一大波請求瞬間都落在了資料庫中導致連線異常。

方案:第一是將系統中key的快取失效時間均勻地錯開,防止統一時間點有大量的key對應的快取失效。比如可以在原有的失效時間基礎上增加一個隨機值,比如幾分鐘隨機,這樣每一個快取的過期時間的重複率就會降低。第二是增加互斥鎖,控制資料庫請求,重建快取。加鎖排隊只是為了減輕資料庫的壓力,但並沒有提高系統吞吐量。使用鎖或佇列、設定過期標誌更新快取、為key設定不同的快取失效時間。第三是設定redis叢集和DB叢集的高可用,如果redis出現宕機情況,可以立即由別的機器頂替上來。這樣可以防止一部分的風險。

4。快取併發問題

多個redis的client同時set key引起的併發問題,由於redis自身是單執行緒操作,多個client併發操作,按照先到先執行的原則,先到的先執行,其餘的阻塞。當然,另外的解決方案是把redis。set操作放在佇列中使其序列化,必須的一個一個執行,當然加鎖也是可以的。