溫馨提示×

溫馨提示×

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

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

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

發(fā)布時間:2020-07-07 08:15:39 來源:網(wǎng)絡(luò) 閱讀:980 作者:Java_老男孩 欄目:編程語言

一、為什么要使用分布式鎖

分布式環(huán)境下修改某個共有的數(shù)據(jù),比如redis的共有數(shù)據(jù);

在同一時間,可能多個節(jié)點都先查詢這個數(shù)據(jù),然后更新。在查詢的時候,結(jié)果是一樣的,但是各個節(jié)點更新的時候,就是以最后一個更新為準(zhǔn)了,這樣就會導(dǎo)致其它節(jié)點的更新其實是失敗的;

案例:告警設(shè)置max_step的功能就是分布式更新導(dǎo)致通知多次;

解決以上問題最徹底的辦法(不一定是最好)是使用分布式鎖,這樣可以保證數(shù)據(jù)的一致性。但是分布式鎖很多會帶來性能的下降,所以不一定是最好的方式。

二、分布式鎖的三種實現(xiàn)方式

1、基于數(shù)據(jù)庫實現(xiàn)分布式鎖

對字段增加唯一性約束;?

2、基于緩存(Redis等)實現(xiàn)分布式鎖

setnx()方法,這種很高效,另外也有一種比較低效的方式:查詢的時候就上鎖,如下:


try{
    lock = redisTemplate.opsForValue().setIfAbsent(lockKey, LOCK);
    logger.info("cancelCouponCode是否獲取到鎖:"+lock);
    if (lock) {
        // TODO
        redisTemplate.expire(lockKey,1, TimeUnit.MINUTES); //成功設(shè)置過期時間
        return res;
    }else {
        logger.info("cancelCouponCode沒有獲取到鎖,不執(zhí)行任務(wù)!");
    }
}finally{
    if(lock){   
        redisTemplate.delete(lockKey);
        logger.info("cancelCouponCode任務(wù)結(jié)束,釋放鎖!");       
    }else{
        logger.info("cancelCouponCode沒有獲取到鎖,無需釋放鎖!");
    }

3、基于Zookeeper實現(xiàn)分布式鎖

讓我們來回顧一下Zookeeper節(jié)點的概念:

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

Zookeeper的數(shù)據(jù)存儲結(jié)構(gòu)就像一棵樹,這棵樹由節(jié)點組成,這種節(jié)點叫做Znode。

Znode分為四種類型:

1.持久節(jié)點 (PERSISTENT)

默認(rèn)的節(jié)點類型。創(chuàng)建節(jié)點的客戶端與zookeeper斷開連接后,該節(jié)點依舊存在 。

2.持久節(jié)點順序節(jié)點(PERSISTENT_SEQUENTIAL)

所謂順序節(jié)點,就是在創(chuàng)建節(jié)點時,Zookeeper根據(jù)創(chuàng)建的時間順序給該節(jié)點名稱進(jìn)行編號:

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

3.臨時節(jié)點(EPHEMERAL)

和持久節(jié)點相反,當(dāng)創(chuàng)建節(jié)點的客戶端與zookeeper斷開連接后,臨時節(jié)點會被刪除:

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

4.臨時順序節(jié)點(EPHEMERAL_SEQUENTIAL)

顧名思義,臨時順序節(jié)點結(jié)合和臨時節(jié)點和順序節(jié)點的特點:在創(chuàng)建節(jié)點時,Zookeeper根據(jù)創(chuàng)建的時間順序給該節(jié)點名稱進(jìn)行編號;當(dāng)創(chuàng)建節(jié)點的客戶端與zookeeper斷開連接后,臨時節(jié)點會被刪除。

Zookeeper分布式鎖的原理

Zookeeper分布式鎖恰恰應(yīng)用了臨時順序節(jié)點。具體如何實現(xiàn)呢?讓我們來看一看詳細(xì)步驟:

獲取鎖

首先,在Zookeeper當(dāng)中創(chuàng)建一個持久節(jié)點ParentLock。當(dāng)?shù)谝粋€客戶端想要獲得鎖時,需要在ParentLock這個節(jié)點下面創(chuàng)建一個臨時順序節(jié)點?Lock1。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

之后,Client1查找ParentLock下面所有的臨時順序節(jié)點并排序,判斷自己所創(chuàng)建的節(jié)點Lock1是不是順序最靠前的一個。如果是第一個節(jié)點,則成功獲得鎖。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

這時候,如果再有一個客戶端 Client2 前來獲取鎖,則在ParentLock下載再創(chuàng)建一個臨時順序節(jié)點Lock2。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

Client2查找ParentLock下面所有的臨時順序節(jié)點并排序,判斷自己所創(chuàng)建的節(jié)點Lock2是不是順序最靠前的一個,結(jié)果發(fā)現(xiàn)節(jié)點Lock2并不是最小的。

于是,Client2向排序僅比它靠前的節(jié)點Lock1注冊Watcher,用于監(jiān)聽Lock1節(jié)點是否存在。這意味著Client2搶鎖失敗,進(jìn)入了等待狀態(tài)。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

這時候,如果又有一個客戶端Client3前來獲取鎖,則在ParentLock下載再創(chuàng)建一個臨時順序節(jié)點Lock3。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

Client3查找ParentLock下面所有的臨時順序節(jié)點并排序,判斷自己所創(chuàng)建的節(jié)點Lock3是不是順序最靠前的一個,結(jié)果同樣發(fā)現(xiàn)節(jié)點Lock3并不是最小的。

于是,Client3向排序僅比它靠前的節(jié)點Lock2注冊Watcher,用于監(jiān)聽Lock2節(jié)點是否存在。這意味著Client3同樣搶鎖失敗,進(jìn)入了等待狀態(tài)。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

這樣一來,Client1得到了鎖,Client2監(jiān)聽了Lock1,Client3監(jiān)聽了Lock2。這恰恰形成了一個等待隊列,很像是Java當(dāng)中ReentrantLock所依賴的

釋放鎖

釋放鎖分為兩種情況:

1.任務(wù)完成,客戶端顯示釋放

當(dāng)任務(wù)完成時,Client1會顯示調(diào)用刪除節(jié)點Lock1的指令。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

2.任務(wù)執(zhí)行過程中,客戶端崩潰

獲得鎖的Client1在任務(wù)執(zhí)行過程中,如果Duang的一聲崩潰,則會斷開與Zookeeper服務(wù)端的鏈接。根據(jù)臨時節(jié)點的特性,相關(guān)聯(lián)的節(jié)點Lock1會隨之自動刪除。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

由于Client2一直監(jiān)聽著Lock1的存在狀態(tài),當(dāng)Lock1節(jié)點被刪除,Client2會立刻收到通知。這時候Client2會再次查詢ParentLock下面的所有節(jié)點,確認(rèn)自己創(chuàng)建的節(jié)點Lock2是不是目前最小的節(jié)點。如果是最小,則Client2順理成章獲得了鎖。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

同理,如果Client2也因為任務(wù)完成或者節(jié)點崩潰而刪除了節(jié)點Lock2,那么Client3就會接到通知。

一文讓你讀懂分布式鎖的使用原理及實現(xiàn)方式

最終,Client3成功得到了鎖。

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

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

AI