快取與資料庫一致性
1.使用快取的場景
快取是提高系統讀效能的常用技術,尤其對於讀多寫少的應用場景,使用快取可以極大的提高系統的效能.
例子:查詢使用者的存款: select money from user where uid = YYY;為了優化該查詢功能,我們可以在快取中建立uid->money的鍵值對。減少資料庫的查詢壓力。
2.讀操作流程
目前資料庫和快取中都有儲存資料,當讀取資料的時候,流程如下。
-
先讀取快取是否存在資料(uid->money)。如果快取中有資料返回結果。
-
如果快取中沒有資料,則從資料庫中讀取資料。
介紹一個概念:快取命中率:快取命中數/總快取訪問數。
3. 寫操作流程
在介紹寫操作流程之前,先討論兩個問題
問題一:淘汰快取還是更新快取?
淘汰快取:資料只會寫入資料庫,不會寫入快取,只會把資料淘汰掉。
更新快取:資料不但寫入資料庫,還會寫入快取。
問題二:先寫快取還是先寫資料庫?
由於對快取的更新和資料庫的更新無法保證事務性操作。一定涉及到哪個先做,哪個後做的問題,我們的原則是採取對業務影響小的策略。下面是四種不同的組合策略:
由此可見第四種策略的影響最小,只會造成一次查詢快取miss而已。那麼當查詢快取miss的時候,我們該怎麼辦?很簡單,查詢資料庫,然後將資料庫的內容更新到快取中。可能有人會問第四種策略,如果一上來淘汰快取就失敗了怎麼辦,當然是直接返回即可,通知使用者本次操作失敗。
我們的結論是:先淘汰快取,再寫資料庫。
4. 分散式環境下如何保證一致性
下面我們再簡單回顧下”先淘汰快取,再寫資料庫 ”策略的讀寫流程。
寫流程:
- 先淘汰快取
- 再寫資料庫
讀流程:
- 先讀快取,如果資料命中則返回
- 如果資料未命中則讀取資料庫
- 將資料庫讀出來的資料寫入快取
4.1 不一致性的例子
我們的這種策略在序列執行的情況,保證一致性是沒有問題的。但是在分散式環境下,資料的讀寫都是併發的,可能有多個服務對同一個資料進行讀寫,也就是說後發出來的請求有可能先完成。我們來舉個例子:
- 傳送了寫請求A,A的第一步淘汰了cache(如上圖中的1)
- A的第二步寫資料庫,發出修改請求(如上圖中的2)
- 傳送了讀請求B,B的第一步讀取cache, 發現cache中是空的(如上圖中的3)
- B的第二步讀取資料庫,發出讀取請求,此時A的第二步寫資料還沒完成,讀出了髒資料,並放入了cache(如上圖中的4)。即後發出的請求4比先發出的請求2先完成了,讀出了髒資料,髒資料又入了快取,造成快取與資料庫中的資料不一致。
4.2解決思路
我們來仔細看一下上面的例子,其實問題就出在對同一資料讀取/寫入請求不是序列的,而是併發的。那麼如何能做到對同一資料的讀取/寫入請求是序列的?只需要讓”同一資料的訪問通過同一條DB連線執行 ”就行。如何做到這一點?可以修改獲取DB連線的方法CPool.DBConnection(), 修改為CPool.DBConnection(uuid)[返回uuid取模相關聯的連線]。
等等,”CPool.DBConnection(uuid)”這個程式碼是執行在每個service上面的,這樣只能保證每個service上面是同一條DB連線。如何解決這個問題?聰明如你,可以在應用層根據uuid取模,來獲取相關的service。這樣就能保證同一資料的請求訊息,都會路由到同一個service。
5.主從DB與cache如何保證一致性
在只有主庫時,通過我們上面講的”序列化”的思路可以解決快取與資料庫不一致的問題。但是在”主從同步,讀寫分離的資料庫架構下”,有可能出現髒資料入快取的情況,此時序列化方案不再適用了,下面我們來討論一下這個問題。
5.1不一致的例子
- 請求A發起了一個寫操作,第一步淘汰了cache(如上圖中的1)
- 請求A繼續寫資料庫,寫的是主庫,寫入最新資料(如上圖中的2)
- 請求B發起了一個讀操作,讀cache, 此時 cache中是空的(如上圖中的3)
- 請求B繼續讀資料庫,讀的是從庫,此時恰巧主從同步還沒有完成,讀出來一個髒資料,然後髒資料入cache(如上圖中的4)
- 最後資料庫的主從同步完成了(如上圖的5)
這種情況下,其實就是主從同步的時延期間,有讀請求讀從庫導致的不一致。這個問題怎麼優化呢?
5.2 解決思路
假設主從同步的時延<1s, 那麼舊資料就是在那1s的間隙中入快取的,是不是可以在寫請求完成後,再休眠1s, 再次淘汰快取,就能將這1s內寫入的髒資料再次淘汰掉呢?
Bingo, 當然是可以。
寫請求的步驟如下:
- 先淘汰快取
- 再寫資料庫
- 休眠1s, 再次淘汰快取
這樣的話保證一致性是沒有問題的,但是所有的寫請求都阻塞了1s, 大大降低了寫請求的吞吐量, 這是不可接受的。其實我們不需要休眠1s,而是直接將”淘汰快取的任務”交給一個非同步的timer來處理。
多說一句,從架構的角度來看,其實我們可以將對快取,資料庫的操作獨立出來,提供一個統一的服務介面,這樣上層的service就不需要關注先操作快取,還是先運算元據庫等問題,我們的架構可以是這樣的:
參考:
https://www.cnblogs.com/winner-0715/p/7451664.html
相關文章
- 分散式快取--快取與資料庫一致性方案分散式快取資料庫
- 快取與資料庫的一致性快取資料庫
- 資料庫與快取雙寫一致性資料庫快取
- Redis快取穿透、擊穿、雪崩,資料庫與快取一致性Redis快取穿透資料庫
- 資料庫與快取資料一致性解決方案資料庫快取
- 快取與資料庫的雙寫一致性快取資料庫
- 快取與資料庫一致性問題深度剖析快取資料庫
- 快取與資料庫雙寫一致性 深度分析快取資料庫
- 快取淘汰、快取穿透、快取擊穿、快取雪崩、資料庫快取雙寫一致性快取穿透資料庫
- 快取與資料庫雙寫一致性幾種策略分析快取資料庫
- 如何解決資料庫與快取的一致性問題資料庫快取
- 如何保證快取與資料庫的雙寫一致性?快取資料庫
- 如何保證快取(redis)與資料庫的雙寫一致性快取Redis資料庫
- 如何保證快取和資料庫的一致性?快取資料庫
- 資料庫和快取的一致性如何保證資料庫快取
- [Redis] 02-快取和資料庫資料一致性問題Redis快取資料庫
- Cache與資料庫的一致性(快取更新模式和操作順序)資料庫快取模式
- 從實戰出發,聊聊快取資料庫一致性快取資料庫
- 趣說 | 資料庫和快取如何保證一致性?資料庫快取
- 阿里面試題:如何保證快取與資料庫的雙寫一致性?阿里面試題快取資料庫
- 首個徹底保證快取與資料庫一致性的開源方案快取資料庫
- 資料庫和快取雙寫一致性方案總結分析資料庫快取
- 就是這麼應對面試官的快取與資料庫一致性問題?面試快取資料庫
- 分散式之資料庫和快取雙寫一致性方案解析分散式資料庫快取
- 分散式之資料庫和快取雙寫一致性方案(二)分散式資料庫快取
- 面試重災區:怎麼保證快取與資料庫的雙寫一致性?面試快取資料庫
- Redis與資料庫資料一致性Redis資料庫
- Python操作Redis快取資料庫PythonRedis快取資料庫
- 分散式快取--快取與資料庫強一致場景下的方案分散式快取資料庫
- 面試常問:如何保證Redis快取和資料庫的資料一致性NRXW面試Redis快取資料庫
- 快取與資料庫不一致,咋辦?快取資料庫
- Redis快取資料庫-快速入門Redis快取資料庫
- 深入理解分散式之資料庫和快取雙寫一致性方案解析分散式資料庫快取
- 【大廠面試01期】高併發場景下,如何保證快取與資料庫一致性?面試快取資料庫
- 使用Redis和Java進行資料庫快取 - DZone資料庫RedisJava資料庫快取
- 快取一致性快取
- 究竟先操作快取,還是資料庫?快取資料庫
- 技能篇:關於快取資料的一致性探討快取