ZooKeeper 實現分布式鎖

1. 分布式鎖概述

在分布式系統中,為了保證共享資源在并發訪問下的數據一致性,需要引入分布式鎖。分布式鎖是一種在分布式環境下控制多個進程對共享資源進行互斥訪問的機制。它與單機環境下的鎖(如Java中的synchronizedLock)不同,單機鎖只能解決同一JVM內部的并發問題,而分布式鎖則需要解決跨JVM、跨機器的并發問題。

2. ZooKeeper實現分布式鎖的原理

ZooKeeper是一個分布式協調服務,它提供了數據一致性、高可用性等特性,非常適合用于實現分布式鎖。ZooKeeper實現分布式鎖主要利用了其以下特性:

2.1 臨時順序節點(EPHEMERAL_SEQUENTIAL)

ZooKeeper的節點可以設置為臨時(Ephemeral)和順序(Sequential)類型。臨時節點會在創建該節點的客戶端會話結束時自動刪除。順序節點則會在創建時自動在節點名稱后面附加一個單調遞增的數字。

利用這兩個特性,可以實現分布式鎖的“排隊”機制:

  1. 創建鎖節點:客戶端在ZooKeeper上創建一個持久化的父節點,例如/locks,作為所有鎖的根目錄。
  2. 競爭鎖:當一個客戶端想要獲取鎖時,它會在/locks父節點下創建一個臨時順序子節點,例如/locks/lock-0000000001
  3. 判斷是否獲得鎖:客戶端獲取/locks下所有子節點的列表,并判斷自己創建的子節點是否是其中序號最小的。如果是,則表示成功獲取鎖。
  4. 監聽前一個節點:如果客戶端創建的子節點不是序號最小的,說明前面還有其他客戶端持有鎖。此時,該客戶端會監聽(Watch)比自己序號小的前一個節點。例如,如果客戶端創建的是/locks/lock-0000000003,它會監聽/locks/lock-0000000002
  5. 釋放鎖:當持有鎖的客戶端完成操作后,會刪除自己創建的臨時節點。由于是臨時節點,即使客戶端崩潰,該節點也會被ZooKeeper自動刪除,從而釋放鎖。
  6. 喚醒等待者:當被監聽的前一個節點被刪除時,ZooKeeper會通知監聽它的客戶端。收到通知的客戶端會再次檢查自己是否是當前序號最小的節點,如果是,則獲取鎖。

2.2 節點監聽機制(Watcher)

ZooKeeper的Watcher機制允許客戶端在節點狀態發生變化時(如節點創建、刪除、數據改變等)接收到通知。這在分布式鎖的實現中至關重要,它避免了客戶端頻繁地去查詢節點狀態,從而減少了不必要的網絡開銷和“羊群效應”(Herd Effect)。

“羊群效應”是指當一個節點發生變化時,所有等待的客戶端都被喚醒,然后它們又同時去競爭鎖,導致不必要的資源消耗。通過讓每個客戶端只監聽它前面一個節點,可以有效地避免這種問題,實現“首尾相接”的通知機制,保證了鎖的傳遞有序且高效。

2.3 臨時節點的自動刪除

ZooKeeper的臨時節點特性保證了即使客戶端在持有鎖期間崩潰,其創建的臨時節點也會被ZooKeeper自動刪除,從而避免了死鎖的發生。這大大提高了分布式鎖的健壯性。

3. ZooKeeper分布式鎖的實現步驟

基于上述原理,實現ZooKeeper分布式鎖的典型步驟如下:

  1. 連接ZooKeeper:客戶端首先需要建立與ZooKeeper集群的連接。
  2. 創建父節點:在ZooKeeper中創建一個持久化的根節點,例如/distributed_locks,用于存放所有分布式鎖的子節點。
  3. 獲取鎖
    a. 客戶端在/distributed_locks下創建一個臨時順序節點,例如/distributed_locks/lock_
    b. 獲取/distributed_locks下所有子節點的列表。
    c. 判斷自己創建的節點是否是所有子節點中序號最小的。如果是,則獲取鎖成功。
    d. 如果不是,則找到比自己序號小的前一個節點,并對其設置Watcher監聽。
    e. 進入等待狀態,直到接收到前一個節點刪除的通知。
    f. 收到通知后,重復步驟b,再次判斷是否獲取鎖。
  4. 釋放鎖
    a. 執行完業務邏輯后,刪除自己創建的臨時順序節點。
    b. 關閉ZooKeeper連接。

4. Java代碼示例 (基于Curator框架)

在Java中,通常使用Apache Curator框架來操作ZooKeeper,因為它封裝了許多ZooKeeper的復雜操作,提供了更高級別的API,包括分布式鎖的實現。Curator提供了InterProcessMutex來實現可重入的分布式排他鎖。

首先,添加Maven依賴:

<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</n> <!-- 包含分布式鎖的實現 --><version>5.2.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>5.2.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-client</artifactId><version>5.2.0</version>
</dependency>

然后是代碼示例:

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;import java.util.concurrent.TimeUnit;public class ZkDistributedLockExample {private static final String ZK_ADDRESS = "127.0.0.1:2181"; // ZooKeeper地址private static final String LOCK_PATH = "/distributed_lock"; // 鎖的路徑public static void main(String[] args) {CuratorFramework client = null;try {// 1. 創建Curator客戶端client = CuratorFrameworkFactory.builder().connectString(ZK_ADDRESS).sessionTimeoutMs(60000).connectionTimeoutMs(30000).retryPolicy(new ExponentialBackoffRetry(1000, 3)) // 重試策略:初始等待1秒,最多重試3次.build();// 2. 啟動客戶端client.start();client.blockUntilConnected(); // 阻塞直到連接成功System.out.println(Thread.currentThread().getName() + " ZooKeeper客戶端連接成功!");// 3. 創建分布式鎖實例InterProcessMutex lock = new InterProcessMutex(client, LOCK_PATH);// 模擬多個線程競爭鎖for (int i = 0; i < 5; i++) {new Thread(() -> {try {System.out.println(Thread.currentThread().getName() + " 嘗試獲取鎖...");if (lock.acquire(10, TimeUnit.SECONDS)) { // 嘗試獲取鎖,最多等待10秒try {System.out.println(Thread.currentThread().getName() + " 成功獲取鎖!執行業務邏輯...");// 模擬業務邏輯處理時間Thread.sleep(2000);} finally {lock.release(); // 釋放鎖System.out.println(Thread.currentThread().getName() + " 釋放鎖。");}} else {System.out.println(Thread.currentThread().getName() + " 獲取鎖失敗!");}} catch (Exception e) {e.printStackTrace();}}, "Thread-" + i).start();}// 等待所有線程執行完畢Thread.sleep(15000);} catch (Exception e) {e.printStackTrace();} finally {if (client != null) {client.close();}}}
}

代碼說明:

  • CuratorFrameworkFactory.builder().build():用于創建Curator客戶端實例,連接ZooKeeper集群。
  • ExponentialBackoffRetry:重試策略,當連接ZooKeeper失敗時,會按照指數退避的方式進行重試。
  • InterProcessMutex(client, LOCK_PATH):創建InterProcessMutex實例,它代表了一個可重入的分布式排他鎖。LOCK_PATH是鎖在ZooKeeper上的路徑。
  • lock.acquire(10, TimeUnit.SECONDS):嘗試獲取鎖,如果10秒內未能獲取到鎖,則返回false。這是一個阻塞方法,直到獲取到鎖或超時。
  • lock.release():釋放鎖。務必在finally塊中調用,確保鎖總是被釋放

5. ZooKeeper分布式鎖的優缺點

5.1 優點

  • 高可用性:ZooKeeper集群本身具有高可用性,只要集群中大多數節點正常工作,分布式鎖服務就能正常提供。
  • 可靠性:利用臨時順序節點和Watcher機制,能夠有效避免死鎖,并且在客戶端崩潰時自動釋放鎖。
  • 公平性:通過順序節點,可以實現公平鎖,保證先到先得。
  • 避免羊群效應:通過只監聽前一個節點,避免了所有等待客戶端同時被喚醒的問題。

5.2 缺點

  • 性能相對較低:與基于Redis等內存數據庫實現的分布式鎖相比,ZooKeeper的性能相對較低,因為每次加鎖和釋放鎖都需要與ZooKeeper集群進行網絡通信,涉及到節點的創建、刪除和監聽,這些操作都需要經過ZooKeeper的Leader節點處理并同步到Follower節點,有一定的延遲。
  • 實現復雜度較高:雖然Curator框架簡化了開發,但其底層原理和機制相對復雜,需要對ZooKeeper有深入的理解才能更好地使用和排查問題。
  • 依賴ZooKeeper集群:系統的可用性依賴于ZooKeeper集群的穩定性。

6. 最佳實踐

  • 選擇合適的鎖路徑:為不同的業務場景或共享資源定義清晰、有意義的鎖路徑。
  • 合理設置會話超時時間:ZooKeeper的會話超時時間決定了客戶端與服務器斷開連接后,臨時節點被刪除的時間。應根據業務需求和網絡狀況合理設置,避免過短導致誤釋放鎖,或過長導致死鎖。
  • 使用Curator框架:強烈推薦使用Apache Curator等成熟的ZooKeeper客戶端框架,它們提供了豐富的特性和更穩定的API,簡化了分布式鎖的實現。
  • finally塊中釋放鎖:確保無論業務邏輯是否發生異常,鎖都能被正確釋放,防止死鎖。
  • 考慮鎖的粒度:根據業務需求,選擇合適的鎖粒度。過粗的粒度會降低并發性,過細的粒度會增加鎖的開銷。
  • 監控ZooKeeper集群:對ZooKeeper集群進行實時監控,包括連接狀態、節點數量、延遲等指標,確保其健康運行。

7. 總結

ZooKeeper作為一款優秀的分布式協調服務,為分布式鎖的實現提供了可靠的基礎。通過其臨時順序節點和Watcher機制,可以構建出高可用、可靠且公平的分布式鎖。雖然其性能可能不如基于內存數據庫的方案,但在對鎖的可靠性和一致性要求較高的場景下,ZooKeeper分布式鎖是一個非常好的選擇。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/87929.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/87929.shtml
英文地址,請注明出處:http://en.pswp.cn/web/87929.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux線程——基礎全解

一、什么是線程&#xff08;Thread&#xff09;&#xff1f;? 定義&#xff1a;線程是程序執行的最小單位。即線程&#xff08;Thread&#xff09;是操作系統能夠進行運算調度的最小單位&#xff0c;它被包含在進程之中&#xff0c;是進程中的實際運作單位。一個進程可以并發多…

Java基礎--封裝+static

目錄 什么是封裝&#xff1f; 什么是訪問限定符&#xff1f; static靜態修飾符 用static修飾的類變量或類方法的注意事項&#xff1a; 什么是封裝&#xff1f; 封裝是面向對象的三大特性之一&#xff0c;指的是將一個類中的實現細節進行隱藏&#xff0c;對外只提供一些開放…

DAY 51 復習日

作業&#xff1a;day43的時候我們安排大家對自己找的數據集用簡單cnn訓練&#xff0c;現在可以嘗試下借助這幾天的知識來實現精度的進一步提高import torch import torch.nn as nn import torch.nn.functional as F import torchvision import torchvision.transforms as trans…

針對網絡爬蟲的相關法律法規整理

在中國&#xff0c;網絡爬蟲的法律法規涉及多個層面&#xff0c;包括個人信息保護、數據安全、網絡安全、知識產權、反不正當競爭等。以下是詳細的法律法規分析及合規指南&#xff1a; 1. 核心法律法規及適用場景? ??&#xff08;1&#xff09;《民法典》——隱私權與個人信…

1.1_5_2 計算機網絡的性能指標(下)

繼續來看計算機網絡的性能指標&#xff0c;接下來我們探討時延&#xff0c;時延帶寬積和往返時延&#xff0c;以及信道利用率這幾個性能指標。 首先來看時延這個性能指標&#xff0c;英文叫delay&#xff0c;也有的教材&#xff0c;把它翻譯為延遲。所謂的時延&#xff0c;就是…

PP-OCRv2:超輕OCR系統的萬能包

PP-OCRv2&#xff1a;超輕OCR系統的萬能包摘要光學字符識別&#xff08;OCR&#xff09;系統已廣泛應用于多種場景&#xff0c;但設計兼顧精度與效率的OCR系統仍具挑戰性。我們此前提出的超輕量OCR系統PP-OCR在平衡兩者方面取得進展。本文進一步提出PP-OCRv2&#xff0c;通過五…

常見的軟件版本開源協議

開源軟件許可證核心指南 一、許可證基礎分類 1. 寬松型許可證&#xff08;Permissive&#xff09; 核心特征&#xff1a;允許閉源衍生&#xff0c;僅保留版權聲明適用場景&#xff1a;商業集成、快速開發代表協議&#xff1a; &#x1f4dc; MIT &#x1f4dc; Apache 2.0 &…

基于FPGA的一維序列三次樣條插值算法verilog實現,包含testbench

目錄 1.前言 2.算法運行效果圖預覽 3.算法運行軟件版本 4.部分核心程序 5.算法仿真參數 6.算法理論概述 7.參考文獻 8.算法完整程序工程 1.前言 三次樣條插值是一種在數據擬合和信號處理中廣泛應用的技術&#xff0c;它通過構造分段三次多項式來逼近給定的離散數據點&a…

RAG 之 Prompt 動態選擇的三種方式

“如果我有5個prompt模板&#xff0c;我想只選擇一個每次都自動五選一能做到嗎怎么做&#xff1f;” 完全可以做到。這在復雜的RAG或Agentic工作流中是一個非常普遍且關鍵的需求&#xff0c;通常被稱為“條件路由&#xff08;Conditional Routing&#xff09;”或“動態調度&am…

【ROS2 自動駕駛學習】02-安裝ROS2及其配套工具

目錄 一、設置語言環境 二、添加存儲庫 三、添加軟件源 四、安裝ROS2 五、配置環境 六、測試ROS2 七、安裝一些工具 7.1 terminator 7.2 colcon工具 7.3 tf工具 7.4 joint-state-publisher工具 7.5 urdf 八、安裝三方庫 8.1 Eigen 8.2 yaml-cpp 8.3 matplotl…

系統學習Python——并發模型和異步編程:基礎知識

分類目錄&#xff1a;《系統學習Python》總目錄 并行是并發的一種特殊情況。**所有并行系統都是并發的&#xff0c;但不是所有并發系統都是并行的。**在21世紀初&#xff0c;我們可以使用單核設備在GNU Linux上同時處理100個進程。一臺擁有4個CPU核的現代筆記本計算機&#xff…

睿爾曼系列機器人——以創新驅動未來,重塑智能協作新生態(下)

在智能制造與人工智能深度融合的當下&#xff0c;機器人技術正經歷從 “功能替代” 到 “價值共創” 的深刻躍遷。睿爾曼&#xff0c;作為全球超輕量仿人機械臂領域的先行者&#xff0c;始終秉持 “讓機器人觸手可及” 的使命&#xff0c;憑借底層技術的突破性進展&#xff0c;…

表征工程(Representation Engineering, RepE)

表征工程(Representation Engineering, RepE) 近年來,表征工程(Representation Engineering, RepE)在提升AI系統透明度和可控性方面取得了顯著進展。 一、大模型可解釋性與可控性的突破 核心論文:《Representation Engineering: A Top-Down Approach to AI Transparen…

國產ARM+FPGA工業開發平臺——GM-3568JHF

一、引言 隨著物聯網和國產替代需求的快速發展&#xff0c;嵌入式系統面臨計算性能與硬件靈活性的雙重挑戰。GM-3568JHF開發板基于國產“ARMFPGA”異構架構&#xff0c;結合瑞芯微RK3568J處理器與紫光同創Logos-2 FPGA芯片&#xff0c;支持國產自主操作系統&#xff0c;滿足通…

RISCV Linux 虛擬內存精講系列一 Sv39

筆者認為&#xff0c;Linux 操作系統&#xff08;Operating System&#xff09;最核心的機制是虛擬內存&#xff08;Virtual Memory&#xff09;。因為&#xff0c;操作系統主要作用是將硬件環境抽象起來&#xff0c;給在其中運行的應用&#xff08;Applications&#xff09;提…

【apply from: “$flutterRoot/packages/flutter_tools/gradle/flutter.gradle“作用】

這行代碼的作用是將 Flutter 的 Gradle 構建腳本集成到 Android 項目中&#xff0c;具體細節如下&#xff1a;作用解析&#xff1a;引入 Flutter 構建邏輯 flutter.gradle 是 Flutter SDK 的核心構建腳本&#xff0c;它負責&#xff1a; 編譯 Dart 代碼為原生二進制文件&#x…

深入理解JavaScript設計模式之命令模式

深入理解JavaScript設計模式之命令模式 文章目錄深入理解JavaScript設計模式之命令模式定義簡單命令模式組合命令模式使用命令模式實現文本編輯器目標關鍵類說明實現的效果交互邏輯流程所有代碼&#xff1a;總結定義 命令模式也是設計模式種相對于變焦簡單容易理解的一種設計模…

CSS 網頁布局:從基礎到進階

CSS 網頁布局&#xff1a;從基礎到進階 引言 隨著互聯網的飛速發展&#xff0c;網頁設計已經成為了一個不可或缺的領域。CSS&#xff08;層疊樣式表&#xff09;作為網頁設計中的關鍵工具&#xff0c;用于控制網頁元素的樣式和布局。本文將為您全面解析CSS網頁布局&#xff0c;…

【人工智能】大語言模型(LLM) NLP

大語言模型&#xff08;LLM&#xff09;& NLP1.大語言模型&#xff08;LLM&#xff09;1.1 一句話解釋1.2 更形象的比喻1.3 為什么叫 “大” 模型1.4 它能做什么1.5 現實中的例子2.對比 NLP2.1 用 “汽車進化” 比喻 NLP → LLM2.2 為什么說 LLM 屬于 NLP2.3 LLM 的 “革命…

Unity HDRP + Azure IoT 的 Python 后端實現與集成方案

Unity HDRP Azure IoT 的 Python 后端實現與集成方案 雖然Unity HDRP本身使用C#開發&#xff0c;但我們可以構建Python后端服務支持物聯網系統&#xff0c;并與Unity引擎深度集成。以下是完整的實現方案&#xff1a; 系統架構 #mermaid-svg-qCDb0g9Ik287Cg8X {font-family:&qu…