四月份的時候,有位朋友去美團面試,他說被問到Redis與MySQL雙寫一致性如何保證? 這道題其實就是在問快取和資料庫在雙寫場景下,一致性是如何保證的?本文將跟大家一起來探討如何回答這個問題。
一致性就是資料保持一致,在分散式系統中,可以理解為多個節點中資料的值是一致的。
快取可以提升效能、緩解資料庫壓力,但是使用快取也會導致資料不一致性的問題。一般我們是如何使用快取呢?有三種經典的快取模式:
Cache-Aside Pattern,即旁路快取模式,它的提出是為了儘可能地解決快取與資料庫的資料不一致問題。
Cache-Aside Pattern的讀請求流程如下:
Cache-Aside Pattern的寫請求流程如下:
更新的時候,先更新資料庫,然後再刪除快取。
Read/Write Through模式中,伺服器端把快取作為主要資料儲存。應用程式跟資料庫快取互動,都是通過抽象快取層完成的。
Read-Through的簡要流程如下
這個簡要流程是不是跟Cache-Aside很像呢?其實Read-Through就是多了一層Cache-Provider,流程如下:
Read-Through實際只是在Cache-Aside之上進行了一層封裝,它會讓程式程式碼變得更簡潔,同時也減少資料來源上的負載。
Write-Through模式下,當發生寫請求時,也是由快取抽象層完成資料來源和快取資料的更新,流程如下:
Write behind跟Read-Through/Write-Through有相似的地方,都是由Cache Provider
來負責快取和資料庫的讀寫。它兩又有個很大的不同:Read/Write Through是同步更新快取和資料的,Write Behind則是隻更新快取,不直接更新資料庫,通過批次非同步的方式來更新資料庫。
這種方式下,快取和資料庫的一致性不強,對一致性要求高的系統要謹慎使用。但是它適合頻繁寫的場景,MySQL的InnoDB Buffer Pool機制就使用到這種模式。
一般業務場景,我們使用的就是Cache-Aside模式。 有些小夥伴可能會問, Cache-Aside在寫入請求的時候,為什麼是刪除快取而不是更新快取呢?
我們在操作快取的時候,到底應該刪除快取還是更新快取呢?我們先來看個例子:
這時候,快取儲存的是A的資料(老資料),資料庫儲存的是B的資料(新資料),資料不一致了,髒資料出現啦。如果是刪除快取取代更新快取則不會出現這個髒資料問題。
更新快取相對於刪除快取,還有兩點劣勢:
Cache-Aside
快取模式中,有些小夥伴還是有疑問,在寫入請求的時候,為什麼是先運算元據庫呢?為什麼不先操作快取呢?
假設有A、B兩個請求,請求A做更新操作,請求B做查詢讀取操作。
醬紫就有問題啦,快取和資料庫的資料不一致了。快取儲存的是老資料,資料庫儲存的是新資料。因此,Cache-Aside
快取模式,選擇了先運算元據庫而不是先操作快取。
有些小夥伴可能會說,不一定要先運算元據庫呀,採用快取延時雙刪策略就好啦?什麼是延時雙刪呢?
這個休眠一會,一般多久呢?都是1秒?
這個休眠時間 = 讀業務邏輯資料的耗時 + 幾百毫秒。 為了確保讀請求結束,寫請求可以刪除讀請求可能帶來的快取髒資料。
不管是延時雙刪還是Cache-Aside的先運算元據庫再刪除快取,如果第二步的刪除快取失敗呢,刪除失敗會導致髒資料哦~
刪除失敗就多刪除幾次呀,保證刪除快取成功呀~ 所以可以引入刪除快取重試機制
重試刪除快取機制還可以,就是會造成好多業務程式碼入侵。其實,還可以通過資料庫的binlog來非同步淘汰key。
以mysql為例 可以使用阿里的canal將binlog紀錄檔採集傳送到MQ佇列裡面,然後通過ACK機制確認處理這條更新訊息,刪除快取,保證資料快取一致性
推薦學習:《》以上就是Redis與MySQL雙寫一致性如何保證? (美團二面)的詳細內容,更多請關注TW511.COM其它相關文章!