前言
使用redis作為快取,必然存在redis快取和DB資料一致性的問題:某一時刻,redis快取資料和DB資料不一致
一 快取更新策略
按照快取更新的方式大致分為: 記憶體淘汰、過期洗掉、主動更新
一) 記憶體淘汰
利用Redis的記憶體淘汰策略,當記憶體不足時自動進行淘汰部分資料,下次查詢時更新快取,一致性差,無維護成本
記憶體淘汰策略詳情請參考:redis記憶體淘汰策略和過期洗掉策略
二) 過期洗掉
快取添加過期時間,到期后根據過期洗掉策略自動進行洗掉快取,下次查詢時進行更新快取,一致性一般,維護成本低
過期洗掉策略詳情請參考:redis記憶體淘汰策略和過期洗掉策略
三) 主動更新
應用程式中修改DB,修改快取,一致性好,維護成本高
主動更新大致分為: Cache Aside Pattern、Read/Write Through Pattern、Write Behind Caching Pattern
1 Cache Aside Pattern
即旁路快取模式,旁路路由策略,最經典常用的快取策略
應用程式負責快取和DB的讀寫
讀寫操作步驟:
讀操作時,先讀快取,快取存在直接回傳;快取不存在則讀DB,然后把讀的DB資料存入快取,回傳
寫操作時,先更新DB,再洗掉快取
讀操作流程圖:

寫操作流程圖:

2 Read/Write Through Pattern
該模式下應用程式直接和快取管理組件互動,快取管理組件和DB互動,無需關心快取一致性問題
應用程式只與快取管理組件互動,負責快取的讀寫,快取管理組件負責DB的讀寫
1) Read Through
讀操作時,快取管理組件先讀快取,快取存在直接回傳;快取不存在則讀DB,然后把讀的DB資料存入快取,回傳
流程圖:

2) Write Through
寫操作時,快取管理組件同步更數DB和快取
流程圖:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-057lcnOf-1678262363678)(/Write Through流程圖.png)]

3 Write Behind Caching Pattern
和 Write Through相似,不同點在于Write Through更新DB和更新快取是同步的,而Write Behind Caching Pattern更新DB和更新快取是異步的
應用程式只與快取管理組件互動操作,負責快取的讀寫,通過定時或閾值的異步方式將資料同步到DB,保證最終一致
讀流程圖:

寫流程圖:

優點:
減少了更新DB的頻率,讀寫回應非常快,吞吐量也會有明顯的提升
缺點:
不能時時同步,資料同步DB程序服務不可用,導致資料丟失
4 三種主動更新策略的對比
| 策略 | 說明 | 優點 | 缺點 |
|---|---|---|---|
| Cache Aside Pattern | 應用程式負責快取和DB的讀寫 | 使用簡單,直接操作快取和DB | 需要撰寫對快取和DB讀寫的代碼 |
| Read/Write Through Pattern | 應用程式只與快取管理組件互動,負責快取的讀寫,快取管理組件負責DB的讀寫 | 只需負責快取的讀寫 | 復雜,需要提供對DB讀寫的handler |
| Write Behind Caching Pattern | 應用程式只與快取管理組件互動,負責快取的讀寫,快取管理組件負責DB的讀寫,性能最好,在高并發場景下可以降低資料庫的壓力 | 性能最好;只需負責快取的讀寫 | 不能時時同步,資料同步DB程序服務不可用,導致資料丟失 |
四) 三種快取更新策略的對比
| 策略 | 說明 | 一致性 | 維護成本 |
|---|---|---|---|
| 記憶體淘汰 | 使用Redis的記憶體淘汰策略,當記憶體不足時自動進行淘汰部分資料,下次查詢時更新快取 | 差 | 無 |
| 過期洗掉 | 快取添加過期時間,到期后根據過期洗掉策略自動進行洗掉快取,下次查詢時進行更新快取 | 低 | 低 |
| 主動更新 | 在修改資料庫的時也修改快取,使用硬編碼方式或者硬編碼+中間件方式在修改資料庫時同步或異步的修改快取 | 好 | 高 |
二 更新快取的兩種方式
1 洗掉快取
更新DB時洗掉快取,查詢時再從DB中讀取資料并更新到快取
2 更新快取
更新DB時更新快取,頻繁更新快取開銷大,且并發時可能導致請求讀取的快取資料是舊資料
三 快取更新策略的實作方式
一) 先更新快取,再更新DB
1 并發寫場景
所有執行緒都是先更新快取再更新DB,在某個寫執行緒更新快取和更新DB之間,其他寫執行緒也更新了快取和DB,導致快取和DB資料不一致
流程圖:

具體步驟:
1) 執行緒1更新快取
2) 執行緒2更新快取
3) 執行緒2更新DB
4) 執行緒1更新DB
快取和DB資料不一致的原因:
理論上先更新快取的執行緒也會先更新DB,但是并發場景下執行緒的執行順序無法保證:
a) 若更新DB的順序是: 執行緒1再執行緒2,則不會出現資料不一致問題
b) 若更新DB的順序是: 執行緒2再執行緒1,此時快取是執行緒2的資料,DB是執行緒1的資料,導致快取和DB資料不一致
先洗掉快取再更新DB----并發讀寫場景流程圖
2 并發讀寫場景
在寫執行緒更新快取和更新DB之間,讀執行緒也可以獲取到最新的快取,不會導致快取和DB資料不一致
流程圖:

具體步驟:
1) 執行緒1更新快取
2) 執行緒2查詢,命中快取回傳
3) 執行緒1更新DB
快取和DB資料不一致的原因:
可以保證快取和DB資料一致,雖然執行緒1更新DB的操作還沒有完成,但是更新快取的操作已經完成了,讀請求可以獲取到最新的快取
二) 先更新DB,再更新快取
1 并發寫場景
所有執行緒都是先更新DB再更新快取,在某個寫執行緒更新DB和更新快取之間,其他寫執行緒也更新了DB和快取,導致快取和DB資料不一致
流程圖:

具體步驟:
1) 執行緒1更新DB
2) 執行緒2更新DB
3) 執行緒2更新快取
4) 執行緒1更新快取
快取和DB資料不一致的原因:
理論上先更新DB的執行緒也會先更新快取,但是并發場景下執行緒的執行順序無法保證:
a) 若更新快取的順序是: 先執行緒1再執行緒2,則不會出現資料不一致問題
b) 若更新快取的順序是: 先執行緒2再執行緒1,此時快取是執行緒1的資料,DB是執行緒2的資料,導致快取和DB資料不一致
2 并發讀寫場景
在寫執行緒更新DB和更新快取之間,讀執行緒可以獲取到舊資料,但最侄訓一致
流程圖:

具體步驟:
1) 執行緒1更新DB
2) 執行緒2查詢,命中快取回傳
3) 執行緒1更新快取
快取和DB資料不一致的原因:
執行緒2獲取的快取是舊資料,但最終都會一致
三) 先洗掉快取,再更新DB
1 并發寫場景
所有執行緒都是先洗掉快取再更新DB,無論哪個執行緒先洗掉快取再更新DB,快取都會被洗掉,不會導致快取和DB資料不一致
流程圖:
具體步驟:
1) 執行緒1洗掉快取
2) 執行緒2洗掉快取
3) 執行緒2更新DB
4) 執行緒1更新DB
快取不一致原因:
無論哪個執行緒先洗掉快取再更新DB,快取都會被洗掉,不會導致快取和DB資料不一致
2 并發讀寫場景
在寫執行緒洗掉快取和更新DB之間,讀執行緒根據查詢的DB結果更新了快取,導致快取和DB資料不一致
流程圖:

具體步驟:
1) 執行緒1洗掉快取
2) 執行緒2查詢,未命中
3) 執行緒2查詢DB
4) 執行緒2根據查詢的DB結果更新快取
5) 執行緒1更新DB
快取和DB資料不一致的原因:
執行緒1洗掉快取和更新DB之間,執行緒2根據查詢的DB結果更新了快取,導致快取和DB資料不一致
四) 先更新DB,再洗掉快取
1 并發寫場景
所有執行緒都是先更新DB再洗掉快取,無論哪個執行緒先更新DB再洗掉快取,快取都會被洗掉,不會導致快取和DB資料不一致
流程圖:

具體步驟:
1) 執行緒1更新DB
2) 執行緒2更新DB
3) 執行緒2洗掉快取
4) 執行緒1洗掉快取
快取不一致原因:
無論哪個執行緒先更新DB再洗掉快取,快取都會被洗掉,不會導致快取和DB資料不一致
2 并發讀寫場景
在寫執行緒更新DB再洗掉快取之間,讀執行緒可以獲取到舊資料,但最侄訓一致
流程圖:
具體步驟:
1) 執行緒1更新DB
2) 執行緒2查詢命中快取回傳
3) 執行緒1洗掉快取
快取不一致原因:
執行緒2獲取的快取是舊資料,但最終都會一致
五) 延遲雙刪
先洗掉快取再更新DB在并發寫場景不會導致資料不一致,但是在并發讀寫場景會導致資料不一致
延遲雙刪是基于先洗掉快取再更新DB的基礎上的改進:在更新DB后延遲一定時間,再次洗掉快取
延時是為了保證第二次洗掉快取前能完成更新DB操作,延時時間根據系統的查詢性能而定
第二次洗掉快取是為了保證后續請求查詢DB(此時資料庫中的資料已是更新后的資料),重新寫入快取,保證資料一致性
1 并發寫場景
無論哪個執行緒都會洗掉快取,不會導致快取和DB資料不一致
流程圖:

具體步驟:
1) 執行緒1洗掉快取
2) 執行緒2洗掉快取
3) 執行緒2更新DB
4) 執行緒1更新DB
5) 執行緒1延時洗掉快取
6) 執行緒2延時洗掉快取
快取不一致原因:
無論哪個執行緒都會洗掉快取,不會導致快取和DB資料不一致
2 并發讀寫場景
流程圖:

具體步驟:
1) 執行緒1洗掉快取
2) 執行緒2查詢,未命中
3) 執行緒2查詢DB
4) 執行緒2根據查詢的DB結果更新快取
5) 執行緒1更新DB
6) 執行緒1延時洗掉快取
快取不一致原因:
執行緒1第一次洗掉快取之后,執行緒2根據查詢的DB結果更新快取,此時查詢得到的結果是舊資料,執行緒1延遲第二次洗掉快取之后,后續查詢DB(此時資料庫中的資料已是更新后的資料),重新寫入快取,不會導致快取和DB資料不一致
3 延時雙刪的缺點
1) 需要延時,低延時場景不合適,如秒殺等需要低延時,需要強一致,高頻繁修改資料場景
2) 不能保證強一致性,在更新DB之前,查詢執行緒查詢得到的結果是舊資料,可但可以減輕快取和DB資料不一致的問題
3) 延時的時間是一個不可評估的值,延時越久,能規避一致性的概率越大
六) 異步洗掉快取
先更新DB再洗掉快取在并發寫場景不會導致資料不一致,但是在并發讀寫場景會短暫的導致資料不一致,但是由于洗掉快取失敗不會重試,并發寫場景、并發讀寫場景都可能長時間導致資料不一致
異步更新快取是基于先更新DB再洗掉快取的基礎上的改進:更新DB之后,基于消費佇列異步洗掉快取
根據消費佇列不同大致分為:訊息佇列、binlog+訊息佇列
1 基于訊息佇列的異步洗掉快取
1) 并發寫場景
無論哪個執行緒先更新DB再洗掉快取,快取都會被洗掉,不會導致快取和DB資料不一致
流程圖:

具體步驟:
1) 執行緒1更新DB
2) 執行緒2更新DB
3) 執行緒2把洗掉快取放入訊息佇列
4) 執行緒1把洗掉快取放入訊息佇列
5) 異步:訊息佇列消費洗掉快取
快取不一致原因:
無論哪個執行緒先更新DB再洗掉快取,快取都會被洗掉,不會導致快取和DB資料不一致
2) 并發讀寫場景
異步洗掉快取期間,讀執行緒獲取的快取是舊資料,短暫出現資料不一致,異步洗掉快取后最侄訓一致
流程圖:

具體步驟:
1) 執行緒1更新DB
2) 執行緒2查詢快取,命中回傳
3) 執行緒1把洗掉快取放入訊息佇列
4) 異步:訊息佇列消費洗掉快取
快取不一致原因:
異步洗掉快取期間,讀執行緒獲取的快取是舊資料,短暫出現資料不一致,異步洗掉快取后最侄訓一致
2 基于binlog+訊息佇列洗掉快取
1) 并發寫場景
流程圖:

具體步驟:
1) 執行緒1更新DB
2) 執行緒2更新DB
3) 異步:binlog日志收集中間件定時收集DB的binglog日志
4) 異步:binlog日志收集中間件發送日志訊息到訊息佇列
5) 異步:訊息佇列消費洗掉快取
快取不一致原因:
無論哪個執行緒先更新DB再洗掉快取,快取都會被洗掉,不會導致快取和DB資料不一致
2) 并發讀寫場景
流程圖:
具體步驟:
1) 執行緒1更新DB
2) 執行緒2查詢快取,命中回傳
3) 異步:binlog日志收集中間件定時收集DB的binglog日志
4) 異步:binlog日志收集中間件發送日志訊息到訊息佇列
5) 異步:訊息佇列消費洗掉快取
快取不一致原因:
異步洗掉快取期間,讀執行緒獲取的快取是舊資料,短暫出現資料不一致,異步洗掉快取后最侄訓一致
3 異步洗掉快取的優缺點
優點
1) 洗掉快取的操作與主流程代碼解耦
2) 中間件自帶重試機制,增加了操作快取的成功率
缺點
引入中間件,提升了系統的復雜度,在高并發場景可能會產生性能問題
七) 幾種實作方式的對比
| 策略 | 并發場景 | 并發問題 | 資料不一致概率 | 說明 |
| 先更新快取,再更新DB | 并發寫 | 所有執行緒都是先更新快取再更新DB,在某個寫執行緒更新快取和更新DB之間,其他寫執行緒也更新了快取和DB,導致快取和DB資料不一致 | 高 | |
| 并發讀寫 | 在寫執行緒更新快取和更新DB之間,讀執行緒也可以獲取到最新的快取,不會導致快取和DB資料不一致 | 不會出現 | ||
| 先更新DB,再更新快取 | 并發寫 | 所有執行緒都是先更新DB再更新快取,在某個寫執行緒更新DB和更新快取之間 其他寫執行緒也更新了DB和快取,此時快取和DB資料不一致 | 高 | |
| 并發讀寫 | 在寫執行緒更新DB和更新快取之間,讀執行緒獲取的快取是舊資料,短暫出現資料不一致,但最侄訓一致 | 短暫不一致,最侄訓一致 | ||
| 先洗掉快取,再更新DB | 并發寫 | 無論哪個執行緒先洗掉快取再更新DB,快取都會被洗掉,不會導致快取和DB資料不一致 | 不會出現 | |
| 并發讀寫 | 在寫執行緒洗掉快取和更新DB之間,讀執行緒根據查詢的DB結果更新了快取,導致快取和DB資料不一致 | 高 | ||
| 先更新DB,再洗掉快取 | 并發寫 | 無論哪個執行緒先更新DB再洗掉快取,快取都會被洗掉,不會導致快取和DB資料不一致 | 不會出現 | |
| 并發讀寫 | 在寫執行緒更新DB和洗掉快取之間,讀執行緒獲取的快取是舊資料,短暫出現資料不一致,但最侄訓一致 | 短暫不一致,最侄訓一致 | ||
| 延遲雙刪 | 并發寫 | 無論哪個執行緒都會洗掉快取,不會導致快取和DB資料不一致 | 不會出現 | 延遲雙刪基于先洗掉快取再更新DB的基礎上的改進:在更新DB后延遲一定時間,再次洗掉快取 |
| 并發讀寫 | 在寫執行緒洗掉快取和更新DB之間,讀執行緒根據查詢的DB結果更新了快取,短暫出現資料不一致,但延時再次洗掉快取后資料會一致 | 短暫不一致,最侄訓一致 | ||
| 異步洗掉快取 | 并發寫 | 無論哪個執行緒先更新DB再洗掉快取,快取都會被洗掉,不會導致快取和DB資料不一致 | 不會出現 | 異步更新快取是基于先更新DB再洗掉快取的基礎上的改進:更新DB之后,基于消費佇列異步洗掉快取 |
| 并發讀寫 | 異步洗掉快取期間,讀執行緒獲取的快取是舊資料,短暫出現資料不一致,異步洗掉快取后最侄訓一致 | 短暫不一致,最侄訓一致 |
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/546659.html
標籤:其他
上一篇:[20230308]12c以上版本模糊查詢問題.txt
下一篇:MySQL學習筆記-事務
