Redis和MySQL如何保持資料一致性?
在高併發的場景下,大量的請求直接訪問Mysql很容易造成效能問題。所以,我們都會用Redis來做資料的快取,削減對資料庫的請求。但是,Mysql和Redis是兩種不同的資料庫,如何保證不同資料庫之間資料的一致性就非常關鍵了。
1.導致資料不一致的原因
在高併發的業務場景下,資料庫大多數情況都是使用者併發訪問最薄弱的環節。
所以,就需要使用redis做一個緩衝操作,讓請求先訪問到redis,而不是直接訪問MySQL等資料庫。
讀取快取步驟一般沒有什麼問題,但是一旦涉及到資料更新:資料庫和快取更新,就容易出現快取(Redis)和資料庫(MySQL)間的資料一致性問題。
這個業務場景,主要是解決讀資料從Redis快取,一般都是按照下圖的流程來進行業務操作。
2.快取先後刪除問題
不管是先寫MySQL資料庫,再刪除Redis快取;還是先刪除快取,再寫庫,都有可能出現資料不一致的情況。
2.1 先刪除快取
如果先刪除Redis快取資料,然而還沒有來得及寫入MySQL,另一個執行緒就來讀取
這個時候發現快取為空,則去Mysql資料庫中讀取舊資料寫入快取,此時快取中為髒資料。
然後資料庫更新後發現Redis和Mysql出現了資料不一致的問題
2.2 後刪除快取
如果先寫了庫,然後再刪除快取,不幸的寫庫的執行緒掛了,導致了快取沒有刪除
這個時候就會直接讀取舊快取,最終也導致了資料不一致情況
因為寫和讀是併發的,沒法保證順序,就會出現快取和資料庫的資料不一致的問題
3 解決方案
3.1 延時雙刪策略
3.1.1 基本思路
在寫庫前後都進行redis.del(key)操作,並且設定合理的超時時間。
虛擬碼如下:
public void write( String key, Object data ){ redis.delKey( key ); db.updateData( data ); Thread.sleep( 500 ); redis.delKey( key );}br
3.1.2 具體步驟
1.先刪除快取
2.再寫資料庫
3.休眠500毫秒
4.再次刪除快取
問題:這個500毫秒怎麼確定的,具體該休眠多久時間呢?
需要評估自己的專案的讀資料業務邏輯的耗時。
這麼做的目的,就是確保讀請求結束,寫請求可以刪除讀請求造成的快取髒資料。
當然這種策略還要考慮redis和資料庫主從同步的耗時。
最後的的寫資料的休眠時間:則在讀資料業務邏輯的耗時基礎上,加幾百ms即可。比如:休眠1秒。
3.1.3 設定快取過期時間是關鍵點
從理論上來說,給快取設定過期時間,是保證最終一致性的解決方案
所有的寫操作以資料庫為準,只要到達快取過期時間,快取刪除
如果後面還有讀請求的話,就會從資料庫中讀取新值然後回填快取
3.1.4 方案缺點
結合雙刪策略+快取超時設定,這樣最差的情況就是:
在快取過期時間內發生資料存在不一致
同時又增加了寫請求的耗時。
3.2 非同步更新快取(基於Mysql binlog的同步機制)
3.2.1 整體思路
1.涉及到更新的資料操作,利用Mysql binlog 進行增量訂閱消費
2.將訊息傳送到訊息佇列
3.透過訊息佇列消費將增量資料更新到Redis上
4.操作情況
讀取Redis快取:熱資料都在Redis上
寫Mysql:增刪改都是在Mysql進行操作
更新Redis資料:Mysql的資料操作都記錄到binlog,透過訊息佇列及時更新到Redis上
3.2.2 Redis更新過程
(1) 資料操作主要分為兩種:
一種是全量(將所有資料一次性寫入Redis)
一種是增量(實時更新)
這裡說的是增量,指的是mysql的update、insert、delate變更資料。
(2)讀取binlog後分析 ,利用訊息佇列,推送更新各臺的redis快取資料。
這樣一旦MySQL中產生了新的寫入、更新、刪除等操作,就可以把binlog相關的訊息推送至Redis
Redis再根據binlog中的記錄,對Redis進行更新
其實這種機制,很類似MySQL的主從備份機制,因為MySQL的主備也是透過binlog來實現的資料一致性
這裡的訊息推送工具你也可以採用別的第三方:kafka、rabbitMQ等來實現推送更新Redis!
總結
在高併發應用場景下,如果是對資料一致性要求高的情況下,要定位好導致資料和快取不一致的原因。
解決高併發場景下資料一致性的方案有兩種,分別是延時雙刪策略和非同步更新快取兩種方案。
另外,設定快取的過期時間是保證資料保持一致性的關鍵操作,需要結合業務進行合理的設定。
來自 “ 架構之美 ”, 原文作者:架構之美;原文連結:https://mp.weixin.qq.com/s/bscB11IfOGuS0DARB8ldBQ,如有侵權,請聯絡管理員刪除。
相關文章
- Mysql和Redis資料如何保持一致MySqlRedis
- Redis 如何保持和MySQL資料一致【一】RedisMySql
- Redis 如何保持和MySQL資料一致【二】RedisMySql
- 如何保證MySQL和Redis資料一致性?MySqlRedis
- 保持MySQL和Redis中的資料一致MySqlRedis
- 讓Redis資料集保持一致性Redis
- 美團四面:如何保障 MySQL 和 Redis 的資料一致性?MySqlRedis
- 8張圖搞懂Redis和MySQL資料一致性問題RedisMySql
- mysqldump備份時如何保持資料的一致性MySql
- 【面試普通人VS高手系列】Redis和Mysql如何保證資料一致性面試RedisMySql
- Redis和資料庫的資料一致性問題Redis資料庫
- 面試官:談談Redis快取和MySQL資料一致性問題面試Redis快取MySql
- Mysql和Redis資料同步策略MySqlRedis
- mysql 資料假刪 保持資料唯一MySql
- 面試常問:如何保證Redis快取和資料庫的資料一致性NRXW面試Redis快取資料庫
- MYSQL 同步到ES 如何設計架構保持一致性MySql架構
- Redis與資料庫資料一致性Redis資料庫
- [Redis] 02-快取和資料庫資料一致性問題Redis快取資料庫
- 高併發架構系列:Redis快取和MySQL資料一致性方案詳解架構Redis快取MySql
- MySQL資料一致性MySql
- 掘地三尺搞定 Redis 與 MySQL 資料一致性問題RedisMySql
- mysql資料一致性解析MySql
- Redis的主從資料一致性Redis
- redis基礎篇——資料一致性Redis
- 談談Redis快取中MySQL的資料如何與Redis同步Redis快取MySql
- 如何保證mongodb和資料庫雙寫資料一致性?MongoDB資料庫
- mysql資料同步至redisMySqlRedis
- 如何保證快取(redis)與資料庫的雙寫一致性快取Redis資料庫
- 美團二面:Redis與MySQL雙寫一致性如何保證?RedisMySql
- 分散式服務資料一致性-redis篇分散式Redis
- mysql和redis實時同步資料怎麼實現MySqlRedis
- 探究CRM系統如何保持資料整潔?
- 如何保持Oracle資料庫的優良效能Oracle資料庫
- 如何使資料庫中取出的資料保持原有格式(轉)資料庫
- 資料庫和快取的一致性如何保證資料庫快取
- 如何保證快取和資料庫的一致性?快取資料庫
- 如何保持Oracle資料庫SQL效能的穩定性Oracle資料庫SQL
- 趣說 | 資料庫和快取如何保證一致性?資料庫快取