如何保持MySQL和Redis的一致性?
如題,現在很多架構都採用了Redis+MySQL來進行儲存,但是由於多方面的原因,總會導致Redis和MySQL之間出現資料的不一致性。
例如如果一個事務執行失敗回滾了,但是如果採取了先寫Redis的方式,就會造成Redis和MySQL資料庫的不一致,再比如說,一個事務寫入了MySQL,但是此時還未寫入Redis,如果這時候有使用者訪問Redis,則此時就會出現資料不一致。
為了解決這些問題,本文將著重討論,如何保證MySQL和Redis之間存在一個合理的資料一致性方案。
1、分別處理
針對某些對資料一致性要求不是特別高的情況下,可以將這些資料放入Redis,請求來了直接查詢Redis,例如近期回覆、歷史排名這種實時性不強的業務。而針對那些強實時性的業務,例如虛擬貨幣、物品購買件數等等,則直接穿透Redis至MySQL上,等到MySQL上寫入成功,再同步更新到Redis上去。這樣既可以起到Redis的分流大量查詢請求的作用,又保證了關鍵資料的一致性。
2、高併發情況下
此時如果寫入請求較多,則直接寫入Redis中去,然後間隔一段時間,批量將所有的寫入請求,重新整理到MySQL中去;如果此時寫入請求不多,則可以在每次寫入Redis,都立刻將該命令同步至MySQL中去。這兩種方法有利有弊,需要根據不同的場景來權衡。
3、基於訂閱binlog的同步機制
阿里巴巴的一款開源框架canal,提供了一種釋出/ 訂閱模式的同步機制,通過該框架我們可以對MySQL的binlog進行訂閱,這樣一旦MySQL中產生了新的寫入、更新、刪除等操作,就可以把binlog相關的訊息推送至Redis,Redis再根據binlog中的記錄,對Redis進行更新。值得注意的是,binlog需要手動開啟,並且不會記錄關於MySQL查詢的命令和操作。
其實這種機制,很類似MySQL的主從備份機制,因為MySQL的主備也是通過binlog來實現的資料一致性。而canal正是模仿了slave資料庫的備份請求,使得Redis的資料更新達到了相同的效果。如下圖就可以看到Slave資料庫中啟動了2個執行緒,一個是MySQL SQL執行緒,這個執行緒跟Matser資料庫中起的執行緒是一樣的,負責MySQL的業務率執行,而另外一個執行緒就是MySQL的I/O執行緒,這個執行緒的主要作用就是同步Master 資料庫中的binlog,達到資料備份的效果。而binlog就可以理解為一堆SQL語言組成的日誌。