數據一致性解決方案總結
我們在系統中,主要進行了數據冗余,那么就會帶來數據一致性的問題。常見的數據一致性問題有:數據庫主從同步延遲導致的讀數據不一致;數據庫主主之間數據的不一致;緩存和數據庫之間的數據不一致。
一、數據庫主從數據不一致解決方案
問題產生:
? 數據庫主從數據不一致問題的產生一般是由于數據庫主從同步時延導致的,當我們往主庫中寫數據之后,立刻對這個數據發起了讀請求,但是此時可能數據還沒有從主庫同步到從庫中,從而產生了數據不一致的問題。
解決方案:
? 我們可以借助于一個緩存,當我們操作數據庫主庫的時候,我們同時往緩存中放入一個 “數據庫名稱:表名稱:主鍵” 組合的key,然后過期時間設置為主從同步的時延,當我們發起讀請求的時候,會先去判斷這個key是否存在,如果存在會強制要求讀主庫,如果這個key不存在,則去讀取從庫
二、數據庫主主之間數據不一致問題解決方案
問題產生:
? 主庫與主庫之間數據不一致問題,一般出現在兩個主庫都提供寫服務的時候,當兩個主庫都對外提供寫服務的時候,同時兩個主庫之間是需要進行數據同步的,那么可能會產生相同主鍵的數據被覆蓋掉的問題
解決方案:
? 1.只有一個主庫對外提供寫服務,另外一個主庫作為一個影子主庫,當主庫宕機之后,立刻將流量切換到這個影子主庫中
? 2.如果使用數據表的主鍵遞增,那么兩個主庫中的表的起始ID不同,步長相等,這樣可以防止同步的時候,相同主鍵的數據被覆蓋掉
? 3.在業務層使用分布式ID發號器生成全局唯一的ID進行插入
三、緩存數據庫數據不一致解決方案
問題產生:
? 當我們使用了緩存的時候,有一個無法避免的問題就是,先操作數據庫還是先操作緩存,大部分業務都是需要先操作數據庫的,如果更新數據庫的數據成功,但是緩存操作還沒有完成,此時讀取操作從緩存中讀取到的就是臟數據。
解決方案:
? 常見的緩存和數據庫數據的更新有兩大類分別是:
? 1.寫時緩存
? 寫時緩存就是 先更新數據庫,然后再更新緩存 ,這種方案有個問題,那就是 容易出現讀到臟數據的問題 ,比如一個線程更新完數據庫后還沒有更新完緩存,此時有另一個線程來讀取緩存,那么就會讀取到之前的老數據。
? 但是寫時緩存的這個問題也不是沒有解決辦法,那就是 通過加鎖,讓更新數據庫和更新緩存同時只能有一個線程來操作 ,但是這個解決方案的顯著問題就是系統性能會變得很差。但是并不是說這種方案沒有好處,它的好處就是 數據的實時性強 。線程讀到的一定是最新的數據。對于對數據一致性有很強要求的場景比如 ‘金融系統’,這種方案是可以考慮的。
? 但是這種方案還有一個缺點就是: 如果對緩存的更新失敗,需要寫操作才能重新操作緩存 ,但是對于大部分業務來說,都是讀多寫少。這個原因其實也是寫時緩存方案使用少的 主要原因 。
? 2.讀時緩存
? 讀時緩存就是 先更新數據庫,然后將緩存刪除,等下次讀取操作到來時,去更新最新的緩存數據 。
? 注意:對于 單機的數據庫 來說是可以的,但是如果是對于 主從架構 的數據庫來說, 可能不太適用 ,因為會帶來更多的讀取臟數據問題。
? 對于數據庫主從架構的系統來說,讀時緩存有兩個常用的方案:
? 1.延遲雙刪方案
? 更新數據庫的時候,刪除緩存 ,同時可以引入消息中間件mq來 發送一個延遲消息 , 延遲一個時間之后再去刪除一次緩存 。這種方案是為了 保證最終一致性 ,對于強一致性的實現支持不太好。
? 2.訂閱binlog刪除緩存方案
? 更新數據庫的時候,等到slave數據庫接收到master的binlog之后再去刪除緩存 。這種方案也是為了 保證最終一致性 ,對于強一致性的實現支持不太好。
四、Redis Sentinel模式下的主從數據不一致問題解決方案
問題產生:
? 當我們使用Redis的Sentinel模式進行部署的時候,會遇到我們往主節點中寫入數據,但是數據還沒有同步到從節點中,此時又有讀請求到來,讀請求分配到了從節點上,就無法讀取到最新的數據。
解決方案:
? 1.對于數據一致性要求非常強的業務場景,比如‘金融行業’我們可以在業務層使用Lettuce、Jedis Cluster客戶端來將讀請求強制指定到讀取主節點中的數據
? 2.使用 min-slaves-to-write 和 min-slaves-max-lag 配置主節點寫入條件,當主節點和指定數量的從節點完成同步之后才給主節點返回寫入成功,這個方案會損失一定的寫入可用性
e** 和 min-slaves-max-lag 配置主節點寫入條件,當主節點和指定數量的從節點完成同步之后才給主節點返回寫入成功,這個方案會損失一定的寫入可用性
后續如果我遇到其他數據不一致的情況,會持續進行更新