<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>

          數(shù)據(jù)庫跟緩存的雙寫一致性

          共 2120字,需瀏覽 5分鐘

           ·

          2021-04-06 21:20

          1 關(guān)于一致性

          為加速系統(tǒng)性能一般都會引入緩存機(jī)制,比如 Redis。這種情況下當(dāng)用戶數(shù)據(jù)時一般會按照如下流程:

          讀流程

          關(guān)于讀的流程大家是沒有異議的,但是對于數(shù)據(jù)的更新呢,如何操作才算合理呢?

          1. 先更新數(shù)據(jù)庫再更新緩存。

          2. 先刪緩存再更新數(shù)據(jù)庫。

          3. 先更新數(shù)據(jù)庫再刪緩存。

          2 一致性解決方法

          2.1 緩存TTL

          簡單直接又暴力的方法,如果有些數(shù)據(jù)不重要,我們讀完一次數(shù)據(jù)到緩存后設(shè)置個TTL即可,等待超時后緩存自動從數(shù)據(jù)庫讀取下數(shù)據(jù)。

          2.2  先更新數(shù)據(jù)庫 再更新緩存

          假如我們有A、B兩個請求,A請求將age = 14,B請求將age = 12。我們看下正常執(zhí)行跟非正常執(zhí)行情況:

          緩存舊數(shù)據(jù)

          可發(fā)現(xiàn)如果出現(xiàn)網(wǎng)絡(luò)震蕩會導(dǎo)致緩存的數(shù)據(jù)是舊數(shù)據(jù)。因此這種方法不可取。并且如果是如下場景也不合適:

          1. 寫場景多而讀場景少的業(yè)務(wù)需求,此時緩存不是經(jīng)常性的讀,卻被頻繁的更新。

          2. 如果緩存的數(shù)據(jù)是經(jīng)過各種復(fù)雜計算后寫入的,那每次寫入緩存都要運算一次,此法不可取。

          2.3 先刪緩存 再更新數(shù)據(jù)庫

          假如A先請求更改數(shù)據(jù),B請求讀數(shù)據(jù),如果因為網(wǎng)絡(luò)導(dǎo)致發(fā)生如下情況也會造成緩存臟數(shù)據(jù),如果此時緩存沒有設(shè)置TTL那會一直是臟數(shù)據(jù)。

          緩存臟數(shù)據(jù)

          上面這種情況如何解決呢?一般可以采用延時雙刪策略,他的核心執(zhí)行流程如下:
          public  void write(String key,Object value){
              redis.delKey(key);
              db.updateValue(value);
              Thread.sleep(1000); // 再次刪除
              redis.delKey(key);
          }

          該思路落實到流程圖上如下所示:

          延時雙刪策略

          sleep的時間要根據(jù)業(yè)務(wù)數(shù)據(jù)邏輯耗時而定,反正目的是確保讀請求結(jié)束,寫請求可以刪除讀請求造成的緩存臟數(shù)據(jù)

          當(dāng)然如果用的是主從寫讀架構(gòu),那處理思路跟上面類似,無非就是休眠時間再加上主從同步的時間即可。

          主從模式二次刪除

          可是其實第二次刪除還是有不妥的地方:

          1. 二次刪除前面涉及到休眠,可能導(dǎo)致系統(tǒng)性能降低,可以采用異步的方式,再起一個線程來進(jìn)行異步刪除。

          2. 如果二次刪除失敗了,還是會導(dǎo)致緩存臟數(shù)據(jù)存在的啊!

          2.4 先更新數(shù)據(jù)庫 再刪緩存

          針對緩存更新問題,老外提出了一個名為《Cache-Aside pattern》的緩存更新套路,該策略在Facebook中也廣泛使用,該策略指出:

          1. 失效:應(yīng)用程序先從緩存取數(shù)據(jù),沒有得到,則從數(shù)據(jù)庫中取數(shù)據(jù),成功后,放到緩存中。

          2. 命中:應(yīng)用程序從緩存中取數(shù)據(jù),取到后返回。

          3. 更新:先把數(shù)據(jù)存到數(shù)據(jù)庫中,成功后,再讓緩存失效。

          假如此時A、B兩個線程同時請求,正常來講不管你是讀寫分離還是單機(jī)版,讀一般比寫快。那刪除緩存一般是有效的。

          先更新數(shù)據(jù)庫再刪除緩存

          但是也有可能別的原因?qū)е伦x比寫還慢,導(dǎo)致我們刪了個寂寞,雖然這種情況很少發(fā)生。
          讀比寫還慢時

          該方案相比先刪除緩存再更新數(shù)據(jù)庫還是穩(wěn)妥些的,但是也不是萬無一失的。不管是先刪緩存再更新數(shù)據(jù)庫還是先更新數(shù)據(jù)庫再刪緩存,如果刪除緩存失敗了都會導(dǎo)致緩存跟數(shù)據(jù)不一致問題

          2.5 消息隊列 確保消息刪除

          通過消息隊列的確認(rèn)消費機(jī)制來刪除緩存。

          消息隊列機(jī)制確保刪除

          缺點也很明顯:
          1. 對業(yè)務(wù)線代碼造成大量的侵入,引入了中間件。

          2. 消息的延遲刪除也會造成短暫的不一致。

          2.6 專門程序+消息隊列 確保消息刪除

          該方案啟動一個訂閱程序去訂閱數(shù)據(jù)庫的binlog,獲得需要操作的數(shù)據(jù)。在應(yīng)用程序中,另起一段程序,獲得這個訂閱程序傳來的信息,進(jìn)行刪除緩存操作。

          專門程序刪除緩存

          訂閱binlog程序在mysql中有現(xiàn)成的中間件叫canal,可以完成訂閱binlog日志的功能。

          3 總結(jié)

          分析后你會發(fā)現(xiàn)數(shù)據(jù)更新時緩存是刪除不是更新,而刪除緩存一般有三種方法:

          1. 如果緩存數(shù)據(jù)不敏感,直接給緩存設(shè)置TTL即可。

          2. 先刪緩存再更新數(shù)據(jù)庫,此時需配合延時雙刪技術(shù),但可能導(dǎo)致二次刪除失敗。

          3. 先更新數(shù)據(jù)庫再刪緩存,此時需配合binlog消費 + 消息隊列來實現(xiàn)。

          4 參考

          1. Java后端:http://rjzheng.cnblogs.com

          2. 艾小仙分布式鎖:https://t.1yb.co/jaaA

          推薦閱讀:

          Nginx的這個默認(rèn)配置,差點讓我的職場生涯折戟沉沙

          一個空格引發(fā)的“慘案“

          “坑爹”排行榜:Java語言最違反常識的功能點TOP 10

          Kafka性能篇:為何Kafka這么"快"?

          原創(chuàng)好文!億級流量網(wǎng)關(guān)設(shè)計思路

          不可不知的軟件架構(gòu)模式

          Redis 高可用篇:你管這叫 Sentinel 哨兵集群原理

          關(guān)互聯(lián)網(wǎng)全棧架構(gòu)


          瀏覽 26
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  免费在线观看成人性爱视频 | 黄色一二三区 | 亚洲性爱AV在线观看 | 免费黄色成人在线观看 | 黄色片AA|