1. 程式人生 > >資料庫與快取怎樣做同步最好

資料庫與快取怎樣做同步最好

前言:

           在讀取與寫入快取方面大家都是這麼做的:判斷是否有快取資料,無資料的話從資料庫載入,若查出資料不為null,則寫入快取,再把資料返回呼叫方。

            但是這裡有一個問題需要分析,快取與資料庫的同步,在更新完資料庫後,是更新快取還是刪除快取,還是先刪快取,再更新資料庫。從理論上來說,設定過期時間是最終保持一致的解決方案。但是這不是最好的辦法,在快取有效期內或者高併發情況下,會很可能出現讀取到的資料與快取不一致的情況。

三種策略:

           1.先更新資料庫,再更新快取

           2.先刪除快取,再更新資料庫

           3.先更新資料庫,再刪除快取

           不會出現先更新快取再更新資料庫,如果更新資料庫失敗了,那就完了

1.先更新資料庫,再更新快取

        這套方案不太好

         a.執行緒安全形度

                 (1) 執行緒A更新了資料庫

                 (2) 執行緒B更新了資料庫

                 (3) 執行緒B更新了快取

                 (4) 執行緒A更新了快取

            這樣快取中就出現了錯誤的資料庫

           b.業務場景

                 如果資料庫寫的場景比較多,讀的場景比較少,就會出現資料庫頻繁更新,快取頻繁更新可能快取根本就沒有讀,這樣浪費效能

                   如果寫入資料庫的值,並不是直接寫入快取的,而是要經過一系列複雜的計算再寫入快取,那麼每次寫入資料庫後,再次計算寫入快取,也是浪費效能的。刪除快取顯得更為合適。

 2.先刪快取,再更新資料庫

            高併發操作下,依舊會出現問題

            (1) A執行緒進行寫操作,先刪除快取

            (2) B執行緒發現沒有快取,去資料庫讀取舊值

            (3) B執行緒將舊值寫入快取

            (4) A執行緒更新資料庫

            這樣,資料庫中的資料,又是髒資料了,還有在資料庫主從分離情況下,中從沒來的及同步,結果把未同步的資料寫入到了快取。這怎麼解決

          採用延時雙刪策略

             redis.delKey(key);

             db.update(Data);

             new Thread(()->{Thread.sleep(1000);redis.delKey(key);}).start();

          在不影響程式響應的情況下,開一個執行緒去刪除快取,    至於是多少時間後刪除,可以自己評估,不一定是1s。

          但是這種情況下,如果第二次刪除快取失敗了怎麼辦?

3.先更新資料庫,再刪快取

      這樣也有問題

            (1) 快取剛好失效

            (2) A查資料庫得到一箇舊值

            (3) B將新值寫入資料庫

            (4) B刪除快取

             (5) A將舊值寫入快取

           因為資料庫的讀比寫快,所以這種概率比較低正常順序應該是1 2 5 3 4,但是也是有可能發生的,也可能是查詢出來值後,經過一系列計算,又寫入快取的。解決辦法還是延時快取雙刪,但是和2一樣,刪除失敗了怎麼辦?

解決方案1

         

               1.更新資料庫

               2.刪除快取失敗

               3.將要刪除的key傳送到訊息佇列

               4.消費訊息刪除key,重試直到成功

解決方案2

           

(1)更新資料庫資料
(2)資料庫會將操作資訊寫入binlog日誌當中
(3)訂閱程式提取出所需要的資料以及key
(4)另起一段非業務程式碼,獲得該資訊
(5)嘗試刪除快取操作,發現刪除失敗
(6)將這些資訊傳送至訊息佇列
(7)重新從訊息佇列中獲得該資料,重試操作。

備註說明:上述的訂閱binlog程式在mysql中有現成的中介軟體叫canal,可以完成訂閱binlog日誌的功能。至於oracle中,博主目前不知道有沒有現成中介軟體可以使用。另外,重試機制,博主是採用的是訊息佇列的方式。如果對一致性要求不是很高,直接在程式中另起一個執行緒,每隔一段時間去重試即可,這些大家可以靈活自由發揮,只是提供一個思路。

參考文獻: