一起分析Redis緩存一致性、緩存穿透、緩存擊穿及緩存雪崩問題

本篇文章給大家帶來了關于redis的相關知識,其中主要介紹了關于緩存一致性、緩存穿透、緩存擊穿、緩存雪崩以及緩存數據的寫同步的與db一致性的問題,下面一起來看一下,希望對大家有幫助。

一起分析Redis緩存一致性、緩存穿透、緩存擊穿及緩存雪崩問題

相關推薦:《分析redis中熱點key存儲問題,聊聊緩存異常的解決方法》

(1)緩存失效一致性問題

一般緩存的使用方式是:先讀取緩存,若不存在則從DB中讀取,并將結果寫入到緩存中;下次數據讀取時便可以直接從緩存中獲取數據。【相關推薦:redis

數據的修改是直接失效緩存數據,再修改DB內容,避免DB修改成功,但由于網絡或者其他問題導致緩存數據沒有清理,造成了臟數據。但這樣仍然無法避免臟數據的產生,一種并發的場景下:假設業務對數據Key:Hello Value:World有大量的讀取和修改請求。線程A向OCS讀取Key:Hello,得到Not Found結果,開始向DB請求數據,得到數據Key:Hello Value:World;接下來準備向OCS寫入此條數據,但在寫入OCS前(網絡,CPU都等可能導致A線程處理速度降低)另一B線程請求修改數據Key:Hello Value:OCS,首先執行失效緩存動作(因為B線程并不知道是否有此條數據,因此直接執行失效操作),OCS成功處理了失效請求。轉回到A線程繼續執行寫入OCS,將Key:Hello Value:World寫入到緩存中,A線程任務結束;B線程也成功修改了DB數據內容為Key:Hello Value:OCS。為了解決這個問題,OCS擴充了Memcached協議(公有云即將支持),增加了deleteAndIncVersion接口。此接口并不會真的刪除數據,而是給數據打了標簽,表明已失效狀態,并且增加數據版本號;如果數據不存在則寫入NULL,同時也生成隨機數據版本號。OCS寫入支持原子對比版本號:假設傳入的版本號與OCS保存的數據版本號一致或者原數據不存在,則準許寫入,否則拒絕修改。

回到剛才的場景上:線程A向OCS讀取Key:Hello,得到Not Found結果,開始向DB請求數據,得到數據Key:Hello Value:World;接下來準備向OCS寫入此條數據,版本號信息默認為1;在A寫入OCS前另一個B線程發起了動作修改數據Key:Hello Value:OCS,首先執行刪除緩存動作,OCS順利處理了deleteAndIncVersion請求,生成了隨機版本號12345(約定大于1000)。轉回到A線程繼續執行寫入OCS,請求將Key:Hello Value:World寫入,此時緩存系統發現傳入的版本號信息不匹配(1 != 12345),寫入失敗,A線程任務結束;B線程也成功修改了DB數據內容為Key:Hello Value:OCS。

此時OCS中的數據為Key:Hello Value:NULL Version:12345;DB中的數據為Key:Hello Value:OCS,后續讀任務時會再次嘗試將DB中的數據寫入到OCS中。

(2)緩存數據的寫同步的與DB一致性問題

隨著網站規模增長和可靠性的提升,會面臨多IDC的部署,每個IDC都有一套獨立的DB和緩存系統,這時緩存一致性又成了突出的問題。

首先緩存系統為了保證高效率,會杜絕磁盤IO,哪怕是寫BINLOG;當然緩存系統為了性能可以只同步刪除,不同步寫入,那么緩存的同步一般會優先于DB同步到達(畢竟緩存系統的效率要高得多),那么就會出現緩存中無數據,DB中是舊數據的場景。此時,有業務請求數據,讀取緩存Not Found,從DB讀取并加載到緩存中的仍然是舊數據,DB數據同步到達時也只更新了DB,緩存臟數據無法被清除。

一起分析Redis緩存一致性、緩存穿透、緩存擊穿及緩存雪崩問題

從上面的情況可以看出,不一致的根本原因是異構系統之間無法協同同步,不能保證DB數據先同步,緩存數據后同步。所以就要考慮緩存系統如何等待DB同步,或者能否做到兩者共用一套同步機制?緩存同步也依賴DB BINLOG是一個可行的方案。

IDC1中的DB,通過BINLOG同步給IDC2中的DB,此事IDC2-DB數據修改也會產生自身的BINLOG,緩存的數據同步就可以通過IDC2-DB BINLOG進行。緩存同步模塊分析BINLOG后,失效相應的緩存Key,同步從并行改為串行,保證了先后順序。

(3)緩存穿透(DB承受了沒有必要的查詢流量)

方法一:是布隆過濾器。它是一種空間效率極高的概率型算法和數據結構,用于判斷一個元素是否在集合中(類似Hashset)。它的核心是一個很長的二進制向量和一系列的hash函數。使用谷歌的guava實現布隆過濾器。1)存在誤算率,隨著存入的元素數量增加,誤算率也隨著增加2)一般情況下不能從布隆過濾器刪除元素3)數組長度以及hash函數個數確定過程復雜,布隆過濾器的使用場景?1)垃圾郵件地址過濾(地址數量很龐大)2)爬蟲URL地址去重3)解決緩存擊穿問題

方法二:存儲空結果,并設置空結果的時間

(4)緩存雪崩(緩存設置同一過期時間,引起的DB洪峰)

方法一:大多數系統設計者考慮用加鎖或者隊列的方式保證緩存的單線 程(進程)寫,從而避免失效時大量的并發請求落到底層存儲系統上

方法二:失效時間隨機值

(5)緩存擊穿(熱點Key,大量并發讀請求引起的小雪崩)

? ? 緩存在某個時間點過期的時候,恰好在這個時間點對這個Key有大量的并發請求過來,這些請求發現緩存過期一般都會從后端DB加載數據并回設到緩存,這個時候大并發的請求可能會瞬間把后端DB壓垮

方法一:1.使用分布是緩存支持的互斥鎖(mutex key),去set一個mutex key,當操作返回成功時,再進行load db的操作并回設緩存,也就是load DB 只會一個線程處理。

方法二:提前”使用互斥鎖(mutex key):在value內部設置1個超時值(timeout1), timeout1比實際的memcache timeout(timeout2)小。當從cache讀取到timeout1發現它已經過期時候,馬上延長timeout1并重新設置到cache。然后再從數據庫加載數據并設置到cache中。增加了業務代碼的侵入過多,以及增加了編碼復雜性

方法三: “永遠不過期”: 從redis上看,確實沒有設置過期時間,這就保證了,不會出現熱點key過期問題,也就是“物理”不過期。從功能上看,如果不過期,那不就成靜態的了嗎?所以我們把過期時間存在key對應的value里,如果發現要過期了,通過一個后臺的異步線程進行緩存的構建,也就是“邏輯”過期

(6)緩存系統常見的緩存滿了和數據丟失問題

需要根據具體業務分析,通常我們采用LRU策略處理溢出,Redis的RDB和AOF持久化策略來保證一定情況下的數據安全。

更多編程相關知識,請訪問:redis!!

? 版權聲明
THE END
喜歡就支持一下吧
點贊12 分享