作者:不學無數的程序員
鏈接:https://www.jianshu.com/p/a8eb1412471f
在做系統優化時,想到了將數據進行分級存儲的思路。因為在系統中會存在一些數據,有些數據的實時性要求不高,比如一些配置信息。
基本上配置了很久才會變一次。而有一些數據實時性要求非常高,比如訂單和流水的數據。所以這里根據數據要求實時性不同將數據分為三級。
- 第1級:訂單數據和支付流水數據;這兩塊數據對實時性和精確性要求很高,所以不添加任何緩存,讀寫操作將直接操作數據庫。
- 第2級:用戶相關數據;這些數據和用戶相關,具有讀多寫少的特征,所以我們使用redis進行緩存。
- 第3級:支付配置信息;這些數據和用戶無關,具有數據量小,頻繁讀,幾乎不修改的特征,所以我們使用本地內存進行緩存。
但是只要使用到緩存,無論是本地內存做緩存還是使用 redis 做緩存,那么就會存在數據同步的問題,因為配置信息緩存在內存中,而內存時無法感知到數據在數據庫的修改。這樣就會造成數據庫中的數據與緩存中數據不一致的問題。
接下來就討論一下關於保證緩存和數據庫雙寫時的數據一致性。
解決方案
那么我們這里列出來所有策略,並且討論他們優劣性。
- 先更新數據庫,后更新緩存
- 先更新數據庫,后刪除緩存
- 先更新緩存,后更新數據庫
- 先刪除緩存,后更新數據庫
先更新數據庫,后更新緩存
這種場景一般是沒有人使用的,主要原因是在更新緩存那一步,為什么呢?因為有的業務需求緩存中存在的值並不是直接從數據庫中查出來的,有的是需要經過一系列計算來的緩存值,那么這時候后你要更新緩存的話其實代價是很高的。如果此時有大量的對數據庫進行寫數據的請求,但是讀請求並不多,那么此時如果每次寫請求都更新一下緩存,那么性能損耗是非常大的。
舉個例子比如在數據庫中有一個值為 1 的值,此時我們有 10 個請求對其每次加一的操作,但是這期間並沒有讀操作進來,如果用了先更新數據庫的辦法,那么此時就會有十個請求對緩存進行更新,會有大量的冷數據產生,如果我們不更新緩存而是刪除緩存,那么在有讀請求來的時候那么就會只更新緩存一次。
先更新緩存,后更新數據庫
這一種情況應該不需要我們考慮了吧,和第一種情況是一樣的。
先刪除緩存,后更新數據庫
該方案也會出問題,具體出現的原因如下。
此時來了兩個請求,請求 A(更新操作) 和請求 B(查詢操作)
- 請求 A 會先刪除 Redis 中的數據,然后去數據庫進行更新操作
- 此時請求 B 看到 Redis 中的數據時空的,會去數據庫中查詢該值,補錄到 Redis 中
- 但是此時請求 A 並沒有更新成功,或者事務還未提交
那么這時候就會產生數據庫和 Redis 數據不一致的問題。如何解決呢?其實最簡單的解決辦法就是延時雙刪的策略。
但是上述的保證事務提交完以后再進行刪除緩存還有一個問題,就是如果你使用的是 Mysql 的讀寫分離的架構的話,那么其實主從同步之間也會有時間差。
此時來了兩個請求,請求 A(更新操作) 和請求 B(查詢操作)
- 請求 A 更新操作,刪除了 Redis
- 請求主庫進行更新操作,主庫與從庫進行同步數據的操作
- 請 B 查詢操作,發現 Redis 中沒有數據
- 去從庫中拿去數據
- 此時同步數據還未完成,拿到的數據是舊數據
此時的解決辦法就是如果是對 Redis 進行填充數據的查詢數據庫操作,那么就強制將其指向主庫進行查詢。
先更新數據庫,后刪除緩存
問題:這一種情況也會出現問題,比如更新數據庫成功了,但是在刪除緩存的階段出錯了沒有刪除成功,那么此時再讀取緩存的時候每次都是錯誤的數據了。
此時解決方案就是利用消息隊列進行刪除的補償。具體的業務邏輯用語言描述如下:
- 請求 A 先對數據庫進行更新操作
- 在對 Redis 進行刪除操作的時候發現報錯,刪除失敗
- 此時將Redis 的 key 作為消息體發送到消息隊列中
- 系統接收到消息隊列發送的消息后再次對 Redis 進行刪除操作
但是這個方案會有一個缺點就是會對業務代碼造成大量的侵入,深深的耦合在一起,所以這時會有一個優化的方案,我們知道對 Mysql 數據庫更新操作后再 binlog 日志中我們都能夠找到相應的操作,那么我們可以訂閱 Mysql 數據庫的 binlog 日志對緩存進行操作。
總結
每種方案各有利弊,比如在第二種先刪除緩存,后更新數據庫這個方案我們最后討論了要更新 Redis 的時候強制走主庫查詢就能解決問題,那么這樣的操作會對業務代碼進行大量的侵入,但是不需要增加的系統,不需要增加整體的服務的復雜度。
最后一種方案我們最后討論了利用訂閱 binlog 日志進行搭建獨立系統操作 Redis,這樣的缺點其實就是增加了系統復雜度。其實每一次的選擇都需要我們對於我們的業務進行評估來選擇,沒有一種技術是對於所有業務都通用的。沒有最好的,只有最適合我們的。
近期熱文推薦:
1.Java 15 正式發布, 14 個新特性,刷新你的認知!!
2.終於靠開源項目弄到 IntelliJ IDEA 激活碼了,真香!
3.我用 Java 8 寫了一段邏輯,同事直呼看不懂,你試試看。。
覺得不錯,別忘了隨手點贊+轉發哦!