首頁  >  文章  >  資料庫  >  MySQL資料庫和Redis快取一致性的更新策略是什麼

MySQL資料庫和Redis快取一致性的更新策略是什麼

WBOY
WBOY轉載
2023-05-27 15:11:24704瀏覽

    一、更新策略

    1、如果Redis中有數據,需要和資料庫中的值相同。

    2、如果Redis中無數據,資料庫中的最新值要對Redis進行同步更新。

    二、讀寫快取

    1、同步直寫策略

    寫入資料庫也同步寫Redis緩存,快取和資料庫中的資料一致;對於讀寫緩存來說,要確保快取和資料庫中的資料一致,就要確保同步直寫策略。

    2、非同步緩寫策略

    某些業務運作中,MySQL資料更新之後,允許在一定時間後再進行Redis資料同步,例如物流系統。

    當出現異常情況時,必須將失敗的動作重新修補,需要藉助rabbitmq或kafka進行重寫。

    三、雙檢加鎖策略

    多個執行緒同時去查詢資料庫的這條數據,那麼我們可以在第一個查詢資料的請求上使用一個互斥鎖來鎖住它。

    其他的執行緒走到這一步拿不到鎖就等著,等第一個執行緒查詢到了數據,然後做快取。

    後面的執行緒進來發現已經有快取了,就直接走快取。

    public String get(String key){
        // 从Redis缓存中读取
        String value = redisTemplate.get(key);
    
        if(value != null){
            return value;
        }
    
        synchronized (RedisTest.class){
            // 重新尝试从Redis缓存中读取
            value = redisTemplate.get(key);
            if(value != null){
                return value;
            }
    
            // 从MySQL数据库中查询
            value = studentDao.get(key);
            // 写入Redis缓存
            redisTemplate.setnx(key,value,time);
            return value;
        }
    }

    四、資料庫與快取一致性的更新策略

    1、先更新資料庫,再更新Redis

    依照常理出牌的話,應該都是如此吧?那麼,這種情況下,會有啥問題呢?

    如果更新資料庫成功後,更新Redis之前異常了,會出現什麼情況呢?

    資料庫與Redis內快取資料不一致。

    2、先更新緩存,再更新資料庫

    多執行緒情況下,會有問題。

    例如

    • 線程1更新redis = 200;

    • 執行緒2更新redis = 100;





    1. 執行緒2更新MySQL = 100;
    2. #執行緒1更新MySQL = 200;

    結果呢,Redis= 100、MySQL=200;我擦!

    3、先刪除緩存,再更新資料庫

    線程1刪除了Redis的快取數據,然後去更新MySQL資料庫;
      還沒等MySQL更新完畢,線程2殺來,讀取快取資料;
    1. 但是,此時MySQL資料庫還沒更新,執行緒2讀取了MySQL中的舊值,然後執行緒2,也會將舊值寫入Redis作為資料快取;

      執行緒1更新完MySQL資料後,發現Redis中已經有資料了,之前都刪過了,那我就不更新了;

      完蛋了。 。
    2. 延時雙刪

      延時雙刪可以解決上面的問題,只要sleep的時間大於執行緒2讀取資料再寫入快取的時間就可以了,也就是執行緒1的二次清除快取操作要在執行緒2寫入快取之後,這樣才能確保Redis快取中的資料是最新的。
    3. /**
       * 延时双删
       * @autor 哪吒编程
       */
      public void deleteRedisData(Student stu){
          // 删除Redis中的缓存数据
          jedis.del(stu);
      
          // 更新MySQL数据库数据
          studentDao.update(stu);
      
          // 休息两秒
          try {
              TimeUnit.SECONDS.sleep(2);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      
          // 删除Redis中的缓存数据
          jedis.del(stu);
      }
    4. 延遲雙刪最大的問題就是sleep,在效率為王的今天,sleep能不用還是不用為好。

      你不睡我都嫌你慢,你還睡上了…
    5. 4、先更新資料庫,再刪除快取

    6. ##線程1先更新資料庫,再刪除Redis快取;
    7. 執行緒2在執行緒1刪除Redis快取之前發起請求,得到了未刪除的Redis快取;
    8. ##線程1此時才刪除Redis快取資料;

    問題還是有,這翻來覆去的,沒完沒了。

    這種情況要如何解決呢?


    引入訊息中間件解決戰鬥,再一次詳細的複盤一下。

    更新資料庫;

    MySQL資料庫和Redis快取一致性的更新策略是什麼

    資料庫將操作資訊寫入binlog日誌;

    訂閱程序提取出key和資料;

    嘗試刪除快取操作,發現刪除失敗;

    #########將這些資料資訊傳送到訊息中介軟體中; ############從訊息中間件取得該數據,重新操作;#############5、總結######哪吒推薦使用第四種方式,先更新資料庫,再刪除快取。 ######方式①和方式②缺點太過明顯,不考慮;###方式③中的sleep,總是讓人頭疼;###方式④是一個比較全面的方案,但是增加了學習成本、維護成本,因為增加了訊息中間件。 ######五、MySQL主從複製工作原理###############1、當master 主伺服器上的資料改變時,則將其變更寫入二進位事件在日誌檔案中;######2、salve 從伺服器會在一定時間間隔內對master 主伺服器上的二進位日誌進行探測,探測其是否發生過改變,######如果偵測到master 主伺服器的二進位事件日誌發生了改變,則開始一個I/O Thread 請求master 二進位事件日誌;######3、同時master 主伺服器為每個I/O Thread 啟動一個dump Thread,用於向其傳送二進位事件日誌;######4、slave 從伺服器將接收到的二進位事件日誌儲存到自己本機的中繼日誌檔案;###

    5、salve 從伺服器將啟動SQL Thread 從中繼日誌中讀取二進位日誌,在本機重播,使得其資料和主伺服器保持一致;

    ##6、最後I/O Thread 和SQL Thread 將進入睡眠狀態,等待下一次被喚醒。

    以上是MySQL資料庫和Redis快取一致性的更新策略是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除