首頁 > 軟體

淺談MySQL資料同步到 Redis 快取的幾種方法

2023-03-17 06:06:19

1 Mysql查完資料,再同步寫入到Redis中

缺點1:會對介面造成延遲,因為同步寫入redis本身就有延遲,並且還要做重試,如果redis寫入失敗,還需要重試,那就更費時間了。

缺點2:不解耦,如果redis崩了,那直接卡執行緒了

缺點3:如果人為該資料庫,那就沒法同步了, 除非再人為刪除對應的Redis,但刪除Redis這個過程也有個時間差

2 Mysql查完資料,通過傳送MQ,在消費者執行緒去同步Redis

缺點1:多了層MQ,也就是會有很大的概率導致同步延遲問題.

缺點2:要對MQ的可用性做預防

缺點3:如果人為該資料庫,那就沒法同步了

優點1:可以大幅減少介面的延遲返回的問題

優點2:MQ本身有重試機制,無需人工去寫重試程式碼

優點3:解耦,把查詢Mysql和同步Redis完全分離,互不干擾

3 訂閱Mysql的Binlog檔案(可藉助Canal來進行)

CanalServer會偽裝成MysqlServer從庫,去訂閱MysqlServer主庫的Binlog檔案

Canal啟動的時候會設定對應的訊息MQ(RabbitMQ, RocketMQ, Kafka), 監聽到Binlog檔案有變化是,會把變化的sql語句轉換成json格式,並作為訊息內容傳送到MQ中

專案中只要監聽對應MQ,就能拿到Binlog改動的內容,Json資料中有明確的操作型別(CURD), 以及對應的資料。把對應資料同步到redis即可

缺點1:canal訂閱Binlog的整個操作過程是單執行緒的,所以面臨超高並行的情況下,效能可能不太出色。當然可以部署多個Canal 與 多個消費者,但是要注意訊息重複消費問題,做好冪等性校驗

優點1:即使人為改資料庫,也會監聽到,並且也會同步

優點2:非同步同步,不會對介面返回有格外延遲

4 延遲雙刪

在執行修改sql之前,先將redis的資料刪除

執行更新sql

延遲一段時間

再次刪除redis的資料

// 延遲雙刪虛擬碼
deleteRedisCache(key);   // 刪除redis快取
updateMysqlSql(obj);        // 更新mysql
Thread.sleep(100);           // 延遲一段時間
deleteRedisCache(key);   // 再次刪除該key的快取

缺點:這個延遲時間不好把控,到底延遲多久,這個很難去評估

擴充套件: 如果不使用延遲雙刪,僅僅是delete快取,然後改mysql資料。只有這兩步會出現什麼問題呢?

5. 單個請求,單執行緒沒問題,高並行多執行緒下會出問題

6. 如果Thread1執行緒要更新資料,此時Thread1執行緒把redis清理了

7. 此時Thread2執行緒來了,但Thread1還沒有更新mysql完畢

8. Thread2查詢redis肯定是null,此時Thread2就要查mysql了,然後再把查到的資料寫到快取

9. 由於Thread1還沒來得及修改mysql資料,所以此時Thread2查出來的資料是【舊資料】,Thread2把舊資料又寫入Redis 了

10. 此時Thread3執行緒來了,查詢Redis發現有資料,則直接拿快取資料了,此時【Thread3查出來的是舊資料】,直接帶著舊資料返回了,這就是問題所在

11. 而延遲雙刪的第二次刪除作用就是防止Thread2把舊資料又寫入了,有了延遲雙刪,Thread3查詢Redis的時候還是null,就會從mysql 去拿最新資料了

12. 所以正常的這個延遲時間,應該是Thread2查快取到拿mysql資料,到再儲存到redis這整個時間,作為Thread1的延遲時間,但是這個Thread2這個過程的時間會受到很多因素影響,因此很難斷定究竟會是多久

5 延遲雙寫

// 延遲雙寫虛擬碼
updateMysqlSql(obj);        // 更新mysql
addRedis(key);   // 再次刪除該key的快取

上述程式碼缺陷;

  • 高並行下,兩條執行緒同時執行上面程式碼,並對mysql 修改,且修改內容不通,可能會導致Redis與Mysql資料不一致
  • T1執行緒執行完updateMysqlSql,釋放了行鎖,此時T2執行緒再執行updateMysqlSql 與 addRedis, 最後T1執行addRedis,這種情況會導致資料庫改成了T2執行緒的資料,但Redis卻是T1執行緒的資料

優化

// 完美延遲雙寫虛擬碼
開啟事務
updateMysqlSql(obj);        // 更新mysql
addRedis(key);   // 再次刪除該key的快取
提交事務

上述程式碼改正:

把兩句程式碼放到一個事務裡面,只有T1執行完Mysql 與 Redis的時候,T2才能開始執行,就可以保證資料一致性。推薦使用分散式鎖

雙寫缺點:Mysql 與 Redis是單執行緒的。效能方面不行,因此不推薦使用

6 總結

推薦使用Canal的方式,進行非同步同步。其次是MQ方式

到此這篇關於淺談MySQL資料同步到 Redis 快取的幾種方法的文章就介紹到這了,更多相關MySQL資料同步到Redis快取內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com