tft每日頭條

 > 生活

 > zookeeper分布鎖原理

zookeeper分布鎖原理

生活 更新时间:2024-09-02 09:20:59

本篇分享文章,是對分布式鎖服務的階段性總結,大家可以去前面翻看相關文章,希望能給讀者帶來收獲。

今天的目錄如下:

  1. 分布式鎖功能回顧

  2. 分布式鎖實現思路

  3. Zookeeper的簡單介紹

  4. 實現分布式鎖服務

1. 分布式鎖功能回顧

前面我們已經分析過分布式鎖服務的功能,大家有興趣去看看《分布式鎖服務的思考》,總結一下功能點:

  • 鎖定服務的接口或資源,防止多個線程同時執行

  • 分布式鎖服務本身需要具有高可用性

  • 可靠的獲得鎖以及釋放鎖

  • 鎖具有超時機制,不會發生死鎖,或者具有死鎖檢測機制

  • 同一個線程可以重複鎖定資源,分布式鎖具有可重入的特點

  • 客戶端獲得鎖具有超時機制或重試機制。

2. 分布式鎖實現思路

分布式鎖服務實現方式有多種,其中比較流行的分布式鎖實現有如下:

  • 結合數據庫事務實現,隻要數據庫架構高可用,基本上能滿足大多數的鎖服務要求。但是需要重點考慮線程阻塞,且鎖沒有超時過期的特性。

  • 使用Redis實現。注意,我在前面的文章《Redis紅鎖不适合分布式鎖服務》,Redis紅鎖并不适合做分布式鎖服務,原因也分析了:5個節點太重,且不能解決線程的阻塞導緻多個線程持有鎖。還不如直接使用單機版本的setnx lua(delete key) 這種方式來的幹脆。(不管單機版的分布式鎖還是紅鎖,都具有線程阻塞問題,詳細說明見前面的兩篇文章)

  • zookeeper實現分布式鎖,今天我們重點說明zookeeper以及實現分布式鎖。

數據庫利用事務實現分布式鎖服務比較簡單,不在這裡深入了。

服務間數據同步以及選舉

比較重要的特點:

  1. 服務之間相互通信,在内存中維持了服務的狀态圖以及事務日志。

  2. 快照存儲在硬盤中,多數可用,服務就可用。

  3. 因為存儲使用内存,速度快,官網解釋10比1的讀寫性能最佳。

  4. 事務順序數字标記,具有順序操作特性,原子性操作。

  5. 有層級命名空間,很像是分布式文件系統。唯一的區别就是每一個命名空間下的node節點以及它的children節點都可以關聯數據。這就像電腦的文件系統,一個文件即存儲數據,也可以作為一個目錄。

  6. 節點分為永久節點和臨時節點,臨時節點生命同client的session一緻,臨時節點不允許有孩子。

  7. watch機制,監聽節點的變化,一旦觸發通知,watch就消失了,若想繼續監聽則必須重新set watch。

zookeeper分布鎖原理(Zookeeper分布式鎖服務及總結)1

數據節點模型

zookeeper常用的場景:

  • 統一命名空間

    dubbo服務提供者把自己的服務Url地址注冊到,如/dubbo/${serviceName}/providers/目錄下,完成服務的發布操作。dubbo服務消費者啟動後,訂閱/dubbo/${serviceName}/providers目錄下的Url地址,并向/dubbo/${serviceName}/consumer/中寫下自己的Url。所有的地址都是臨時的節點,這樣服務的提供者和消費者都能感知到資源的變化,dubbo可以監控/dobbo/${serviceName}/下面的所有服務者和消費者的信息。

  • 配置管理

    利用zk實現配置中心,在應用時首先要封裝一套應用層的API方便業務邏輯使用,如果我們的服務比較少使用文件就可以滿足,反之需要使用配置中心管理服務,例如實現服務降級開關。除了zookeeper,還有Etcd3、consul等,這裡可告訴大家,zk實現配置管理比較重,管理複雜,不建議使用了。

  • 分布式集群管理

    zookeeper很早就出現了,是大數據hadoop生态圈的協調管理者。zk集群選舉機制采用了zab協議,保證了分布式數據的一緻性,并實現leader選舉。

  • 分布式鎖服務(強一緻性)

    保持資源獨占和嚴格的控制時序。使用一緻性保證,可以很簡單的構建一些高級的用法:客戶端barriers、queues、以及可撤銷的讀寫鎖。

4. 實現分布式鎖服務

使用zk實現分布式鎖很簡單,首先我們看下client獲得鎖的步驟:

  1. 參與鎖競争的client調用create()方法創建一個路徑比如:‘locknode/lock-0000001’的有序臨時節點。

  2. 在locknode節點上調用getChildren(),獲得有序節點列表,為防止羊群效應,這裡不可設置watch。

  3. 如果client在第一步創建的是列表中最小的後綴節點,那麼該client獲得鎖并返回。

  4. 如果創建的節點序列,不是列表中最小的節點,則client調用exists()監聽該節點的上一個節點。

  5. 返回null,重新返回step2執行。否則,等待通知獲得鎖的擁有權。

釋放鎖的流程很簡單:隻需要删除自己創建的節點。zk實現的分布式鎖沒有輪詢,所以等待通知就好。

下面用代碼說明上述過程:

1.在目錄下創建臨時有序節點的過程

zookeeper分布鎖原理(Zookeeper分布式鎖服務及總結)2

創建臨時節點,注意失敗重試

2.創建目錄之後,可以直接獲得臨時節點名稱。這裡看下demo通過session獲得節點的方法

zookeeper分布鎖原理(Zookeeper分布式鎖服務及總結)3

通過session前綴得到臨時節點名字

zookeeper分布鎖原理(Zookeeper分布式鎖服務及總結)4

封裝的對象

為了方便臨時節點的表示,demo給出一個封裝對象:ZNodeName。實現compare方法比較大小,方便排序

3.獲取lock(dir)目錄下的所有children,封裝ZNodeName對象并放入Set中

zookeeper分布鎖原理(Zookeeper分布式鎖服務及總結)5

獲取dir目錄下的所有臨時節點,放入Set中

4.比較當前client是否是最小的節點

lessThanMe.isEmpty() //表示當前session創建的節點具有最小的suffix

zookeeper分布鎖原理(Zookeeper分布式鎖服務及總結)6

獲得鎖返回成功

5.當前節點并非最小值,就監聽當前臨時節點的上一個臨時節點。例如當前節點是003,那麼就監聽002。

zookeeper分布鎖原理(Zookeeper分布式鎖服務及總結)7

監聽上一個節點的變化

等待上一個節點的釋放觸發LockWatcher,再去執行一遍獲得鎖的邏輯。

如果上一個節點不存在,本次獲得鎖失敗。

zookeeper分布鎖原理(Zookeeper分布式鎖服務及總結)8

LockWatcher的邏輯

以上代碼呢,大家隻要能看懂大概zk的實現方式即可,為什麼隻是了解呢?

  • 首先zookeeper開發比較重,就是不方便。例如,簡單的創建zk對象,就需要阻塞等待通知。

  • 另外,我們在應用中可直接使用apache封裝好的工具curator就可以了,使用簡單,學習成本低。

    • acquire

    • release

5. 總結
  • 在分布式應用中,需要防止并發訪問資源造成數據不一緻,需可重入分布式鎖。

  • 常用的分布式鎖實現。mysql默認Repeatable Read事務隔離以及Redis setnx lua delete。

  • 簡單介紹zk,了解即可,不需要深入了。

  • 代碼介紹原理,了解接即可,因為直接使用curator更方便

希望本文能給大家帶來收獲,如果有疑問或者覺得表述不正确,可在評論中指出。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved