11.7.3 分布式锁与领导选举实践
分布式锁与领导选举实践旨在通过 ZooKeeper 的临时节点、顺序节点与 Watch 机制,实现跨进程互斥与主从切换。以下以运维视角给出可落地的流程与注意事项,确保可用性、一致性与可观测性,并包含安装、示例、排错与练习。
一、分布式锁实践#
1. 原理草图(锁)#
2. 安装与连接准备#
以已部署 ZooKeeper 集群为前提,准备客户端连接:
# 进入 ZooKeeper 安装目录
cd /opt/zookeeper
# 连接到集群(任一节点)
bin/zkCli.sh -server 10.0.0.11:2181
# 期望输出:Welcome to ZooKeeper!
3. 锁实现策略与命令示例#
3.1 初始化父节点#
# 创建锁父路径(持久节点)
create /locks ""
create /locks/taskA ""
命令解释:create /locks/taskA "" 创建持久节点,作为所有锁的根路径。
3.2 申请锁(创建临时顺序节点)#
# 模拟客户端A
create -s -e /locks/taskA/lock- ""
# 模拟客户端B
create -s -e /locks/taskA/lock- ""
预期效果:
- A 得到 /locks/taskA/lock-0000000001
- B 得到 /locks/taskA/lock-0000000002
3.3 判断持锁者(最小序号)#
ls /locks/taskA
命令解释:ls 返回所有锁节点,序号最小者持锁。
3.4 监听前序节点(避免羊群效应)#
# B 监听 A 的前序节点
get -w /locks/taskA/lock-0000000001
命令解释:-w 仅在该节点变更时触发,减少 watcher 风暴。
3.5 释放锁#
# 持锁者删除自身节点
delete /locks/taskA/lock-0000000001
预期效果:B 的 watcher 触发,B 重新判断成为持锁者。
4. Fencing Token 防护令牌示例#
# 获取当前持锁的序号作为 fencing token
# 示例:lock-0000000003 -> token=3
业务写入侧必须校验 token 递增性,拒绝旧 token 写操作。
5. 常见排错#
- 问题:锁长时间不释放
排查:
bash # 查看会话 stat /locks/taskA/lock-0000000001
若持锁节点会话未过期,确认业务是否异常未主动释放。 - 问题:watch 未触发
排查:watch 为一次性触发,需在收到事件后重新get -w。
6. 练习#
- 练习1:启动三个终端模拟三客户端,依序创建
lock-,验证公平性。 - 练习2:杀掉持锁客户端进程,观察临时节点自动删除与锁转移。
二、领导选举实践#
1. 原理草图(选举)#
2. 选举路径与命令示例#
# 创建选举父路径
create /election ""
create /election/serviceX ""
# 各实例创建临时顺序节点
create -s -e /election/serviceX/leader- ""
create -s -e /election/serviceX/leader- ""
# 观察顺序
ls /election/serviceX
命令解释:/election/serviceX/leader-0000000001 序号最小者为 Leader。
3. Leader 标识写入与维护#
# Leader 写入自身信息(IP:PORT)
create /leader ""
create /leader/serviceX "10.0.0.21:8080"
# Follower 读取当前Leader
get /leader/serviceX
4. 故障演练#
# 强制删除 Leader 临时节点模拟故障
delete /election/serviceX/leader-0000000001
# 观察重新选举
ls /election/serviceX
5. 常见排错#
- 问题:出现“多 Leader”
排查:确认所有实例使用同一选举路径且都使用临时顺序节点。 - 问题:频繁切换
排查:检查网络抖动与 sessionTimeout 设置是否过低。
6. 练习#
- 练习1:设置不同
sessionTimeout,观察 Leader 失效时间差异。 - 练习2:同时启动 5 个实例,统计选举时间与 Leader 变更次数。
三、运维与监控要点#
1. 关键指标与命令#
# 四字命令查看指标(需在 zk 配置中启用)
echo mntr | nc 10.0.0.11 2181
# 关注字段
# zk_num_alive_connections
# zk_outstanding_requests
# zk_watch_count
2. 告警与阈值建议#
- 会话过期频繁:
zk_expired_sessions> 0 - Leader 频繁变更:选举路径节点短期内大量创建/删除
- 锁等待过长:应用侧统计锁等待时间 > 5s
四、验证与压测方法#
# 并发锁争用测试(示例:10个并发)
for i in {1..10}; do
bin/zkCli.sh -server 10.0.0.11:2181 <<'EOF' &
create -s -e /locks/taskA/lock- ""
EOF
done
wait
预期效果:序号连续,公平性良好。
五、实践清单#
- 使用临时顺序节点实现锁与选举
- 只监听前序节点,降低 Watcher 风暴
- 引入 fencing token,防止旧持有者写入
- 业务侧处理选举切换过程中的幂等与状态一致性
- 监控会话、延迟与 Leader 变更频率