緩存同步、如何保證緩存一致性、緩存誤用(^_^)

緩存誤用

緩存,是互聯網分層架構中,非常重要的一個部分,通常用它來降低數據庫壓力,提升系統整體性能,縮短訪問時間。

有架構師說“緩存是萬金油,哪裏有問題,加個緩存,就能優化”,緩存的濫用,可能會導致一些錯誤用法。

緩存,你真的用對了麼?

誤用二:使用緩存未考慮雪崩

常規的緩存玩法,如上圖:


服務先讀緩存,緩存命中則返回
緩存不命中,再讀數據庫

什麼時候會產生雪崩?
答:如果緩存掛掉,所有的請求會壓到數據庫,如果未提前做容量預估,可能會把數據庫壓垮(在緩存恢復之前,數據庫可能一直都起不來),導致系統整體不可服務。

如何應對潛在的雪崩?
答:提前做容量預估,如果緩存掛掉,數據庫仍能扛住,才能執行上述方案。

否則,就要進一步設計。

常見方案一:高可用緩存


 

如上圖:使用高可用緩存集羣,一個緩存實例掛掉後,能夠自動做故障轉移。

 

常見方案二:緩存水平切分


 

如上圖:使用緩存水平切分(推薦使用一致性哈希算法進行切分),一個緩存實例掛掉後,不至於所有的流量都壓到數據庫上。

數據不一致解決場景及解決方案

答:發生寫請求後(不管是先操作DB,還是先淘汰Cache),在主從數據庫同步完成之前,如果有讀請求,都可能發生讀Cache Miss,讀從庫把舊數據存入緩存的情況。此時怎麼辦呢?

一、數據庫主從不一致


先回顧下,無緩存時,數據庫主從不一致問題。


 

如上圖,發生的場景是,寫後立刻讀:


(1)主庫一個寫請求(主從沒同步完成)
(2)從庫接着一個讀請求,讀到了舊數據
(3)最後,主從同步完成
 

導致的結果是:主動同步完成之前,會讀取到舊數據。

 

可以看到,主從不一致的影響時間很短,在主從同步完成後,就會讀到新數據。

 

二、緩存與數據庫不一致


再看,引入緩存後,緩存和數據庫不一致問題。


 

如上圖,發生的場景也是,寫後立刻讀:


(1+2)先一個寫請求,淘汰緩存,寫數據庫

 

(3+4+5)接着立刻一個讀請求,讀緩存,cache miss,讀從庫,寫緩存放入數據,以便後續的讀能夠cache hit(主從同步沒有完成,緩存中放入了舊數據)

 

(6)最後,主從同步完成

 

導致的結果是:舊數據放入緩存,即使主從同步完成,後續仍然會從緩存一直讀取到舊數據。

 

可以看到,加入緩存後,導致的不一致影響時間會很長,並且最終也不會達到一致。

 

三、問題分析


可以看到,這裏提到的緩存與數據庫數據不一致,根本上是由數據庫主從不一致引起的。當主庫上發生寫操作之後,從庫binlog同步的時間間隔內,讀請求,可能導致有舊數據入緩存。

 

思路:那能不能寫操作記錄下來,在主從時延的時間段內,讀取修改過的數據的話,強制讀主,並且更新緩存,這樣子緩存內的數據就是最新。在主從時延過後,這部分數據繼續讀從庫,從而繼續利用從庫提高讀取能力。

四、不一致解決方案


選擇性讀主


可以利用一個緩存記錄必須讀主的數據。


 

如上圖,當寫請求發生時:


(1)寫主庫
(2)將哪個庫,哪個表,哪個主鍵三個信息拼裝一個key設置到cache裏,這條記錄的超時時間,設置爲“主從同步時延”
 

PS:key的格式爲“db:table:PK”,假設主從延時爲1s,這個key的cache超時時間也爲1s。

 

 

如上圖,當讀請求發生時:


這是要讀哪個庫,哪個表,哪個主鍵的數據呢,也將這三個信息拼裝一個key,到cache裏去查詢,如果,


(1)cache裏有這個key,說明1s內剛發生過寫請求,數據庫主從同步可能還沒有完成,此時就應該去主庫查詢。並且把主庫的數據set到緩存中,防止下一次cahce miss。
(2)cache裏沒有這個key,說明最近沒有發生過寫請求,此時就可以去從庫查詢

以此,保證讀到的一定不是不一致的髒數據。

 

PS:如果系統可以接收短時間的不一致,建議建議定時更新緩存就可以了。避免系統過於複雜。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章