Zookeeper实现分布式锁的原理

🧠 一、Zookeeper 分布式锁的核心原理

Zookeeper 的分布式锁基于其两个特性:

  1. 临时节点(Ephemeral Node)

    • 客户端与 ZK 会话断开后,节点自动删除。
    • 这样可以防止"锁被永久占用"。
  2. 有序节点(Sequential Node)

    • 每次创建节点时,ZK 会在名称后自动追加递增序号,如:

      csharp 复制代码
      /lock/lock-00000001
      /lock/lock-00000002
    • 这样天然可以实现「排队」。

🔩 二、Zookeeper 分布式锁算法原理

假设锁路径是 /lock

  1. 客户端尝试加锁

    • 每个客户端创建一个临时顺序节点:

      csharp 复制代码
      /lock/lock-00000001
  2. ZK 排序所有子节点

    • 客户端获取 /lock 下的所有子节点,判断自己是不是最小的。
    • 如果自己是最小节点 → 获取锁成功
    • 否则 → 监听前一个节点(例如自己是 00000005,就监听 00000004)。
  3. 锁释放(解锁)

    • 客户端完成任务后,删除自己的临时节点。
    • 监听该节点的下一个客户端会收到通知,从而重新竞争锁。

🔄 三、Zookeeper 分布式锁的完整流程图(文字版)

arduino 复制代码
Client A 创建 /lock/lock-00000001  → 成功获得锁
Client B 创建 /lock/lock-00000002  → 监听 00000001
Client C 创建 /lock/lock-00000003  → 监听 00000002

当 Client A 删除节点 → Client B 收到通知 → 获得锁
当 Client B 删除节点 → Client C 收到通知 → 获得锁

💡 四、Java 中的常见实现方式

✅ 方式 1:使用 Curator 框架(最常用)

Curator 是 Apache 官方维护的 Zookeeper 高级客户端 ,封装了分布式锁、选主、Barrier 等高级特性。

推荐直接用它来实现锁,而不是自己操作 ZNode。

🧱 Maven 依赖坐标

xml 复制代码
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.6.0</version>
</dependency>

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>5.6.0</version>
</dependency>

(版本号可查最新的 Apache Curator Releases

🧩 代码示例

java 复制代码
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 ZookeeperLockDemo {

    private static final String ZK_ADDRESS = "127.0.0.1:2181";
    private static final String LOCK_PATH = "/distribute-lock";

    public static void main(String[] args) {
        // 1️⃣ 创建客户端
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString(ZK_ADDRESS)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .build();
        client.start();

        // 2️⃣ 创建分布式锁对象
        InterProcessMutex lock = new InterProcessMutex(client, LOCK_PATH);

        try {
            // 3️⃣ 尝试获取锁,等待最多5秒
            if (lock.acquire(5, TimeUnit.SECONDS)) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 获得锁,执行任务...");
                    Thread.sleep(3000);
                } finally {
                    lock.release();
                    System.out.println(Thread.currentThread().getName() + " 释放锁");
                }
            } else {
                System.out.println("获取锁超时");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.close();
        }
    }
}

⚙️ 五、Curator 实现锁的底层原理(简述)

InterProcessMutex 的底层逻辑其实和上文算法一致:

  1. 创建 /distribute-lock/lock-xxxx 临时顺序节点。
  2. 判断是否为最小节点。
  3. 如果不是,监听前一个节点。
  4. 前一个节点释放时收到 Watcher 事件,重新判断。
  5. 最终释放时删除节点。

Curator 内部封装了:

  • 异常重试机制
  • 会话断开自动释放
  • 可重入锁支持

🧾 六、Zookeeper 分布式锁的优缺点

优点 缺点
公平锁,严格按顺序 性能较 Redis 锁慢(网络开销 + ZK 延迟)
可重入锁、自动失效 依赖 ZK 集群的高可用性
强一致性 部署复杂度较高
相关推荐
uzong4 小时前
后端线上发布计划模板
后端
uzong5 小时前
软件工程师应该关注的几种 UML 图
后端
上进小菜猪6 小时前
基于 YOLOv8 的 100 类中药材智能识别实战 [目标检测完整源码]
后端
码事漫谈7 小时前
AI 技能工程入门:从独立能力到协作生态
后端
码事漫谈7 小时前
构建高并发AI服务网关:C++与gRPC的工程实践
后端
颜酱9 小时前
前端必备动态规划的10道经典题目
前端·后端·算法
半夏知半秋9 小时前
rust学习-闭包
开发语言·笔记·后端·学习·rust
LucianaiB10 小时前
【保姆级教程】10分钟把手机变成AI Agent:自动刷课、回消息,学不会我“退网”!
后端
Mr -老鬼10 小时前
功能需求对前后端技术选型的横向建议
开发语言·前端·后端·前端框架
IT=>小脑虎10 小时前
Go语言零基础小白学习知识点【基础版详解】
开发语言·后端·学习·golang