您好,登錄后才能下訂單哦!
Zookeeper中分布式鎖的原理是什么,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
Zookeeper 的 ZNode 節點
在了解 Zookeeper 實現分布式鎖之前,首先,我們需要了解 Zookeeper 里面節點相關的知識。
Zookeeper 里面的節點可以分為兩大類,一種是臨時節點,一種是持久化節點。
臨時節點,指的是節點創建后,如果創建節點的客戶端和 Zookeeper 服務端的會話失效(例如斷開連接),那么節點就會被刪除。
持久化節點指的是節點創建后,即使創建節點的客戶端和 Zookeeper 服務端的會話失效(例如斷開連接),節點也不會被刪除,只有客戶端主動發起刪除節點的請求,節點才會被刪除。
另外還有一種節點叫做有序節點,這種節點在創建時會有一個序號,這個序號是自增的。有序節點既可以是有序臨時節點,也可以是有序持久化節點。
Zookeeper 中所有的數據都是通過節點來存儲的,它的目錄結構就像一個文件樹,如下圖。
Zookeeper結構
圖中的 locks、register、data 這幾個目錄自定義創建的,分別用來存儲不同業務的數據,例如 locks 用來存放分布式鎖相關的信息,register 用來存放注冊中心相關的數據。
現在我們要獲取一個分布式的所,那么假設這個鎖的 K 叫做 K1,那么現在有一個客戶端 a,然后去 JK 里面去創建一個分布式的,所創建 K1 這個分布式鎖,那么他就會在 nex 這個目錄下面創建一個叫做 K1 的文件夾,叫做 K1 的文件。現在我們要獲取一個分布式的所,那么假設這個鎖的 K 叫做 K1,那么現在有一個客戶端 a,然后去 JK 里面去創建一個分布式的,所創建 K1 這個分布式鎖,那么他就會在 nex 這個目錄下面創建一個叫做 K1 的文件夾,叫做 K1 的文件。
如何實現
采用 Zookeeper 實現分布式鎖,有兩種方案:1. 基于臨時節點實現;2. 基于臨時順序節點實現。下面以及介紹這種方案的實現原理。
首先,假設所有的分布式鎖都存儲在 locks 這個目錄中。
方案一:基于臨時節點實現(不推薦)
假設現在有客戶端 A、B、C 均來獲取同一把分布式鎖:Key1。
首先,客戶端 A 來獲取分布式鎖 Key1,那么它就會嘗試在 locks 這個目錄下去創建一個叫做 Key1 的 ZNode 節點。如果這個時候 locks 目錄里面沒有 Key1 這個 ZNode 節點,那么客戶端 A 就能成功創建 Key1 節點,這就表示客戶端 A 成功獲取到了 Key1 這把鎖鎖。
圖1
同時,客戶端 B 也來獲取 Key1 這把鎖。客戶端 B 也需要去 locks 這個目錄里面去創建 Key1 ZNode 節點,這個時候,由于 Key1 這個 ZNode 節點已經存在,所以客戶端 B 就會創建失敗。而創建失敗就表示客戶端 B 獲取鎖失敗,所以這個時候客戶端 B 就會向 Zookeeper 注冊自己的監聽器(Watcher),監聽 Key1 這個 ZNode 節點的變化(當 Key1 節點發生變化時,Zookeeper 會通知到客戶端 B)。
如果客戶端 A 和客戶端 B,是同時請求到 Zookeeper,那么 Zookeeper 它有一個機制,它會保證只會有其中一個客戶端能創建成功 Key1 這個 ZNode 節點。
圖2
同理,此時客戶端 C 來獲取 Key1 鎖時,也是無法獲取到鎖,也會把自己的 Watcher 注冊到 ZK 中,監聽 Key1 這個 ZNode 節點的變化。
當客戶端 A 處理完自己的業務邏輯之后,那么就會執行釋放鎖的操作。釋放鎖時,客戶端刪除 Key1 節點,如果節點刪除成功就表示鎖釋放成功。當 Key1 這個節點被刪除后,Zookeeper 就會通知所有監聽 Key1 這個節點的客戶端,也就是客戶端 B、C。
當客戶端 B 和 C 接到通知以后,知道 Key1 節點發生了變化,這個時候它們就會重新去請求 Zookeeper,嘗試在 locks 目錄下面創建 Key1 節點,這個時候也只會有一個客戶端能成功創建 Key1 節點。假如說是客戶端 B 創建成功了,那么就表示客戶端 B 成功獲取到了鎖.客戶端 C 獲取鎖失敗,那么就繼續去監聽 Key1 這個節點的變化。
圖3
為什么不推薦
以上就是基于臨時節點這個方案去實現 Zookeeper 分布式鎖,但是這個方案通常是不被推薦的。為什么呢?這是因為使用這個方案會存在一個很大的問題:羊群效應。
什么意思呢?
從上面的過程中我們可以看到,當客戶端 A 釋放鎖成功以后,Zookeeper 需要去通知所有監聽 Key1 這個節點的客戶端。上面我們的例子中只有客戶端 B 和客戶端 C,但是在實際應用中可能有成百上千個客戶端,甚至更多。Zookeeper 在這一瞬間需要發送成百上千個請求,首先這個效率顯然是不高的,另外當分布式鎖的競爭較為激烈時,極有可能在這一瞬間 Zookeeper 的網卡可能被撐爆。而且系統中可能并不僅僅存 Key1 這一把鎖,還會存在 Key2、Key3、Key4...,這些鎖也會存在競爭,Zookeeper 的壓力會更大。
在這個過程中,我們很明顯地能感覺到這是不合理的,因為獲取分布式鎖時肯定是只有其中一個客戶端能獲取到,那么當 Key1 這個節點被刪除以后,需要通知其他的客戶端來獲取鎖,這個時候我們有必要去通知所有的客戶端嗎?
顯然是沒有必要的,我們只需要通知其中一個客戶端就可以了。因此方案二出現了。
方案二:基于臨時順序節點實現(推薦)
基于臨時順序節點去實現分布式鎖時,就不是在 Linux 這個目錄下面創建 Key1 這個臨時節點了。而是先在 locks 這個目錄下面創建一個 Key1 目錄,然后在 Key1 目錄里面去創建臨時順序節點。
假設現在客戶端 a 來獲取分布式鎖 Key1,那么這個時候客戶端 A 就會在 Key1 這個目錄里面創建一個臨時順序節點,這個臨時順序節點的序號是 001。
然后客戶端 A 會判斷自己創建的這個臨時順序節點 001 在 Key1 這個目錄里面,它的序號是不是最小的?如果是最小的,那么就表示客戶端 A 獲取鎖成功。
接著客戶端 B 也來獲取 Key1 這個分布式鎖,它也會在 Key1 這個目錄下面去創建一個臨時順序節點,由于這個時候自增序號已經變為 002 了,因為之前已經創建過 001 了,所以客戶端 B 會創建 002 這個臨時順序節點。
圖4
同理,客戶端 B 也會判斷自己當前創建的臨時順序節點 002,是不是當前 Key1 目錄中序號最小的臨時節點,顯然不是,因為前面有一個 001 臨時順序節點,所以客戶端 B 這個時候是獲取鎖失敗。
當客戶端 B 獲取鎖失敗之后,它會把自己的監聽器注冊到 Zookeeper,它監聽的是它前面一個臨時順序節點,也就是 001 這個順序節點。
圖5
此時如果客戶端 C 也來獲取分布式鎖 Key1,這個時候它就會在 Key 目錄中創建臨時順序節點 003,同樣 003 也不是序號最小的臨時順序節點,所以客戶端 C 也獲取鎖失敗,接著它會去監聽 002 這個臨時順序節點。
當客戶端 A 處理完業務邏輯之后,它就會去釋放鎖。釋放鎖的操作就是去刪除 Key1 這個目錄下面客戶端 A 所創建的臨時順序節點,也就是刪除 001 這個臨時順序節點。當 001 這個順序節點被刪除以后,Zookeeper 就會去通知監聽 001 這個順序節點的所有客戶端,也就是通知客戶端 B。客戶端 B 接收到 Zookeeper 的通知之后,它就會去判斷我當前創建的臨時順序節點 002 是不是當前 Key1 這個目錄中序號最小的一個臨時順序節點。此時由于 001 這個順序節點已經不存在了,顯然 002 是最小的了,因此客戶端 B 就獲取鎖成功。
圖6
同樣當客戶端 B 釋放鎖之后,就會將 002 刪除,002 刪除以后,Zookeeper 會通知客戶端 C,客戶端 C 發現我當前創建的臨時順序節點 003 是 Key1 這個目錄里面最小的序號,所以客戶端 C 獲取鎖成功。
看完上述內容,你們掌握Zookeeper中分布式鎖的原理是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。