看这篇博客之前可以先去了解博主的另一篇讲解ZooKeeper的博客:分布式微服务--ZooKeeper的客户端常用命令 & Java API 操作-CSDN博客

1. 为什么需要分布式锁?

在分布式系统中,多个服务节点可能同时访问或修改同一份共享资源(例如数据库记录、缓存数据、文件等)。
如果不加限制,容易出现数据不一致或竞争条件。
因此,需要一种机制来保证:同一时刻只有一个节点能访问某资源。这就是分布式锁的意义。

常见分布式锁实现方式:

  • 基于 Redis

  • 基于 ZooKeeper

  • 基于 数据库

其中 ZooKeeper 实现分布式锁更安全可靠,因为它的核心是 强一致性 + 临时顺序节点机制


2. ZooKeeper 的分布式锁原理

ZooKeeper 提供的 临时节点(Ephemeral)有序节点(Sequential) 是实现分布式锁的关键。

核心思想:

  1. 创建锁节点
    所有客户端到某个固定路径(如 /lock)下创建一个 临时顺序节点,例如:

    /lock/lock_00000001
    /lock/lock_00000002
    /lock/lock_00000003
    
    • 临时节点保证客户端宕机或断开时自动删除。

    • 顺序节点保证多个客户端的排队顺序。

  2. 获取锁
    客户端判断自己创建的节点是否是 序号最小的节点

    • 如果是 → 获取锁成功。

    • 如果不是 → 监听比自己小的前一个节点,等待其释放。

  3. 释放锁
    客户端执行完业务逻辑后,删除自己的节点 → 唤醒下一个等待者。


3. 分布式锁实现步骤

假设我们要对某个共享资源 order 加锁。

1)获取锁

  • 客户端在 /lock/order 下创建临时顺序节点,例如:
    /lock/order/lock_00000010

  • 获取 /lock/order 下所有子节点,并排序。

  • 如果自己是最小的节点 → 获得锁。

  • 否则 → 监听自己前一个节点。

2)释放锁

  • 客户端完成业务逻辑后,删除自己的节点。

  • ZooKeeper 会通知下一个等待者。

3)异常情况

  • 如果客户端宕机或与 ZooKeeper 断开连接,ZooKeeper 会自动删除临时节点,从而避免锁“死锁”。


4. ZooKeeper 分布式锁代码示例

基于 Curator(推荐)

Curator 是 ZooKeeper 的一个高级客户端,封装了分布式锁。


样例代码(本次使用的锁是InterProcessMutex):

xml

  <!--curator--><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.0.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.0.0</version></dependency>

代码


/*** 模拟12306售票系统 —— 使用 Zookeeper 分布式锁保证并发安全*/
public class Ticket12306 implements Runnable{// 模拟数据库中的票数private int tickets = 10;// 分布式可重入锁对象(Curator 提供)private InterProcessMutex lock ;public Ticket12306(){// 1. 定义重试策略:初始等待时间 3 秒,最多重试 10 次RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);// 2. 通过 builder 模式创建 CuratorFramework 客户端CuratorFramework client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181") // Zookeeper 连接地址.sessionTimeoutMs(60 * 1000) // 会话超时时间.connectionTimeoutMs(15 * 1000) // 连接超时时间.retryPolicy(retryPolicy) // 指定重试策略.build();// 3. 开启连接client.start();// 4. 创建分布式锁对象,指定锁的路径(ZK 节点)//   不同客户端只要路径一样,就能实现互斥lock = new InterProcessMutex(client,"/lock");}@Overridepublic void run() {while(true){try {// 1. 尝试获取锁,最多等待 3 秒lock.acquire(3, TimeUnit.SECONDS);// 2. 拿到锁后执行业务逻辑 —— 卖票if(tickets > 0){System.out.println(Thread.currentThread()+":" + tickets);Thread.sleep(100); // 模拟业务处理耗时tickets--; // 卖出一张票}} catch (Exception e) {e.printStackTrace();} finally {// 3. 无论如何,最后都要释放锁,避免死锁try {lock.release();} catch (Exception e) {e.printStackTrace();}}}}
}

测试:

/*** 测试类:模拟多个客户端同时抢票*/
public class LockTest {public static void main(String[] args) {// 创建一个 Ticket12306 对象(共享 10 张票)Ticket12306 ticket12306 = new Ticket12306();// 创建两个线程,模拟两个不同的售票平台(携程、飞猪)Thread t1 = new Thread(ticket12306,"携程");Thread t2 = new Thread(ticket12306,"飞猪");// 启动线程,同时卖票t1.start();t2.start();}
}

总结:

  1. InterProcessMutex 是 Curator 提供的 可重入分布式锁,底层用 Zookeeper 的临时顺序节点实现。

  2. lock.acquire() 获取锁,获取不到会阻塞(或超时返回 false)。

  3. lock.release() 释放锁,必须写在 finally,避免异常导致死锁。

  4. 这种方式可以模拟 多进程/多机器的并发安全,保证同一时刻只有一个客户端在修改票数。


5. ZooKeeper 分布式锁的优缺点

✅ 优点

  • 强一致性:ZK 的数据一致性保证了锁的可靠性。

  • 自动释放:客户端宕机,临时节点会自动删除,避免死锁。

  • 公平性:顺序节点机制,保证先来先服务。

❌ 缺点

  • 性能较低:每次加锁/解锁都需要与 ZK 通信,适合低并发场景。

  • 部署复杂:需要搭建 ZooKeeper 集群。

  • 羊群效应:节点删除时可能触发大量客户端通知(不过监听前一个节点可以缓解)。


6. 使用场景

  • 订单系统(防止超卖)

  • 分布式定时任务(同一时间只允许一个节点执行)

  • 共享资源访问控制(文件、缓存等)


7. 总结

  • ZooKeeper 分布式锁依赖 临时顺序节点 + watcher 机制

  • Curator 封装了常用的锁(InterProcessMutex),开发更方便。

  • 适合一致性要求高、并发量不是极高的业务场景。

  • 高并发下更推荐 Redis 分布式锁(性能更好,但需要妥善解决可靠性问题)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96198.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96198.shtml
英文地址,请注明出处:http://en.pswp.cn/web/96198.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于容器化云原生的 MySQL 及中间件高可用自动化集群项目

1 项目概述 本项目旨在构建一个高可用、高性能的 MySQL 集群,能够处理大规模并发业务。通过容器化部署、多级缓存、完善的监控和备份策略,确保数据库服务的连续性和数据安全性。 架构总览 预期目标 数据库服务可用性达到 99.99% 支持每秒 thousands 级别的并发访问 实现秒…

如何将 iPhone 备份到电脑/PC 的前 5 种方法

定期备份你的 iPhone&#xff08;最好每两周一次&#xff09;对于保护你的数据至关重要。它确保了如果设备损坏、丢失或被盗&#xff0c;或者你换了新手机&#xff0c;你不会丢失重要信息&#xff0c;并且可以轻松地从备份中恢复应用程序、照片、设置等。如果你不确定如何备份 …

国产AI芯片编程模型深度对比:寒武纪MLU vs 壁仞BR100异构计算设计

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;H卡级别算力&#xff0c;80G大显存&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生更享专属优惠。 引言&#xff1a;国产AI芯片的崛起与挑战 随着人工智能技术的飞速…

【项目】基于One Thread One Loop模型的高性能网络库实现 - 项目介绍与前置知识

目录 项目介绍 HTTP服务器基本认识 Reactor模式基本认识 单Reactor单线程模式认识 单Reactor多线程模式认识 多Reactor多线程模式认识 模块划分 Server模块 Buffer模块 Socket模块 Channel模块 Connection模块 Acceptor模块 TimerQueue模块 Poller模块 EventLo…

lua中table键类型及lua中table的初始化有几种方式

在 Lua 中&#xff0c;table 的键几乎可以是任何类型&#xff0c;但有几个重要的规则和最佳实践需要了解。1. 主要键类型(1) 字符串 (string)这是最常见、最推荐的键类型。local person {name "Alice", -- 等同于 ["name"] "Alice"["age…

matlab实现利用双MZI产生RZ33-QPSK信号

利用MATLAB实现双MZI产生RZ33-QPSK信号的代码&#xff1a; 参数设置 % 信号参数 fs 1e6; % 采样频率 fc 10e6; % 载波频率 T 1e-6; % 符号周期 N 1000; % 采样点数 t 0:1/fs:(N-1)/fs; % 时间向量生成QPSK信号 % 生成随机二进制序列 data randi([0,1],1,N);% 将二进制序列…

Vue响应式更新 vs React状态更新:两种范式的底层逻辑与实践差异

在现代前端框架中&#xff0c;Vue和React作为两大主流选择&#xff0c;分别采用了截然不同的状态管理与更新机制。Vue的“响应式更新”通过自动追踪依赖实现数据与视图的联动&#xff0c;而React的“状态更新”则依赖显式setState触发重新渲染。本文将从底层原理、更新流程、优…

Spring MVC 的常用注解

一、控制器相关注解ControllerController注解用于标记一个类为 Spring MVC 的控制器。在 Spring MVC 框架里&#xff0c;控制器扮演着关键角色&#xff0c;负责接收 HTTP 请求并返回响应。当一个类被Controller注解标记后&#xff0c;Spring 容器会自动识别并将其纳入管理。例如…

Oracle APEX 利用卡片实现翻转(方法一)

目录 0. 以 Oracle 的标准示例表 EMP 为例&#xff0c;实现卡片翻转 1. 创建PL/SQL动态内容区域 2. 添加 CSS 实现翻转效果 3. 添加动态操作 (Dynamic Action) 4. 看效果 0. 以 Oracle 的标准示例表 EMP 为例&#xff0c;实现卡片翻转 正面&#xff1a; 显示员工姓名 (EN…

Gradio全解11——Streaming:流式传输的视频应用(1)——FastRTC:Python实时通信库

Gradio全解11——Streaming&#xff1a;流式传输的视频应用&#xff08;1&#xff09;——FastRTC&#xff1a;Python实时通信库前言第11章 Streaming&#xff1a;流式传输的视频应用11.1 FastRTC&#xff1a;Python实时通信库11.1.1 WebRTC协议与FastRTC介绍1. WebRTC协议的概…

一文学会二叉搜索树,AVL树,红黑树

文章目录二叉搜索树查找插入删除AVL树概念插入旋转AVL验证红黑树概念插入检测二叉搜索树 也称二叉排序树或二叉查找树 二叉搜索树&#xff1a;可以为空&#xff0c;若不为空满足以下性质 ⭐1&#xff0c;非空左子树小于根节点的值 ⭐2&#xff0c;非空右子大于根节点的值 ⭐3…

Android实战进阶 - 启动页

场景&#xff1a;当启动页处于倒计时阶段&#xff0c;用户将其切换为后台的多任务卡片状态&#xff0c;倒计时会继续执行&#xff0c;直到最后执行相关逻辑&#xff08;一般会跳转引导页、进入主页等&#xff09; 期望&#xff1a;而综合市场来看&#xff0c;一般我们期望的是当…

无标记点动捕技术:重塑展厅展馆的沉浸式数字交互新时代

在元宇宙浪潮的持续推进下&#xff0c;虚拟数字人正逐渐成为连接虚实世界的重要媒介。在展厅展馆中&#xff0c;数字人不仅能够扮演导览员、讲解员角色&#xff0c;更可通过情感化交互提升参观体验&#xff0c;使文化传播更具感染力和沉浸感。虚拟人的引入&#xff0c;为传统展…

轻松Linux-7.Ext系列文件系统

天朗气清&#xff0c;惠风和煦&#xff0c;今日无事&#xff0c;遂来更新。 1.概述 总所周知&#xff0c;我们存的数据都是在一个叫硬盘的东西里面&#xff0c;这个硬盘又像个黑盒&#xff0c;这章就来简单解析一下Linux中文件系统。 现在我们用的大都是固态硬盘&#xff0c;…

Matlab机器人工具箱使用4 蒙特卡洛法绘制工作区间

原理&#xff1a;利用rand随机数&#xff0c;给各个关节设置随机关节变量&#xff0c;通过正运动学得到末端位姿变换矩阵&#xff0c;然后利用变换矩阵2三维坐标标记出末端坐标&#xff0c;迭代多次就可以构成点云。教程视频&#xff1a;【MATLAB机器人工具箱10.4 机械臂仿真教…

【项目】在AUTODL上使用langchain实现《红楼梦》知识图谱和RAG混合检索(三)知识图谱和路由部分

首先在数据集 - 开放知识图谱下载红楼梦的知识图谱&#xff0c;这个网站上有各种各样的知识图谱&#xff0c;可以挑你感兴趣的做( • ̀ω•́ ) 这个知识图谱的作者们已经将三元组抽取出来了&#xff0c;我们可以直接用&#xff0c;如果你对三元组是如何生成的感兴趣&#xf…

pycharm 最新版上一次编辑位置

2025nipycharm方法一&#xff1a;用快捷键&#xff08;最方便&#xff09;跳回上一次编辑位置&#xff1a;Windows/Linux: Ctrl Alt ←macOS: ⌘ Option ←跳到前一次位置&#xff1a;Windows/Linux: Ctrl Alt →macOS: ⌘ Option →方法二&#xff1a;显示工具栏按钮在…

前端性能监控与优化:从 Lighthouse 到 APM

在当今竞争激烈的数字环境中&#xff0c;用户对Web应用性能的要求日益提高。一个缓慢或响应迟钝的应用不仅会流失用户&#xff0c;更可能损害品牌形象和商业价值。因此&#xff0c;前端性能的监控与优化已成为前端开发不可或缺的关键环节。本文将深入探讨从基础的性能评估工具L…

TC_Motion多轴运动-电子齿轮

目录 电子齿轮 【基本概念】 【应用示例】 【开发总结】 END 电子齿轮 【基本概念】 定义:通过软件方法实现机械齿轮的速比调节功能(两个轴成线性比例旋转) 优点 免维护,告别机械损耗 易调节,任意修改齿轮比 精度高,无机械背隙 应用场景 多台电机拖动同一负载,要求多台…

CentOS 7 下载教程

访问阿里云镜像站 阿里巴巴开源镜像站 选择centos 点这个 选择7版本 进入isos目录 点这个 选择这个版本 因为这个镜像的日期更新 推荐下载 DVD 版&#xff1a;包含完整系统和常用软件&#xff0c;无需额外联网安装组件Minimal 版&#xff1a;精简版&#xff0c;仅包含基础系…