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 变更频率