11.5.5 一致性保证:顺序性、原子性与可见性
一致性保证是 ZooKeeper 对外提供“可靠协调服务”的核心约束,体现在顺序性、原子性与可见性三方面。本节结合原理草图、命令与排错示例,帮助理解一致性边界与读写路径选择。
原理草图(顺序性/原子性/可见性)
顺序性(Ordering)
- Leader 为每个写请求分配唯一 ZXID,并串行化提交顺序。
- 所有 Follower 以相同 ZXID 顺序提交事务日志与内存数据。
- Watch 事件按事务提交顺序触发。
原子性(Atomicity)
- 只有超过半数 ACK 的 Proposal 才会提交;未达 Quorum 的写入对外不可见。
- 崩溃恢复时未提交事务回滚,避免“部分成功”。
可见性(Visibility)
- 写成功后对多数节点可见,最终对全部存活节点可见。
- 默认可从任意节点读,但可能读到旧值;通过 sync 或读 Leader 可提升可见性。
- 同一会话内读到的版本单调递增,不回退。
安装与基础环境准备(示例)
以三节点集群为例,确认后续一致性验证可执行。
# 1) 安装(以 Debian/Ubuntu 为例)
sudo apt-get update
sudo apt-get install -y zookeeperd
# 2) 备份并编辑配置
sudo cp /etc/zookeeper/conf/zoo.cfg /etc/zookeeper/conf/zoo.cfg.bak
sudo tee /etc/zookeeper/conf/zoo.cfg >/dev/null <<'EOF'
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/lib/zookeeper
clientPort=2181
server.1=zk1:2888:3888
server.2=zk2:2888:3888
server.3=zk3:2888:3888
EOF
# 3) 设置 myid(每台机器对应不同数字)
echo 1 | sudo tee /var/lib/zookeeper/myid
sudo systemctl restart zookeeper
sudo systemctl status zookeeper --no-pager
命令与一致性验证(示例)
通过多客户端写读与
sync强制追赶验证顺序性与可见性。
# 1) 连接 Leader(先通过命令确认)
echo stat | nc zk1 2181 | egrep 'Mode|Zxid'
# 2) 两个客户端分别写入
# 终端A
/ usr/share/zookeeper/bin/zkCli.sh -server zk1:2181 <<'EOF'
create /conf "v1"
set /conf "v2"
EOF
# 终端B(尽快执行)
/ usr/share/zookeeper/bin/zkCli.sh -server zk1:2181 <<'EOF'
set /conf "v3"
EOF
# 3) 在 Follower 读(可能读到旧值)
/ usr/share/zookeeper/bin/zkCli.sh -server zk2:2181 <<'EOF'
get /conf
EOF
# 4) 使用 sync 追赶后再读(提高可见性)
/ usr/share/zookeeper/bin/zkCli.sh -server zk2:2181 <<'EOF'
sync /conf
get /conf
EOF
事务日志与 ZXID 观测(示例)
观察顺序性与提交结果,确认无“部分成功”。
# 1) 查看节点状态
echo mntr | nc zk1 2181 | egrep 'zk_server_state|zk_zxid|zk_synced_followers'
# 2) 查看事务日志目录(不同发行版路径可能不同)
# 以默认 dataDir=/var/lib/zookeeper 为例
ls -lh /var/lib/zookeeper/version-2/
命令解释要点
- stat:查看当前角色(Leader/Follower)与最新 ZXID。
- sync /path:强制当前连接的服务端与 Leader 同步到最新 ZXID。
- mntr:输出监控指标,含角色、最新 ZXID、同步的 Follower 数量等。
常见排错(示例)
1) 读到旧数据
- 现象:Follower get 返回旧值。
- 处理:在读前执行 sync /path 或改为直连 Leader。
echo stat | nc zk2 2181 | egrep 'Mode|Zxid'
/usr/share/zookeeper/bin/zkCli.sh -server zk2:2181 <<'EOF'
sync /conf
get /conf
EOF
2) 写入失败或无响应
- 现象:set 卡住或失败。
- 排查:检查是否无多数派,或节点间网络异常。
echo stat | nc zk1 2181 | egrep 'Mode|Connections|Zxid'
# 观察是否只有 1 个节点存活,无法形成 quorum
3) 事务日志不一致
- 现象:启动报错或状态不一致。
- 处理:确认 myid、server.X 配置一致,检查磁盘空间与权限。
cat /var/lib/zookeeper/myid
grep '^server\.' /etc/zookeeper/conf/zoo.cfg
df -h /var/lib/zookeeper
练习
1) 在三个节点上分别执行 echo stat | nc <host> 2181,确认一个 Leader 与两个 Follower,并记录 ZXID。
2) 在 Leader 连续 set /conf v1、set /conf v2,在 Follower 执行 get /conf,对比 sync 前后读到的值。
3) 临时停止一个节点(systemctl stop zookeeper),观察写入是否仍能成功;再停止第二个节点,观察写入失败原因并记录现象。
通过上述示例可验证:顺序性由 ZXID 串行化保证,原子性由 Quorum 提交保证,可见性可通过 sync 或读 Leader 提升到线性一致边界。