Zookeeper 如何實(shí)現(xiàn)分布式鎖

學(xué)習(xí)完整課程請(qǐng)移步 互聯(lián)網(wǎng) Java 全棧工程師

本節(jié)視頻

什么是臨時(shí)順序節(jié)點(diǎn)?

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

Znode 分為四種類型:

持久節(jié)點(diǎn)(PERSISTENT)

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

持久節(jié)點(diǎn)順序節(jié)點(diǎn)(PERSISTENT_SEQUENTIAL)

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

臨時(shí)節(jié)點(diǎn)(EPHEMERAL)

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

臨時(shí)順序節(jié)點(diǎn)(EPHEMERAL_SEQUENTIAL)

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

Zookeeper 分布式鎖的原理

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

獲取鎖

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

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

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

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

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

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

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

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

這樣一來,Client1 得到了鎖,Client2 監(jiān)聽了 Lock1,Client3 監(jiān)聽了 Lock2。這恰恰形成了一個(gè)等待隊(duì)列,

釋放鎖

釋放鎖分為兩種情況:

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

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

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

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

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

同理,如果 Client2 也因?yàn)槿蝿?wù)完成或者節(jié)點(diǎn)崩潰而刪除了節(jié)點(diǎn) Lock2,那么 Client3 就會(huì)接到通知。

最終,Client3 成功得到了鎖。

Zookeeper 和 Redis 分布式鎖的比較

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。