1. 程式人生 > >MySQL資料庫與Redis快取資料一致性問題

MySQL資料庫與Redis快取資料一致性問題

我們時常接受失望,這樣我們才能不斷重整旗鼓。——《島上書店》

1、引言

在最近專案開發中,採用mysql儲存持久化資料,redis快取熱門資料,遇到一個問題,對於一些強實時性業務,我們需要先將資料寫到mysql上,mysql寫入成功後,再去更新redis,從而確保redis解決讀的問題,同時保證了關鍵資料的一致性問題。

但是這裡出現了一個問題,如果mysql操作成功了,但是redis出現異常,操作失敗,如何實現回滾?

2、MySQL操作成功之後Redis操作失敗的回滾

針對Redis出現異常,操作失敗,對MySQL進行回滾操作:

傳統通過註解@Transactional只會回滾MySQL異常的情況,Redis本身也不具備回滾功能,Redis的事務也只能保證操作順序一致,並不能保證操作失敗進行資料回滾,在MySQL操作成功的情況下,@Transactional註解會認為方法並沒有異常,會繼續執行而不回滾,這樣就導致了MySQL和Redis不一致的情況。

為了避免這種情況,每次操作Redis之後,都會判斷Redis有沒有操作成功,操作失敗則進行手動回滾,加一行程式碼:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 配合@Transactional註解即可解決問題。

3、一致性問題解決

(1)針對業務進行處理

針對某些對資料一致性要求不是特別高的情況下,可以將這些資料放入Redis,首先查詢Redis,例如近期回覆、歷史排名這種實時性不強的業務。而針對那些強實時性的業務,例如物品購買件數等,則直接寫入MySQL上,等到MySQL上寫入成功,再同步更新到Redis上去。這樣既可以起到Redis的分流大量讀請求的作用,又保證了關鍵資料的一致性。

(2)高併發情況下定時處理

黨寫入請求較多時,如點贊等操作,則直接寫入Redis中去,然後一段時間週期,批量將所有的寫入請求從redis中重新整理到MySQL中去;如果此時寫入請求不多,則可以在每次寫入Redis,比如關注操作,都立刻將該命令同步至MySQL中去。這兩種方法有利有弊,需要根據實際的業務場景來權衡。