1. 程式人生 > >zookeeper 分散式鎖種類以及優缺點

zookeeper 分散式鎖種類以及優缺點

zookeeper 分散式鎖原理:

1 大家也許都很熟悉了多個執行緒或者多個程序間的共享鎖的實現方式了,但是在分散式場景中我們會面臨多個Server之間的鎖的問題,實現的複雜度比較高。利用基於google chubby原理開發的開源的zookeeper,可以使得這個問題變得簡單很多。下面介紹幾種可能的實現方式,並且對比每種實現方式的優缺點。

1. 利用節點名稱的唯一性來實現共享鎖

ZooKeeper抽象出來的節點結構是一個和unix檔案系統類似的小型的樹狀的目錄結構。ZooKeeper機制規定:同一個目錄下只能有一個唯一的檔名。例如:我們在Zookeeper目錄/test目錄下建立,兩個客戶端建立一個名為Lock節點,只有一個能夠成功。

演算法思路: 利用名稱唯一性,加鎖操作時,只需要所有客戶端一起建立/test/Lock節點,只有一個建立成功,成功者獲得鎖。解鎖時,只需刪除/test/Lock節點,其餘客戶端再次進入競爭建立節點,直到所有客戶端都獲得鎖。

基於以上機制,利用節點名稱唯一性機制的共享鎖演算法流程如圖所示:


該共享鎖實現很符合我們通常多個執行緒去競爭鎖的概念,利用節點名稱唯一性的做法簡明、可靠。

由上述演算法容易看出,由於客戶端會同時收到/test/Lock被刪除的通知,重新進入競爭建立節點,故存在"驚群現象"。

使用該方法進行測試鎖的效能列表如下:



總結 這種方案的正確性和可靠性是ZooKeeper機制保證的,實現簡單。缺點是會產生“驚群”效應,假如許多客戶端在等待一把鎖,當鎖釋放時候所有客戶端都被喚醒,僅僅有一個客戶端得到鎖。

2. 利用臨時順序節點實現共享鎖的一般做法

首先介紹一下,Zookeeper中有一種節點叫做順序節點,故名思議,假如我們在/lock/目錄下建立節3個點,ZooKeeper叢集會按照提起建立的順序來建立節點,節點分別為/lock/0000000001、/lock/0000000002、/lock/0000000003。

ZooKeeper中還有一種名為臨時節點的節點,臨時節點由某個客戶端建立,當客戶端與ZooKeeper叢集斷開連線,則開節點自動被刪除。

利用上面這兩個特性,我們來看下獲取實現分散式鎖的基本邏輯:

  • 客戶端呼叫create()方法建立名為“locknode/guid-lock-”的節點,需要注意的是,這裡節點的建立型別需要設定為EPHEMERAL_SEQUENTIAL。
  • 客戶端呼叫getChildren(“locknode”)方法來獲取所有已經建立的子節點,同時在這個節點上註冊上子節點變更通知的Watcher。
  • 客戶端獲取到所有子節點path之後,如果發現自己在步驟1中建立的節點是所有節點中序號最小的,那麼就認為這個客戶端獲得了鎖。
  • 如果在步驟3中發現自己並非是所有子節點中最小的,說明自己還沒有獲取到鎖,就開始等待,直到下次子節點變更通知的時候,再進行子節點的獲取,判斷是否獲取鎖。

釋放鎖的過程相對比較簡單,就是刪除自己建立的那個子節點即可。

上面這個分散式鎖的實現中,大體能夠滿足了一般的分散式叢集競爭鎖的需求。這裡說的一般性場景是指叢集規模不大,一般在10臺機器以內。

不過,細想上面的實現邏輯,我們很容易會發現一個問題,步驟4,“即獲取所有的子點,判斷自己建立的節點是否已經是序號最小的節點”,這個過程,在整個分散式鎖的競爭過程中,大量重複執行,並且絕大多數的執行結果都是判斷出自己並非是序號最小的節點,從而繼續等待下一次通知——這個顯然看起來不怎麼科學。客戶端無端的接受到過多的和自己不相關的事件通知,這如果在叢集規模大的時候,會對Server造成很大的效能影響,並且如果一旦同一時間有多個節點的客戶端斷開連線,這個時候,伺服器就會像其餘客戶端傳送大量的事件通知——這就是所謂的驚群效應。而這個問題的根源在於,沒有找準客戶端真正的關注點。

我們再來回顧一下上面的分散式鎖競爭過程,它的核心邏輯在於:判斷自己是否是所有節點中序號最小的。於是,很容易可以聯想的到的是,每個節點的建立者只需要關注比自己序號小的那個節點。

3. 利用臨時順序節點實現共享鎖的改進實現

下面是改進後的分散式鎖實現,和之前的實現方式唯一不同之處在於,這裡設計成每個鎖競爭者,只需要關注”locknode”節點下序號比自己小的那個節點是否存在即可。

演算法思路:對於加鎖操作,可以讓所有客戶端都去/lock目錄下建立臨時順序節點,如果建立的客戶端發現自身建立節點序列號是/lock/目錄下最小的節點,則獲得鎖。否則,監視比自己建立節點的序列號小的節點(比自己建立的節點小的最大節點),進入等待。

對於解鎖操作,只需要將自身建立的節點刪除即可。

具體演算法流程如下圖所示:


使用上述演算法進行測試的的結果如下表所示:


該演算法只監控比自身建立節點序列號小(比自己小的最大的節點)的節點,在當前獲得鎖的節點釋放鎖的時候沒有“驚群”。

總結 利用臨時順序節點來實現分散式鎖機制其實就是一種按照建立順序排隊的實現。這種方案效率高,避免了“驚群”效應,多個客戶端共同等待鎖,當鎖釋放時只有一個客戶端會被喚醒。

4. 使用menagerie

其實就是對方案3的一個封裝,不用自己寫程式碼了。直接拿來用就可以了。

menagerie基於Zookeeper實現了Java.util.concurrent包的一個分散式版本。這個封裝是更大粒度上對各種分散式一致性使用場景的抽象。其中最基礎和常用的是一個分散式鎖的實現: org.menagerie.locks.ReentrantZkLock,通過ZooKeeper的全域性有序的特性和EPHEMERAL_SEQUENTIAL型別znode的支援,實現了分散式鎖。具體做法是:不同的client上每個試圖獲得鎖的執行緒,都在相同的basepath下面建立一個EPHEMERAL_SEQUENTIAL的node。EPHEMERAL表示要建立的是臨時znode,建立連線斷開時會自動刪除; SEQUENTIAL表示要自動在傳入的path後面綴上一個自增的全域性唯一字尾,作為最終的path。因此對不同的請求ZK會生成不同的字尾,並分別返回帶了各自後綴的path給各個請求。因為ZK全域性有序的特性,不管client請求怎樣先後到達,在ZKServer端都會最終排好一個順序,因此自增字尾最小的那個子節點,就對應第一個到達ZK的有效請求。然後client讀取basepath下的所有子節點和ZK返回給自己的path進行比較,當發現自己建立的sequential node的字尾序號排在第一個時,就認為自己獲得了鎖;否則的話,就認為自己沒有獲得鎖。這時肯定是有其他併發的並且是沒有斷開的client/執行緒先建立了node。

相關推薦

zookeeper 分散式種類以及優缺點

zookeeper 分散式鎖原理:1 大家也許都很熟悉了多個執行緒或者多個程序間的共享鎖的實現方式了,但是在分散式場景中我們會面臨多個Server之間的鎖的問題,實現的複雜度比較高。利用基於google chubby原理開發的開源的zookeeper,可以使得這個問題變得簡單

JAVA中的各種以及最優的zookeeper分散式解決方案

一、鎖出現的原因-執行緒或者程序競爭資源當有一個或者多個執行緒或者程序進行操作時,其他執行緒或者程序都不可以對這個資源進行操作,直到該執行緒或者程序完成操作,其他執行緒或者程序才能對該資源進行操作,而其他執行緒或程序都處於等待狀態。二、執行緒同步的方式和機制1、解決資源競爭問

分散式快取重建併發衝突問題以及zookeeper分散式解決方案(7)

分散式重建快取的併發衝突問題 重建快取:比如我們這裡,資料在所有的快取中都不存在了(LRU演算法弄掉了),就需要重新查詢資料寫入快取,重建快取 分散式的重建快取,在不同的機器上,不同的服務例項中,去做上面的事情,就會出現多個機器分散式重建去讀取相同的資料,然

Zookeeper分散式和佇列

1.分散式鎖 分散式鎖,這個主要得益於ZooKeeper為我們保證了資料的強一致性。鎖服務可以分為兩類,一個是保持獨佔,另一個是控制時序。 所謂保持獨佔,就是所有試圖來獲取這個鎖的客戶端,最終只有一個可以成功獲得這把鎖。通常的做法是把zk上的一個znode看作是一把鎖,通過 create z

ZooKeeper - 分散式

 ZooKeeper實現分散式鎖的優點:ZK可以建立持久節點、臨時節點和順序節點。臨時節點在會話結束之後,自動被刪除。即使發生宕機,只要超出心跳時間,就會斷開會話,從而刪除臨時節點,不會造成死鎖的現象。  指定競爭的資源,在ZK下生成持久節點。 在

七張圖徹底講清楚ZooKeeper分散式的實現原理【石杉的架構筆記】

歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100) 週一至週五早8點半!精品技術文章準時送上! 一、寫在前面 之前寫過一篇文章(《拜託,面試請不要再問我Redis分散式鎖的實現原理》),給大家說了一下Redisson這個開源框架是如何實現Redis分散式鎖原理的,這篇文章再給大家聊一下ZooKe

zooKeeper分散式的實現原理

ZooKeeper分散式鎖機制 接下來我們一起來看看,多客戶端獲取及釋放zk分散式鎖的整個流程及背後的原理。 首先大家看看下面的圖,如果現在有兩個客戶端一起要爭搶zk上的一把分散式鎖,會是個什麼場景? 如果大家對zk還不太瞭解的話,建議先自行百度一下,簡單瞭解點基本概念,比

ZooKeeper分散式簡單實踐 利用Redis實現分散式

寫在最前面 前幾周寫了篇 利用Redis實現分散式鎖 ,今天簡單總結下ZooKeeper實現分散式鎖的過程。其實生產上我只用過Redis或者資料庫的方式,之前還真沒了解過ZooKeeper怎麼實現分散式鎖。這周簡單寫了個小Demo,更堅定了我繼續使用Redis的信心了。 ZooKeep

ZooKeeper分散式簡單實踐

ZooKeeper分散式鎖的實現原理 在分散式解決方案中,Zookeeper是一個分散式協調工具。當多個JVM客戶端,同時在ZooKeeper上建立相同的一個臨時節點,因為臨時節點路徑是保證唯一,只要誰能夠建立節點成功,誰就能夠獲取到鎖。沒有建立成功節點,就會進行等待,當釋放鎖的時候,採用事件通知給客

zookeeper 分散式

推薦: 1.  Curator  實現  <dependency> <groupId>org.apache.curator</groupId> <artifa

淺談ZooKeeper分散式(來自LJ)

目前的應用系統,大部分都是分散式部署的,分散式應用中的資料一致性問題是每個系統都要面臨的問題,分散式的CAP理論告訴我們“一個分散式系統不可能同時滿足一致性(C:Consistency)、可用性(A:Availability)和分割槽容錯性(P:Partition toler

Zookeeper分散式的使用

由於公司引入了dubbo+zookeeper框架,裡面不可避免的引入的zookeeper分散式鎖,所以自己大致瞭解了一下。由於是自己研究,有不正確的地方還請大佬批評指正。 首先先介紹一下自己對zookeeper分散式鎖的理解,之後會引入一版別人的感覺比較好的描述給大家 1

zookeeper-分散式的程式碼實現-【每日五分鐘搞定大資料】

本文涉及到幾個zookeeper簡單的知識點,永久節點、有序節點、watch機制。比較基礎,熟悉的就別看了跳過這篇吧 每個執行緒在/locks節點下建立一個臨時有序節點test_lock_0000000040 獲得/locks節點下所有子節點A、B、C,排序獲得最小值 若當前節點B為最小值則獲得鎖,執

zookeeper學習系列(五)zookeeper分散式機制

大家也許都很熟悉了多個執行緒或者多個程序間的共享鎖的實現方式了,但是在分散式場景中我們會面臨多個Server之間的鎖的問題,實現的複雜度比較高。利用基於google chubby原理開發的開源的zookeeper,可以使得這個問題變得簡單很多。下面介紹幾種可能的實現方式

CSDN站內最全的zookeeper分散式的講解

1 場景描述 在分散式應用, 往往存在多個程序提供同一服務. 這些程序有可能在相同的機器上, 也有可能分佈在不同的機器上. 如果這些程序共享了一些資源, 可能就需要分散式鎖來鎖定對這些資源的訪問。 2 思路 程序需要訪問共享資料時, 就在"/locks"節點下建立一個sequence型別

Zookeeper】程式設計實戰之Zookeeper分散式實現秒殺

1. Zookeeper簡述    我們要了解一樣技術,首先應該要到它的官網,因為官網的資訊一般都是最準確的,如下圖是Zookeeper官網對它的介紹。    從官網的介紹中,可以總結出,Zookeeper是一個集中式服務,它能夠實現高度可靠的分散式協調,可用於開發和維護開源

使用Java程式碼實現zookeeper分散式

產生問題 例:在分散式(叢集)環境下,每臺JVM不能實現同步,比如將一個專案部署到多臺tomcat伺服器,那麼用多臺JVM在使用時間戳生成唯一的訂單號時,會出現訂單號重複問題。 解決辦法

經過線上實戰的redis 分散式zookeeper分散式區別

經過線上實戰的redis 分散式鎖程式碼。     能用,但是效能較差。 已考慮:     1.只能被擁有鎖的執行緒解鎖     2. 設定節點和超時時間用同一個key  未考慮:  1. 不能重入  2. 沒有本地鎖,併發效能會比較差,不使用用在併發爭鎖較多的場景下。本

Zookeeper分散式的簡單實現

package org.kelab.vf.zk.lock.impl; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.zookeeper.*; im

ZooKeeper分散式與程式碼實現

1.zk的核心機制之一:分散式鎖        分散式鎖能夠在一組程序之間提供互斥機制,使得在任何時候只有一個程序可以持有鎖。分散式鎖可以用於在大型分散式系統中實現領導者選舉,在任何時間點,持有鎖的那