在高并發的業務場景下,數據庫的性能瓶頸往往都是用戶并發訪問過大。所以,一般都使用redis做一個緩沖操作,讓請求先訪問到redis,而不是直接去訪問MySQL等數據庫。從而減少網絡請求的延遲響應
數據為什么會不一致
這樣的問題主要是在并發讀寫訪問的時候,緩存和數據相互交叉執行。
一、單庫情況下
同一時刻發生了并發讀寫請求,
A請求發送一個寫操作到服務端,第一步會淘汰cache,然后因為各種原因卡主了,不在執行后面業務(例:大量的業務操作、調用其他服務處理消耗了1s)。
B請求發送一個讀操作,讀cache,因為cache淘汰,所以為空
B請求繼續讀DB,讀出一個臟數據,并寫入cache
A請求終于執行完全,在寫入數據到DB
總結:因最后才把寫操作數據入DB,并沒同步。cache里面一直保持臟數據
臟數據是指源系統中的數據不在給定的范圍內或對于實際業務毫無意義,或是數據格式非法,以及在源系統中存在不規范的編碼和含糊的業務邏輯。
A請求發送一個寫操作到服務端,第一步會淘汰cache
A請求寫主數據庫,寫了最新的數據。
B請求發送一個讀操作,讀cache,因為cache淘汰,所以為空
B請求繼續讀DB,讀的是從庫,此時主從同步還沒同步成功。讀出臟數據,然后臟數據入cache
最后數據庫主從同步完成
總結:這種情況下請求A和請求B操作時序沒問題,是主從同步的時延問題(假設1s),導致讀請求讀取從庫讀到臟數據導致的不一致
單庫下,邏輯處理中消耗1s。可能讀到舊數據入緩存
主從+讀寫分離,在1s的主從同步時延中。讀到從庫的舊數據入緩存
數據優化方案
先淘汰緩存
再寫數據庫
往消息總線esb發送一個淘汰消息,發送立即返回。寫請求的處理時間幾乎沒有增加,這個方法淘汰了緩存兩次。因此被稱為“緩存雙淘汰法“,而在消息總線下游,有一個異步淘汰緩存的消費者,在拿到淘汰消息在1s后淘汰緩存,這樣,即使在一秒內有臟數據入緩存,也能夠被淘汰掉。
上述的步驟,都是在業務線里面執行,新增一個線下的讀取binlog異步淘汰緩存模塊,讀取binlog總的數據,然后進行異步淘汰。
1.思路:
MySQLbinlog增量發布訂閱消費+消息隊列+增量數據更新到redis
1)讀請求走Redis:熱數據基本都在Redis
2)寫請求走MySQL:增刪改都操作MySQL
3)更新Redis數據:MySQ的數據操作binlog,來更新到Redis
2.Redis更新
1)數據操作主要分為兩塊:
一個是全量(將全部數據一次寫入到redis)
一個是增量(實時更新)
這里說的是增量,指的是mysql的update、insert、delate變更數據。
這樣一旦MySQL中產生了新的寫入、更新、刪除等操作,就可以把binlog相關的消息推送至Redis,Redis再根據binlog中的記錄,對Redis進行更新。就無需在從業務線去操作緩存內容
如有感悟,和交流探討額