11.5.3 ZXID与事务日志的同步机制

ZXID与事务日志的同步机制#

原理草图:ZXID与同步决策#

文章图片

ZXID构成与语义#

ZXID(ZooKeeper Transaction ID)由64位组成,高32位为epoch,低32位为counter。epoch在每次新领导者产生时递增,用于区分不同任期;counter在同一epoch内对事务按序递增,确保全局有序。ZXID天然形成全局递增序列,是一致性判断与数据同步的关键依据。

示例:解析ZXID

ZXID=0x00000002_0000000f
epoch=2
counter=15

事务日志与快照#

每个服务器维护本地事务日志(log)与定期快照(snapshot)。事务日志记录所有已提交事务及其ZXID,快照用于加速恢复。启动时先加载最新快照,再重放快照之后的事务日志以恢复到最新状态。

关键路径与配置

# /etc/zookeeper/zoo.cfg
dataDir=/var/lib/zookeeper
dataLogDir=/var/log/zookeeper
snapCount=100000

查看日志与快照文件

# 查看事务日志与快照
ls -lh /var/log/zookeeper/version-2
ls -lh /var/lib/zookeeper/version-2

# 预期:log.* 为事务日志,snapshot.* 为快照

同步机制与差异对齐#

在同步阶段,Learner(Follower/Observer)向Leader上报自身的最后ZXID。Leader依据ZXID差异选择以下同步方式:
- DIFF:Learner落后不多,Leader直接发送缺失的事务日志。
- TRUNC:Learner日志比Leader“更靠前”,可能是旧Leader产生的事务,需要截断到Leader认可的最后ZXID。
- SNAP:差异过大或日志缺失,Leader下发快照并随后补齐快照后的事务。

同步决策示例(基于日志)

# 观察Leader日志(通常在 /var/log/zookeeper/zookeeper.log)
grep -E "DIFF|TRUNC|SNAP" /var/log/zookeeper/zookeeper.log

# 预期输出示例
# ... Learner received DIFF
# ... Learner received TRUNC
# ... Learner received SNAP

事务日志的广播与提交#

Leader按ZXID顺序提案(proposal),写入本地日志并发送给多数派。多数派确认后,Leader提交事务并广播commit,Follower按ZXID顺序落盘并应用。该流程确保所有节点在同一ZXID序列上推进,避免乱序与分歧。

简单读写验证(观察ZXID递增)

# 写入ZNode
zkCli.sh -server 127.0.0.1:2181 <<'EOF'
create /zxid_test "v1"
set /zxid_test "v2"
get /zxid_test
quit
EOF

# 预期:每次写操作都会产生新的ZXID

命令示例:查询同步状态与节点角色#

# 查询节点角色与同步情况
echo stat | nc 127.0.0.1 2181
echo mntr | nc 127.0.0.1 2181 | egrep "zk_server_state|zk_last_processed_zxid"

# 预期:
# zk_server_state  leader 或 follower
# zk_last_processed_zxid  0x...(持续递增)

排错要点(常见问题)#

  1. Follower频繁SNAP:可能日志滚动过快或dataLogDir缺失
    - 检查dataLogDir是否可写
    - 增大snapCount
  2. TRUNC频繁出现:可能旧Leader产生未提交事务
    - 确保多数派稳定,避免网络抖动
  3. ZXID不递增:可能写请求未达Leader或会话过期
    - 用stat确认Leader
    - 检查客户端是否连接Leader或是否自动转发

排错命令

# 检查dataLogDir权限
ls -ld /var/log/zookeeper
# 查看最近错误
tail -n 100 /var/log/zookeeper/zookeeper.log

一致性保障要点#

  • 全序性:ZXID提供全局顺序,所有事务按ZXID应用。
  • 任期隔离:epoch变化隔离新旧Leader任期,避免旧任期事务被提交。
  • 崩溃恢复:以日志与快照为准对齐到Leader认可的最大ZXID,保证恢复后的状态与集群一致。

练习#

  1. 模拟Follower落后:停掉一个Follower,写入多次数据,启动后观察是否出现DIFF或SNAP。
  2. 修改snapCount为较小值,触发快照频繁生成,观察同步方式变化。
  3. 比较Leader与Follower的zk_last_processed_zxid,确认最终一致。