1. 程式人生 > >Redis和DB資料不一致解決方案

Redis和DB資料不一致解決方案

大多情況下,我們使用快取都是這樣的策略:先讀快取,讀取不到就讀資料庫然後同步到快取中。

問題出現場景

問題就是在併發訪問中,不論是先寫庫,再刪除快取;還是先刪快取,再寫庫,都有可能出現數據不一致的情況

1、在併發中是無法保證讀寫的先後順序的,如果刪掉了快取還沒來得及寫庫,另一個執行緒就過來讀取發現快取為空就去資料庫讀取並寫入快取,此時快取中為髒資料。
2、如果先寫了庫,再刪除快取前,寫庫的執行緒宕機了,沒有刪除掉快取,則也會出現資料不一致情況。
3、如果是redis叢集,或者主從模式,寫主讀從,由於redis複製存在一定的時間延遲,也有可能導致資料不一致。

優化解決方案

雙刪 + 超時

在寫庫前後都進行redis.del(key)操作,並且設定合理的超時時間。這樣最差的情況是在超時時間記憶體在不一致,當然這種情況極其少見,可能的原因就是服務宕機。此種情況可以滿足絕大多數需求。
當然這種策略要考慮redis和資料庫主從同步的耗時,所以在第二次刪除前最好休眠一定時間,比如500毫秒,這樣毫無疑問又增加了寫請求的耗時

通過讀取binlog的方式,非同步淘汰快取

這裡寫圖片描述

好處:業務程式碼侵入性低,將快取與資料庫不一致的時間儘可能縮小。

binlog介紹:Mysql的binlog日誌作用是用來記錄mysql內部增刪改查等對mysql資料庫有更新的內容的記錄(對資料庫的改動),對資料庫的查詢select或show等不會被binlog日誌記錄;主要用於資料庫的主從複製以及增量恢復。(binlog也可以設定日誌過期時間)

binlog日誌模式
Mysql複製主要有三種方式:基於SQL語句的複製(statement-based replication, SBR),基於行的複製(row-based replication, RBR),混合模式複製(mixed-based replication, MBR)。對應的,binlog的格式也有三種:STATEMENT,ROW,MIXED。

1、STATEMENT模式(SBR)
每一條會修改資料的sql語句會記錄到binlog中。優點是並不需要記錄每一條sql語句和每一行的資料變化,減少了binlog日誌量,節約IO,提高效能。缺點是在某些情況下會導致master-slave
中的資料不一致(如sleep()函式, last_insert_id(),以及user-defined functions(udf)等會出現問題) 2、ROW模式(RBR) 不記錄每條sql語句的上下文資訊,僅需記錄哪條資料被修改了,修改成什麼樣了。而且不會出現某些特定情況下的儲存過程、或function、或trigger的呼叫和觸發無法被正確複製的問題。缺點是會產生大量的日誌,尤其是alter table的時候會讓日誌暴漲。 3、MIXED模式(MBR) 以上兩種模式的混合使用,一般的複製使用STATEMENT模式儲存binlog,對於STATEMENT模式無法複製的操作使用ROW模式儲存binlog,MySQL會根據執行的SQL語句選擇日誌儲存方式。