天天看點

如何保證 Redis 緩存與資料庫雙寫一緻性?

在做系統優化時,想到了将資料進行分級存儲的思路。因為在系統中會存在一些資料,有些資料的實時性要求不高,比如一些配置資訊。

基本上配置了很久才會變一次。而有一些資料實時性要求非常高,比如訂單和流水的資料。是以這裡根據資料要求實時性不同将資料分為三級。

第1級:訂單資料和支付流水資料;這兩塊資料對實時性和精确性要求很高,是以不添加任何緩存,讀寫操作将直接操作資料庫。

第2級:使用者相關資料;這些資料和使用者相關,具有讀多寫少的特征,是以我們使用redis進行緩存。

第3級:支付配置資訊;這些資料和使用者無關,具有資料量小,頻繁讀,幾乎不修改的特征,是以我們使用本地記憶體進行緩存。

但是隻要使用到緩存,無論是本地記憶體做緩存還是使用 redis 做緩存,那麼就會存在資料同步的問題,因為配置資訊緩存在記憶體中,而記憶體時無法感覺到資料在資料庫的修改。這樣就會造成資料庫中的資料與緩存中資料不一緻的問題。

接下來就讨論一下關于保證緩存和資料庫雙寫時的資料一緻性。

解決方案

那麼我們這裡列出來所有政策,并且讨論他們優劣性。

先更新資料庫,後更新緩存

先更新資料庫,後删除緩存

先更新緩存,後更新資料庫

先删除緩存,後更新資料庫

這種場景一般是沒有人使用的,主要原因是在更新緩存那一步,為什麼呢?因為有的業務需求緩存中存在的值并不是直接從資料庫中查出來的,有的是需要經過一系列計算來的緩存值,那麼這時候後你要更新緩存的話其實代價是很高的。如果此時有大量的對資料庫進行寫資料的請求,但是讀請求并不多,那麼此時如果每次寫請求都更新一下緩存,那麼性能損耗是非常大的。

舉個例子比如在資料庫中有一個值為 1 的值,此時我們有 10 個請求對其每次加一的操作,但是這期間并沒有讀操作進來,如果用了先更新資料庫的辦法,那麼此時就會有十個請求對緩存進行更新,會有大量的冷資料産生,如果我們不更新緩存而是删除緩存,那麼在有讀請求來的時候那麼就會隻更新緩存一次。

這一種情況應該不需要我們考慮了吧,和第一種情況是一樣的。

該方案也會出問題,具體出現的原因如下。

如何保證 Redis 緩存與資料庫雙寫一緻性?

此時來了兩個請求,請求 A(更新操作) 和請求 B(查詢操作)

請求 A 會先删除 Redis 中的資料,然後去資料庫進行更新操作

此時請求 B 看到 Redis 中的資料時空的,會去資料庫中查詢該值,補錄到 Redis 中

但是此時請求 A 并沒有更新成功,或者事務還未送出

那麼這時候就會産生資料庫和 Redis 資料不一緻的問題。如何解決呢?其實最簡單的解決辦法就是延時雙删的政策。

如何保證 Redis 緩存與資料庫雙寫一緻性?
如何保證 Redis 緩存與資料庫雙寫一緻性?

請求 A 更新操作,删除了 Redis

請求主庫進行更新操作,主庫與從庫進行同步資料的操作

請 B 查詢操作,發現 Redis 中沒有資料

去從庫中拿去資料

此時同步資料還未完成,拿到的資料是舊資料

此時的解決辦法就是如果是對 Redis 進行填充資料的查詢資料庫操作,那麼就強制将其指向主庫進行查詢。

如何保證 Redis 緩存與資料庫雙寫一緻性?

問題:這一種情況也會出現問題,比如更新資料庫成功了,但是在删除緩存的階段出錯了沒有删除成功,那麼此時再讀取緩存的時候每次都是錯誤的資料了。

如何保證 Redis 緩存與資料庫雙寫一緻性?

此時解決方案就是利用消息隊列進行删除的補償。具體的業務邏輯用語言描述如下:

請求 A 先對資料庫進行更新操作

在對 Redis 進行删除操作的時候發現報錯,删除失敗

此時将Redis 的 key 作為消息體發送到消息隊列中

系統接收到消息隊列發送的消息後再次對 Redis 進行删除操作

但是這個方案會有一個缺點就是會對業務代碼造成大量的侵入,深深的耦合在一起,是以這時會有一個優化的方案,我們知道對 Mysql 資料庫更新操作後再 binlog 日志中我們都能夠找到相應的操作,那麼我們可以訂閱 Mysql 資料庫的 binlog 日志對緩存進行操作。

如何保證 Redis 緩存與資料庫雙寫一緻性?

總結

每種方案各有利弊,比如在第二種先删除緩存,後更新資料庫這個方案我們最後讨論了要更新 Redis 的時候強制走主庫查詢就能解決問題,那麼這樣的操作會對業務代碼進行大量的侵入,但是不需要增加的系統,不需要增加整體的服務的複雜度。

最後一種方案我們最後讨論了利用訂閱 binlog 日志進行搭建獨立系統操作 Redis,這樣的缺點其實就是增加了系統複雜度。其實每一次的選擇都需要我們對于我們的業務進行評估來選擇,沒有一種技術是對于所有業務都通用的。沒有最好的,隻有最适合我們的。

近期熱文推薦:

1.Java 15 正式釋出, 14 個新特性,重新整理你的認知!!

2.終于靠開源項目弄到 IntelliJ IDEA 激活碼了,真香!

3.我用 Java 8 寫了一段邏輯,同僚直呼看不懂,你試試看。。

4.吊打 Tomcat ,Undertow 性能很炸!!

5.《Java開發手冊(嵩山版)》最新釋出,速速下載下傳!

覺得不錯,别忘了随手點贊+轉發哦!