<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官: Redis 與 MySQL 雙寫一致性如何保證?

          共 3638字,需瀏覽 8分鐘

           ·

          2022-01-22 18:57

          前言

          四月份的時候,有位好朋友去美團面試。他說,被問到Redis與MySQL雙寫一致性如何保證?這道題其實就是在問緩存和數(shù)據(jù)庫在雙寫場景下,一致性是如何保證的?本文將跟大家一起來探討如何回答這個問題。


          談?wù)勔恢滦?/span>

          一致性就是數(shù)據(jù)保持一致,在分布式系統(tǒng)中,可以理解為多個節(jié)點中數(shù)據(jù)的值是一致的。

          • 強一致性:這種一致性級別是最符合用戶直覺的,它要求系統(tǒng)寫入什么,讀出來的也會是什么,用戶體驗好,但實現(xiàn)起來往往對系統(tǒng)的性能影響大
          • 弱一致性:這種一致性級別約束了系統(tǒng)在寫入成功后,不承諾立即可以讀到寫入的值,也不承諾多久之后數(shù)據(jù)能夠達到一致,但會盡可能地保證到某個時間級別(比如秒級別)后,數(shù)據(jù)能夠達到一致狀態(tài)
          • 最終一致性:最終一致性是弱一致性的一個特例,系統(tǒng)會保證在一定時間內(nèi),能夠達到一個數(shù)據(jù)一致的狀態(tài)。這里之所以將最終一致性單獨提出來,是因為它是弱一致性中非常推崇的一種一致性模型,也是業(yè)界在大型分布式系統(tǒng)的數(shù)據(jù)一致性上比較推崇的模型

          三個經(jīng)典的緩存模式

          緩存可以提升性能、緩解數(shù)據(jù)庫壓力,但是使用緩存也會導致數(shù)據(jù)不一致性的問題。一般我們是如何使用緩存呢?有三種經(jīng)典的緩存使用模式:

          • Cache-Aside Pattern
          • Read-Through/Write-through
          • Write-behind

          Cache-Aside Pattern

          Cache-Aside Pattern,即旁路緩存模式,它的提出是為了盡可能地解決緩存與數(shù)據(jù)庫的數(shù)據(jù)不一致問題。

          Cache-Aside讀流程

          Cache-Aside Pattern的讀請求流程如下:

          Cache-Aside讀請求
          1. 讀的時候,先讀緩存,緩存命中的話,直接返回數(shù)據(jù)
          2. 緩存沒有命中的話,就去讀數(shù)據(jù)庫,從數(shù)據(jù)庫取出數(shù)據(jù),放入緩存后,同時返回響應(yīng)。

          Cache-Aside 寫流程

          Cache-Aside Pattern的寫請求流程如下:

          Cache-Aside寫請求

          更新的時候,先更新數(shù)據(jù)庫,然后再刪除緩存。

          Read-Through/Write-Through(讀寫穿透)

          Read/Write-Through模式中,服務(wù)端把緩存作為主要數(shù)據(jù)存儲。應(yīng)用程序跟數(shù)據(jù)庫緩存交互,都是通過抽象緩存層完成的。

          Read-Through

          Read-Through的簡要流程如下

          Read-Through簡要流程
          1. 從緩存讀取數(shù)據(jù),讀到直接返回
          2. 如果讀取不到的話,從數(shù)據(jù)庫加載,寫入緩存后,再返回響應(yīng)。

          這個簡要流程是不是跟Cache-Aside很像呢?其實Read-Through就是多了一層Cache-Provider而已,流程如下:

          Read-Through流程

          Read-Through實際只是在Cache-Aside之上進行了一層封裝,它會讓程序代碼變得更簡潔,同時也減少數(shù)據(jù)源上的負載。

          Write-Through

          Write-Through模式下,當發(fā)生寫請求時,也是由緩存抽象層完成數(shù)據(jù)源和緩存數(shù)據(jù)的更新,流程如下:

          Write-behind (異步緩存寫入)

          Write-behind 跟Read-Through/Write-Through有相似的地方,都是由Cache Provider來負責緩存和數(shù)據(jù)庫的讀寫。它們又有個很大的不同:Read/Write-Through是同步更新緩存和數(shù)據(jù)的,Write-Behind則是只更新緩存,不直接更新數(shù)據(jù)庫,通過批量異步的方式來更新數(shù)據(jù)庫。

          Write behind流程

          這種方式下,緩存和數(shù)據(jù)庫的一致性不強,對一致性要求高的系統(tǒng)要謹慎使用。但是它適合頻繁寫的場景,MySQL的InnoDB Buffer Pool機制就使用到這種模式。

          操作緩存的時候,到底是刪除緩存呢,還是更新緩存?

          日常開發(fā)中,我們一般使用的就是Cache-Aside模式。有些小伙伴可能會問, Cache-Aside在寫入請求的時候,為什么是刪除緩存而不是更新緩存呢?

          Cache-Aside寫入流程

          我們在操作緩存的時候,到底應(yīng)該刪除緩存還是更新緩存呢?我們先來看個例子:

          1. 線程A先發(fā)起一個寫操作,第一步先更新數(shù)據(jù)庫
          2. 線程B再發(fā)起一個寫操作,第二步更新了數(shù)據(jù)庫
          3. 由于網(wǎng)絡(luò)等原因,線程B先更新了緩存
          4. 線程A更新緩存。

          這時候,緩存保存的是A的數(shù)據(jù)(老數(shù)據(jù)),數(shù)據(jù)庫保存的是B的數(shù)據(jù)(新數(shù)據(jù)),數(shù)據(jù)不一致了,臟數(shù)據(jù)出現(xiàn)啦。如果是刪除緩存取代更新緩存則不會出現(xiàn)這個臟數(shù)據(jù)問題。

          更新緩存相對于刪除緩存,還有兩點劣勢:

          • 如果你寫入的緩存值,是經(jīng)過復雜計算才得到的話。更新緩存頻率高的話,就浪費性能啦。
          • 在寫數(shù)據(jù)庫場景多,讀數(shù)據(jù)場景少的情況下,數(shù)據(jù)很多時候還沒被讀取到,又被更新了,這也浪費了性能呢(實際上,寫多的場景,用緩存也不是很劃算的,哈哈)

          雙寫的情況下,先操作數(shù)據(jù)庫還是先操作緩存?

          Cache-Aside緩存模式中,有些小伙伴還是會有疑問,在寫請求過來的時候,為什么是先操作數(shù)據(jù)庫呢?為什么不先操作緩存呢?

          假設(shè)有A、B兩個請求,請求A做更新操作,請求B做查詢讀取操作。

          1. 線程A發(fā)起一個寫操作,第一步del cache
          2. 此時線程B發(fā)起一個讀操作,cache miss
          3. 線程B繼續(xù)讀DB,讀出來一個老數(shù)據(jù)
          4. 然后線程B把老數(shù)據(jù)設(shè)置入cache
          5. 線程A寫入DB最新的數(shù)據(jù)

          醬紫就有問題啦,緩存和數(shù)據(jù)庫的數(shù)據(jù)不一致了。緩存保存的是老數(shù)據(jù),數(shù)據(jù)庫保存的是新數(shù)據(jù)。因此,Cache-Aside緩存模式,選擇了先操作數(shù)據(jù)庫而不是先操作緩存。

          • 個別小伙伴可能會問,先操作數(shù)據(jù)庫再操作緩存,不一樣也會導致數(shù)據(jù)不一致嘛?它倆又不是原子性操作的。這個是會的,但是這種方式,一般因為刪除緩存失敗等原因,才會導致臟數(shù)據(jù),這個概率就很低。小伙伴們可以畫下操作流程圖,自己先分析下哈。接下來我們再來分析這種刪除緩存失敗的情況,如何保證一致性

          數(shù)據(jù)庫和緩存數(shù)據(jù)保持強一致,可以嘛?

          實際上,沒辦法做到數(shù)據(jù)庫與緩存絕對的一致性。

          • 加鎖可以嘛?并發(fā)寫期間加鎖,任何讀操作不寫入緩存?
          • 緩存及數(shù)據(jù)庫封裝CAS樂觀鎖,更新緩存時通過lua腳本?
          • 分布式事務(wù),3PC?TCC?

          其實,這是由CAP理論決定的。緩存系統(tǒng)適用的場景就是非強一致性的場景,它屬于CAP中的AP。個人覺得,追求絕對一致性的業(yè)務(wù)場景,不適合引入緩存。

          CAP理論,指的是在一個分布式系統(tǒng)中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區(qū)容錯性),三者不可得兼。

          但是,通過一些方案優(yōu)化處理,是可以保證弱一致性,最終一致性的。

          3種方案保證數(shù)據(jù)庫與緩存的一致性

          緩存延時雙刪

          有些小伙伴可能會說,并不一定要先操作數(shù)據(jù)庫呀,采用緩存延時雙刪策略,就可以保證數(shù)據(jù)的一致性啦。什么是延時雙刪呢?

          延時雙刪流程
          1. 先刪除緩存
          2. 再更新數(shù)據(jù)庫
          3. 休眠一會(比如1秒),再次刪除緩存。

          這個休眠一會,一般多久呢?都是1秒?

          這個休眠時間 = ?讀業(yè)務(wù)邏輯數(shù)據(jù)的耗時 + 幾百毫秒。為了確保讀請求結(jié)束,寫請求可以刪除讀請求可能帶來的緩存臟數(shù)據(jù)。

          這種方案還算可以,只有休眠那一會(比如就那1秒),可能有臟數(shù)據(jù),一般業(yè)務(wù)也會接受的。但是如果第二次刪除緩存失敗呢?緩存和數(shù)據(jù)庫的數(shù)據(jù)還是可能不一致,對吧?給Key設(shè)置一個自然的expire過期時間,讓它自動過期怎樣?那業(yè)務(wù)要接受過期時間內(nèi),數(shù)據(jù)的不一致咯?還是有其他更佳方案呢?

          刪除緩存重試機制

          不管是延時雙刪還是Cache-Aside的先操作數(shù)據(jù)庫再刪除緩存,都可能會存在第二步的刪除緩存失敗,導致的數(shù)據(jù)不一致問題??梢允褂眠@個方案優(yōu)化:刪除失敗就多刪除幾次呀,保證刪除緩存成功就可以了呀~ 所以可以引入刪除緩存重試機制

          刪除緩存重試流程
          1. 寫請求更新數(shù)據(jù)庫
          2. 緩存因為某些原因,刪除失敗
          3. 把刪除失敗的key放到消息隊列
          4. 消費消息隊列的消息,獲取要刪除的key
          5. 重試刪除緩存操作

          讀取biglog異步刪除緩存

          重試刪除緩存機制還可以吧,就是會造成好多業(yè)務(wù)代碼入侵。其實,還可以這樣優(yōu)化:通過數(shù)據(jù)庫的binlog來異步淘汰key

          以mysql為例吧

          可以使用阿里的canal將binlog日志采集發(fā)送到MQ隊列里面
          然后通過ACK機制確認處理這條更新消息,刪除緩存,保證數(shù)據(jù)緩存一致性

          程序汪資料鏈接

          程序汪接的7個私活都在這里,經(jīng)驗整理

          Java項目分享 ?最新整理全集,找項目不累啦 04版

          堪稱神級的Spring Boot手冊,從基礎(chǔ)入門到實戰(zhàn)進階

          臥槽!字節(jié)跳動《算法中文手冊》火了,完整版 PDF 開放下載!

          臥槽!阿里大佬總結(jié)的《圖解Java》火了,完整版PDF開放下載!

          字節(jié)跳動總結(jié)的設(shè)計模式 PDF 火了,完整版開放下載!

          歡迎添加程序汪個人微信 itwang008? 進粉絲群或圍觀朋友圈

          瀏覽 68
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  先锋影音Vs男人资源站 | 亚洲AV影视网 | 99久久婷婷国产综合精品青牛牛 | 黄色电影网站免费在线观看 | 黄色免费国产 |