一、开篇概述
目前工业界主流分布式锁两大技术栈:Redis 分布式锁 、ZooKeeper 分布式锁。二者都能实现跨进程、跨实例资源互斥,但设计思想、底层机制、特性、性能、容错能力截然不同。 很多团队选型时容易纠结:到底该用哪一种?本篇抛开理论空谈,结合线上真实业务场景、压力表现、故障场景逐一拆解,同时补充跨语言实现,覆盖 Java 之外的主流开发语言。
二、ZooKeeper 分布式锁核心原理
先快速理清 ZK 锁的底层实现,方便后续对比。ZK 基于树形节点 + 临时节点 + 有序节点 + Watch 监听实现分布式锁,是典型的 CP 模型组件。
2.1 核心数据节点类型
- 持久节点:节点创建后永久存在,手动删除才会消失;
- 临时节点(Ephemeral) :客户端会话断开、宕机、网络中断,节点自动删除,天然防死锁;
- 临时有序节点:在临时节点基础上,ZK 自动为节点后缀拼接全局递增序号,用来实现排队。
2.2 标准公平锁执行流程(主流实现)
- 所有竞争线程在同一父节点下,创建临时有序子节点;
- 获取当前父节点下所有子节点并排序,判断自己创建的节点是否为序号最小节点;
- 若是最小节点:成功获取锁,执行业务逻辑;
- 若不是最小节点:对前一个序号节点注册 Watch 监听,进入阻塞等待;
- 持有锁的线程执行完毕,主动删除自身节点;
- 前序节点被删除后,触发 Watch 事件,唤醒当前线程,再次判断序号竞争锁。
2.3 ZK 锁核心原生特性
- 天然公平锁:有序节点保证请求先后顺序,无线程饥饿;
- 天然防死锁:依赖临时节点,客户端宕机自动删节点,无需手动设置过期时间;
- 强一致性:ZK 集群数据同步采用 ZAB 协议,半数节点写入成功即生效,无主从异步丢锁问题;
- 阻塞唤醒:基于 Watch 机制,无空轮询,CPU 占用极低。
2.4 简单 Java 原生 ZK 锁示例(Curator 框架)
生产环境基本使用 Apache Curator 封装好的锁 API,无需手写原生节点逻辑: