自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Zookeeper實(shí)現(xiàn)分布式鎖的原理

大數(shù)據(jù) 分布式
相信大部分面試都是說(shuō)用 Redis 去實(shí)現(xiàn)分布式鎖,用 Zookeeper 實(shí)現(xiàn)分布式鎖相對(duì)而言遇到的較少,最近在整理之前的面經(jīng)答案,因此特意寫(xiě)篇博客解釋一下。

[[384001]]

本文轉(zhuǎn)載自微信公眾號(hào)「菜鳥(niǎo)飛呀飛」,作者劉進(jìn)坤。轉(zhuǎn)載本文請(qǐng)聯(lián)系菜鳥(niǎo)飛呀飛公眾號(hào)。    

前言

在面字節(jié)跳動(dòng)時(shí),遇到了這道面試題:如何用 Zookeeper 實(shí)現(xiàn)分布式鎖?

相信大部分面試都是說(shuō)用 Redis 去實(shí)現(xiàn)分布式鎖,用 Zookeeper 實(shí)現(xiàn)分布式鎖相對(duì)而言遇到的較少,最近在整理之前的面經(jīng)答案,因此特意寫(xiě)篇博客解釋一下。

實(shí)現(xiàn)一把分布式鎖通常有很多方法,比較常見(jiàn)的有 redis 和 Zookeeper。相信大家對(duì) redis 實(shí)現(xiàn)分布式鎖已經(jīng)非常了解,今天介紹的是如何通過(guò) Zookeeper 去實(shí)現(xiàn)一把分布式鎖。

首先 Zookeeper 為什么能實(shí)現(xiàn)一把分布式鎖呢?這是因?yàn)樗幸粋€(gè)特性,就是多個(gè)線程去 Zookeeper 里面去創(chuàng)建同一個(gè)節(jié)點(diǎn)的時(shí)候,只會(huì)有一個(gè)線程去執(zhí)行成功。

Zookeeper 的 ZNode 節(jié)點(diǎn)

在了解 Zookeeper 實(shí)現(xiàn)分布式鎖之前,首先,我們需要了解 Zookeeper 里面節(jié)點(diǎn)相關(guān)的知識(shí)。

Zookeeper 里面的節(jié)點(diǎn)可以分為兩大類(lèi),一種是臨時(shí)節(jié)點(diǎn),一種是持久化節(jié)點(diǎn)。

臨時(shí)節(jié)點(diǎn),指的是節(jié)點(diǎn)創(chuàng)建后,如果創(chuàng)建節(jié)點(diǎn)的客戶(hù)端和 Zookeeper 服務(wù)端的會(huì)話失效(例如斷開(kāi)連接),那么節(jié)點(diǎn)就會(huì)被刪除。

持久化節(jié)點(diǎn)指的是節(jié)點(diǎn)創(chuàng)建后,即使創(chuàng)建節(jié)點(diǎn)的客戶(hù)端和 Zookeeper 服務(wù)端的會(huì)話失效(例如斷開(kāi)連接),節(jié)點(diǎn)也不會(huì)被刪除,只有客戶(hù)端主動(dòng)發(fā)起刪除節(jié)點(diǎn)的請(qǐng)求,節(jié)點(diǎn)才會(huì)被刪除。

另外還有一種節(jié)點(diǎn)叫做有序節(jié)點(diǎn),這種節(jié)點(diǎn)在創(chuàng)建時(shí)會(huì)有一個(gè)序號(hào),這個(gè)序號(hào)是自增的。有序節(jié)點(diǎn)既可以是有序臨時(shí)節(jié)點(diǎn),也可以是有序持久化節(jié)點(diǎn)。

Zookeeper 中所有的數(shù)據(jù)都是通過(guò)節(jié)點(diǎn)來(lái)存儲(chǔ)的,它的目錄結(jié)構(gòu)就像一個(gè)文件樹(shù),如下圖。

Zookeeper結(jié)構(gòu)

圖中的 locks、register、data 這幾個(gè)目錄自定義創(chuàng)建的,分別用來(lái)存儲(chǔ)不同業(yè)務(wù)的數(shù)據(jù),例如 locks 用來(lái)存放分布式鎖相關(guān)的信息,register 用來(lái)存放注冊(cè)中心相關(guān)的數(shù)據(jù)。

現(xiàn)在我們要獲取一個(gè)分布式的所,那么假設(shè)這個(gè)鎖的 K 叫做 K1,那么現(xiàn)在有一個(gè)客戶(hù)端 a,然后去 JK 里面去創(chuàng)建一個(gè)分布式的,所創(chuàng)建 K1 這個(gè)分布式鎖,那么他就會(huì)在 nex 這個(gè)目錄下面創(chuàng)建一個(gè)叫做 K1 的文件夾,叫做 K1 的文件?,F(xiàn)在我們要獲取一個(gè)分布式的所,那么假設(shè)這個(gè)鎖的 K 叫做 K1,那么現(xiàn)在有一個(gè)客戶(hù)端 a,然后去 JK 里面去創(chuàng)建一個(gè)分布式的,所創(chuàng)建 K1 這個(gè)分布式鎖,那么他就會(huì)在 nex 這個(gè)目錄下面創(chuàng)建一個(gè)叫做 K1 的文件夾,叫做 K1 的文件。

如何實(shí)現(xiàn)

采用 Zookeeper 實(shí)現(xiàn)分布式鎖,有兩種方案:1. 基于臨時(shí)節(jié)點(diǎn)實(shí)現(xiàn);2. 基于臨時(shí)順序節(jié)點(diǎn)實(shí)現(xiàn)。下面以及介紹這種方案的實(shí)現(xiàn)原理。

首先,假設(shè)所有的分布式鎖都存儲(chǔ)在 locks 這個(gè)目錄中。

方案一:基于臨時(shí)節(jié)點(diǎn)實(shí)現(xiàn)(不推薦)

假設(shè)現(xiàn)在有客戶(hù)端 A、B、C 均來(lái)獲取同一把分布式鎖:Key1。

首先,客戶(hù)端 A 來(lái)獲取分布式鎖 Key1,那么它就會(huì)嘗試在 locks 這個(gè)目錄下去創(chuàng)建一個(gè)叫做 Key1 的 ZNode 節(jié)點(diǎn)。如果這個(gè)時(shí)候 locks 目錄里面沒(méi)有 Key1 這個(gè) ZNode 節(jié)點(diǎn),那么客戶(hù)端 A 就能成功創(chuàng)建 Key1 節(jié)點(diǎn),這就表示客戶(hù)端 A 成功獲取到了 Key1 這把鎖鎖。

圖1

同時(shí),客戶(hù)端 B 也來(lái)獲取 Key1 這把鎖??蛻?hù)端 B 也需要去 locks 這個(gè)目錄里面去創(chuàng)建 Key1 ZNode 節(jié)點(diǎn),這個(gè)時(shí)候,由于 Key1 這個(gè) ZNode 節(jié)點(diǎn)已經(jīng)存在,所以客戶(hù)端 B 就會(huì)創(chuàng)建失敗。而創(chuàng)建失敗就表示客戶(hù)端 B 獲取鎖失敗,所以這個(gè)時(shí)候客戶(hù)端 B 就會(huì)向 Zookeeper 注冊(cè)自己的監(jiān)聽(tīng)器(Watcher),監(jiān)聽(tīng) Key1 這個(gè) ZNode 節(jié)點(diǎn)的變化(當(dāng) Key1 節(jié)點(diǎn)發(fā)生變化時(shí),Zookeeper 會(huì)通知到客戶(hù)端 B)。

如果客戶(hù)端 A 和客戶(hù)端 B,是同時(shí)請(qǐng)求到 Zookeeper,那么 Zookeeper 它有一個(gè)機(jī)制,它會(huì)保證只會(huì)有其中一個(gè)客戶(hù)端能創(chuàng)建成功 Key1 這個(gè) ZNode 節(jié)點(diǎn)。

圖2

同理,此時(shí)客戶(hù)端 C 來(lái)獲取 Key1 鎖時(shí),也是無(wú)法獲取到鎖,也會(huì)把自己的 Watcher 注冊(cè)到 ZK 中,監(jiān)聽(tīng) Key1 這個(gè) ZNode 節(jié)點(diǎn)的變化。

當(dāng)客戶(hù)端 A 處理完自己的業(yè)務(wù)邏輯之后,那么就會(huì)執(zhí)行釋放鎖的操作。釋放鎖時(shí),客戶(hù)端刪除 Key1 節(jié)點(diǎn),如果節(jié)點(diǎn)刪除成功就表示鎖釋放成功。當(dāng) Key1 這個(gè)節(jié)點(diǎn)被刪除后,Zookeeper 就會(huì)通知所有監(jiān)聽(tīng) Key1 這個(gè)節(jié)點(diǎn)的客戶(hù)端,也就是客戶(hù)端 B、C。

當(dāng)客戶(hù)端 B 和 C 接到通知以后,知道 Key1 節(jié)點(diǎn)發(fā)生了變化,這個(gè)時(shí)候它們就會(huì)重新去請(qǐng)求 Zookeeper,嘗試在 locks 目錄下面創(chuàng)建 Key1 節(jié)點(diǎn),這個(gè)時(shí)候也只會(huì)有一個(gè)客戶(hù)端能成功創(chuàng)建 Key1 節(jié)點(diǎn)。假如說(shuō)是客戶(hù)端 B 創(chuàng)建成功了,那么就表示客戶(hù)端 B 成功獲取到了鎖.客戶(hù)端 C 獲取鎖失敗,那么就繼續(xù)去監(jiān)聽(tīng) Key1 這個(gè)節(jié)點(diǎn)的變化。

圖3

為什么不推薦

以上就是基于臨時(shí)節(jié)點(diǎn)這個(gè)方案去實(shí)現(xiàn) Zookeeper 分布式鎖,但是這個(gè)方案通常是不被推薦的。為什么呢?這是因?yàn)槭褂眠@個(gè)方案會(huì)存在一個(gè)很大的問(wèn)題:羊群效應(yīng)。

什么意思呢?

從上面的過(guò)程中我們可以看到,當(dāng)客戶(hù)端 A 釋放鎖成功以后,Zookeeper 需要去通知所有監(jiān)聽(tīng) Key1 這個(gè)節(jié)點(diǎn)的客戶(hù)端。上面我們的例子中只有客戶(hù)端 B 和客戶(hù)端 C,但是在實(shí)際應(yīng)用中可能有成百上千個(gè)客戶(hù)端,甚至更多。Zookeeper 在這一瞬間需要發(fā)送成百上千個(gè)請(qǐng)求,首先這個(gè)效率顯然是不高的,另外當(dāng)分布式鎖的競(jìng)爭(zhēng)較為激烈時(shí),極有可能在這一瞬間 Zookeeper 的網(wǎng)卡可能被撐爆。而且系統(tǒng)中可能并不僅僅存 Key1 這一把鎖,還會(huì)存在 Key2、Key3、Key4...,這些鎖也會(huì)存在競(jìng)爭(zhēng),Zookeeper 的壓力會(huì)更大。

在這個(gè)過(guò)程中,我們很明顯地能感覺(jué)到這是不合理的,因?yàn)楂@取分布式鎖時(shí)肯定是只有其中一個(gè)客戶(hù)端能獲取到,那么當(dāng) Key1 這個(gè)節(jié)點(diǎn)被刪除以后,需要通知其他的客戶(hù)端來(lái)獲取鎖,這個(gè)時(shí)候我們有必要去通知所有的客戶(hù)端嗎?

顯然是沒(méi)有必要的,我們只需要通知其中一個(gè)客戶(hù)端就可以了。因此方案二出現(xiàn)了。

方案二:基于臨時(shí)順序節(jié)點(diǎn)實(shí)現(xiàn)(推薦)

基于臨時(shí)順序節(jié)點(diǎn)去實(shí)現(xiàn)分布式鎖時(shí),就不是在 Linux 這個(gè)目錄下面創(chuàng)建 Key1 這個(gè)臨時(shí)節(jié)點(diǎn)了。而是先在 locks 這個(gè)目錄下面創(chuàng)建一個(gè) Key1 目錄,然后在 Key1 目錄里面去創(chuàng)建臨時(shí)順序節(jié)點(diǎn)。

假設(shè)現(xiàn)在客戶(hù)端 a 來(lái)獲取分布式鎖 Key1,那么這個(gè)時(shí)候客戶(hù)端 A 就會(huì)在 Key1 這個(gè)目錄里面創(chuàng)建一個(gè)臨時(shí)順序節(jié)點(diǎn),這個(gè)臨時(shí)順序節(jié)點(diǎn)的序號(hào)是 001。

然后客戶(hù)端 A 會(huì)判斷自己創(chuàng)建的這個(gè)臨時(shí)順序節(jié)點(diǎn) 001 在 Key1 這個(gè)目錄里面,它的序號(hào)是不是最小的?如果是最小的,那么就表示客戶(hù)端 A 獲取鎖成功。

接著客戶(hù)端 B 也來(lái)獲取 Key1 這個(gè)分布式鎖,它也會(huì)在 Key1 這個(gè)目錄下面去創(chuàng)建一個(gè)臨時(shí)順序節(jié)點(diǎn),由于這個(gè)時(shí)候自增序號(hào)已經(jīng)變?yōu)?002 了,因?yàn)橹耙呀?jīng)創(chuàng)建過(guò) 001 了,所以客戶(hù)端 B 會(huì)創(chuàng)建 002 這個(gè)臨時(shí)順序節(jié)點(diǎn)。

圖4

同理,客戶(hù)端 B 也會(huì)判斷自己當(dāng)前創(chuàng)建的臨時(shí)順序節(jié)點(diǎn) 002,是不是當(dāng)前 Key1 目錄中序號(hào)最小的臨時(shí)節(jié)點(diǎn),顯然不是,因?yàn)榍懊嬗幸粋€(gè) 001 臨時(shí)順序節(jié)點(diǎn),所以客戶(hù)端 B 這個(gè)時(shí)候是獲取鎖失敗。

當(dāng)客戶(hù)端 B 獲取鎖失敗之后,它會(huì)把自己的監(jiān)聽(tīng)器注冊(cè)到 Zookeeper,它監(jiān)聽(tīng)的是它前面一個(gè)臨時(shí)順序節(jié)點(diǎn),也就是 001 這個(gè)順序節(jié)點(diǎn)。

圖5

此時(shí)如果客戶(hù)端 C 也來(lái)獲取分布式鎖 Key1,這個(gè)時(shí)候它就會(huì)在 Key 目錄中創(chuàng)建臨時(shí)順序節(jié)點(diǎn) 003,同樣 003 也不是序號(hào)最小的臨時(shí)順序節(jié)點(diǎn),所以客戶(hù)端 C 也獲取鎖失敗,接著它會(huì)去監(jiān)聽(tīng) 002 這個(gè)臨時(shí)順序節(jié)點(diǎn)。

當(dāng)客戶(hù)端 A 處理完業(yè)務(wù)邏輯之后,它就會(huì)去釋放鎖。釋放鎖的操作就是去刪除 Key1 這個(gè)目錄下面客戶(hù)端 A 所創(chuàng)建的臨時(shí)順序節(jié)點(diǎn),也就是刪除 001 這個(gè)臨時(shí)順序節(jié)點(diǎn)。當(dāng) 001 這個(gè)順序節(jié)點(diǎn)被刪除以后,Zookeeper 就會(huì)去通知監(jiān)聽(tīng) 001 這個(gè)順序節(jié)點(diǎn)的所有客戶(hù)端,也就是通知客戶(hù)端 B。客戶(hù)端 B 接收到 Zookeeper 的通知之后,它就會(huì)去判斷我當(dāng)前創(chuàng)建的臨時(shí)順序節(jié)點(diǎn) 002 是不是當(dāng)前 Key1 這個(gè)目錄中序號(hào)最小的一個(gè)臨時(shí)順序節(jié)點(diǎn)。此時(shí)由于 001 這個(gè)順序節(jié)點(diǎn)已經(jīng)不存在了,顯然 002 是最小的了,因此客戶(hù)端 B 就獲取鎖成功。

圖6

同樣當(dāng)客戶(hù)端 B 釋放鎖之后,就會(huì)將 002 刪除,002 刪除以后,Zookeeper 會(huì)通知客戶(hù)端 C,客戶(hù)端 C 發(fā)現(xiàn)我當(dāng)前創(chuàng)建的臨時(shí)順序節(jié)點(diǎn) 003 是 Key1 這個(gè)目錄里面最小的序號(hào),所以客戶(hù)端 C 獲取鎖成功。

思考

當(dāng)客戶(hù)端 A 獲取鎖成功以后,長(zhǎng)時(shí)間不釋放鎖,或者說(shuō)客戶(hù)端 A 所在的機(jī)器宕機(jī),或者客戶(hù)端 A 所在的機(jī)器出現(xiàn)網(wǎng)絡(luò)故障,這個(gè)時(shí)候會(huì)出現(xiàn)什么狀況?

當(dāng)客戶(hù)端 A 所在的機(jī)器出現(xiàn)宕機(jī),或者出現(xiàn)網(wǎng)絡(luò)故障后,長(zhǎng)時(shí)間不和 Zookeeper 通信的時(shí)候,客戶(hù)端 A 和 Zookeeper 之間創(chuàng)建的 Session 就會(huì)失效,當(dāng)這個(gè) Session 失效以后,Zookeeper 會(huì)將客戶(hù)端 A 所創(chuàng)建的臨時(shí)順序節(jié)點(diǎn)給直接刪除,這個(gè)時(shí)候其他的客戶(hù)端就能正常獲取鎖了。

 

責(zé)任編輯:武曉燕 來(lái)源: 菜鳥(niǎo)飛呀飛
相關(guān)推薦

2021-10-25 10:21:59

ZK分布式鎖ZooKeeper

2024-11-28 15:11:28

2022-07-25 06:44:19

ZooKeeper分布式鎖

2022-10-27 10:44:14

分布式Zookeeper

2017-10-24 11:28:23

Zookeeper分布式鎖架構(gòu)

2021-07-16 07:57:34

ZooKeeperCurator源碼

2015-05-18 09:59:48

ZooKeeper分布式計(jì)算Hadoop

2020-11-16 12:55:41

Redis分布式鎖Zookeeper

2019-07-16 09:22:10

RedisZookeeper分布式鎖

2020-05-12 14:03:51

RedisZooKeeper分布式鎖

2019-06-19 15:40:06

分布式鎖RedisJava

2019-02-26 09:51:52

分布式鎖RedisZookeeper

2017-01-16 14:13:37

分布式數(shù)據(jù)庫(kù)

2018-04-03 16:24:34

分布式方式

2017-04-13 10:51:09

Consul分布式

2022-04-08 08:27:08

分布式鎖系統(tǒng)

2022-01-06 10:58:07

Redis數(shù)據(jù)分布式鎖

2023-08-21 19:10:34

Redis分布式

2021-07-08 09:21:17

ZooKeeper分布式鎖 Curator

2025-03-25 10:29:52

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)