溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

MySQL數(shù)據(jù)庫和Redis緩存一致性的更新策略是什么

發(fā)布時(shí)間:2023-05-08 15:13:19 來源:億速云 閱讀:126 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“MySQL數(shù)據(jù)庫和Redis緩存一致性的更新策略是什么”的相關(guān)知識(shí),小編通過實(shí)際案例向大家展示操作過程,操作方法簡單快捷,實(shí)用性強(qiáng),希望這篇“MySQL數(shù)據(jù)庫和Redis緩存一致性的更新策略是什么”文章能幫助大家解決問題。

    一、更新策略

    1、如果Redis中有數(shù)據(jù),需要和數(shù)據(jù)庫中的值相同。

    2、如果Redis中無數(shù)據(jù),數(shù)據(jù)庫中的最新值要對(duì)Redis進(jìn)行同步更新。

    二、讀寫緩存

    1、同步直寫策略

    寫入數(shù)據(jù)庫也同步寫Redis緩存,緩存和數(shù)據(jù)庫中的數(shù)據(jù)一致;對(duì)于讀寫緩存來說,要保證緩存和數(shù)據(jù)庫中的數(shù)據(jù)一致,就要保證同步直寫策略。

    2、異步緩寫策略

    某些業(yè)務(wù)運(yùn)行中,MySQL數(shù)據(jù)更新之后,允許在一定時(shí)間后再進(jìn)行Redis數(shù)據(jù)同步,比如物流系統(tǒng)。

    當(dāng)出現(xiàn)異常情況時(shí),不得不將失敗的動(dòng)作重新修補(bǔ),需要借助rabbitmq或kafka進(jìn)行重寫。

    三、雙檢加鎖策略

    多個(gè)線程同時(shí)去查詢數(shù)據(jù)庫的這條數(shù)據(jù),那么我們可以在第一個(gè)查詢數(shù)據(jù)的請(qǐng)求上使用一個(gè) 互斥鎖來鎖住它。

    其他的線程走到這一步拿不到鎖就等著,等第一個(gè)線程查詢到了數(shù)據(jù),然后做緩存。

    后面的線程進(jìn)來發(fā)現(xiàn)已經(jīng)有緩存了,就直接走緩存。

    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數(shù)據(jù)庫中查詢
            value = studentDao.get(key);
            // 寫入Redis緩存
            redisTemplate.setnx(key,value,time);
            return value;
        }
    }

    四、數(shù)據(jù)庫和緩存一致性的更新策略

    1、先更新數(shù)據(jù)庫,再更新Redis

    按照常理出牌的話,應(yīng)該都是如此吧?那么,這種情況下,會(huì)有啥問題呢?

    如果更新數(shù)據(jù)庫成功后,更新Redis之前異常了,會(huì)出現(xiàn)什么情況呢?

    數(shù)據(jù)庫與Redis內(nèi)緩存數(shù)據(jù)不一致。

    2、先更新緩存,再更新數(shù)據(jù)庫

    多線程情況下,會(huì)有問題。

    比如

    • 線程1更新redis = 200;

    • 線程2更新redis = 100;

    • 線程2更新MySQL = 100;

    • 線程1更新MySQL = 200;

    結(jié)果呢,Redis=100、MySQL=200;我擦!

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

    線程1刪除了Redis的緩存數(shù)據(jù),然后去更新MySQL數(shù)據(jù)庫;
    還沒等MySQL更新完畢,線程2殺來,讀取緩存數(shù)據(jù);
    但是,此時(shí)MySQL數(shù)據(jù)庫還沒更新,線程2讀取了MySQL中的舊值,然后線程2,還會(huì)將舊值寫入Redis作為數(shù)據(jù)緩存;
    線程1更新完MySQL數(shù)據(jù)后,發(fā)現(xiàn)Redis中已經(jīng)有數(shù)據(jù)了,之前都刪過了,那我就不更新了;
    完蛋了。。

    延時(shí)雙刪

    延時(shí)雙刪可以解決上面的問題,只要sleep的時(shí)間大于線程2讀取數(shù)據(jù)再寫入緩存的時(shí)間就可以了,也就是線程1的二次清緩存操作要在線程2寫入緩存之后,這樣才能保證Redis緩存中的數(shù)據(jù)是最新的。

    /**
     * 延時(shí)雙刪
     * @autor 哪吒編程
     */
    public void deleteRedisData(Student stu){
        // 刪除Redis中的緩存數(shù)據(jù)
        jedis.del(stu);
    
        // 更新MySQL數(shù)據(jù)庫數(shù)據(jù)
        studentDao.update(stu);
    
        // 休息兩秒
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        // 刪除Redis中的緩存數(shù)據(jù)
        jedis.del(stu);
    }

    延遲雙刪最大的問題就是sleep,在效率為王的今天,sleep能不用還是不用為好。

    你不睡我都嫌你慢,你還睡上了…

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

    1. 線程1先更新數(shù)據(jù)庫,再刪除Redis緩存;

    2. 線程2在線程1刪除Redis緩存之前發(fā)起請(qǐng)求,得到了未刪除的Redis緩存;

    3. 線程1此時(shí)才刪除Redis緩存數(shù)據(jù);

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

    這種情況如何解決呢?

    引入消息中間件解決戰(zhàn)斗,再一次詳細(xì)的復(fù)盤一下。

    1. 更新數(shù)據(jù)庫;

    2. 數(shù)據(jù)庫將操作信息寫入binlog日志;

    3. 訂閱程序提取出key和數(shù)據(jù);

    4. 嘗試刪除緩存操作,發(fā)現(xiàn)刪除失??;

    5. 將這些數(shù)據(jù)信息發(fā)送到消息中間件中;

    6. 從消息中間件中獲取該數(shù)據(jù),重新操作;

    5、總結(jié)

    哪吒推薦使用第四種方式,先更新數(shù)據(jù)庫,再刪除緩存。

    方式①和方式②缺點(diǎn)太過明顯,不考慮;
    方式③中的sleep,總是讓人頭疼;
    方式④是一個(gè)比較全面的方案,但是增加了學(xué)習(xí)成本、維護(hù)成本,因?yàn)樵黾恿讼⒅虚g件。

    五、MySQL主從復(fù)制工作原理

    MySQL數(shù)據(jù)庫和Redis緩存一致性的更新策略是什么

    1、當(dāng) master 主服務(wù)器上的數(shù)據(jù)發(fā)生改變時(shí),則將其改變寫入二進(jìn)制事件日志文件中;

    2、salve 從服務(wù)器會(huì)在一定時(shí)間間隔內(nèi)對(duì) master 主服務(wù)器上的二進(jìn)制日志進(jìn)行探測(cè),探測(cè)其是否發(fā)生過改變,

    如果探測(cè)到 master 主服務(wù)器的二進(jìn)制事件日志發(fā)生了改變,則開始一個(gè) I/O Thread 請(qǐng)求 master 二進(jìn)制事件日志;

    3、同時(shí) master 主服務(wù)器為每個(gè) I/O Thread 啟動(dòng)一個(gè)dump Thread,用于向其發(fā)送二進(jìn)制事件日志;

    4、slave 從服務(wù)器將接收到的二進(jìn)制事件日志保存至自己本地的中繼日志文件中;

    5、salve 從服務(wù)器將啟動(dòng) SQL Thread 從中繼日志中讀取二進(jìn)制日志,在本地重放,使得其數(shù)據(jù)和主服務(wù)器保持一致;

    6、最后 I/O Thread 和 SQL Thread 將進(jìn)入睡眠狀態(tài),等待下一次被喚醒。

    關(guān)于“MySQL數(shù)據(jù)庫和Redis緩存一致性的更新策略是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI