bigywater.tech
ZooKeeper · 25

ZooKeeper 请求处理链

一个请求进入 ZooKeeper 之后经过哪些环节?与其读源码,不如直接看运行中的线程和 mntr 里每个环节的耗时。这篇用 jstack 和 mntr 把单机、leader、follower 的请求处理链还原出来。

Throttler → Prep → Sync → Final
单机写请求依次经过的线程
fsync 是大头
各环节平均耗时里只有 fsync 达到毫秒级
1
连在 follower 上读 3000 次,leader 多收到的包数

单机的处理链

实测 · 本机执行输出
   ['ConnnectionExpirer', 'ContainerManagerTask', 'NIOServerCxnFactory.AcceptThread', 'NIOServerCxnFactory.SelectorThread-N', 'NIOWorkerThread-N', 'ProcessThread(sid:…)', 'RequestThrottler', 'SessionTracker', 'SyncThread:N']
  3000 次异步写之后的处理链耗时指标(平均,单位见 mntr): {'avg_prep_process_time': '0.0203', 'avg_sync_process_time': '0.002', 'avg_fsynctime': '1.6115', 'avg_proposal_latency': '0.0', 'avg_commit_process_time': '0.0', 'avg_request_throttle_queue_time_ms': '0.0079'}

线程名里的 N 是我把数字替换掉了,避免不同运行之间不同的编号。线程与处理器的对应关系来自 ZooKeeper 的命名:ProcessThread 运行 PrepRequestProcessor,SyncThread 运行 SyncRequestProcessor。

leader 与 follower 的差别

实测 · 本机执行输出
  leader 特有的线程: ['ContainerManagerTask', 'LearnerHandler-/N.N.N.N:N', 'ProcessThread(sid:…)', 'SessionTracker']
  follower 特有的线程: ['FollowerRequestProcessor:N']
  两者共有: ['CommitProcessor:N', 'ConnnectionExpirer', 'ListenerHandler-/N.N.N.N:N', 'NIOServerCxnFactory.AcceptThread', 'NIOServerCxnFactory.SelectorThread-N', 'NIOWorkerThread-N', 'QuorumPeerListener', 'QuorumPeer[myid=N](plain=N.N.N.N:N)(secure=disabled)', 'RecvWorker:N', 'RequestThrottler', 'SendWorker:N', 'SyncThread:N', 'WorkerReceiver[myid=N]', 'WorkerSender[myid=N]']
  leader  : {'avg_prep_process_time': '0.0383', 'avg_sync_process_time': '0.011', 'avg_fsynctime': '3.3333', 'avg_proposal_latency': '0.0', 'avg_commit_process_time': '0.0206', 'avg_request_throttle_queue_time_ms': '0.0'}
  follower: {'avg_prep_process_time': '0.0', 'avg_sync_process_time': '0.0107', 'avg_fsynctime': '3.2154', 'avg_proposal_latency': '0.1599', 'avg_commit_process_time': '0.0326', 'avg_request_throttle_queue_time_ms': '0.0247'}

读在哪里完成

实测 · 本机执行输出
  3000 次读之后 leader 收到的包数增量 1(读在 follower 本地完成,只有少量 ping / 同步包)

分步演示

请求处理链
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。线程名用 jstack 取;耗时来自 mntr(avg_* 指标,单位为毫秒);3 节点伪集群,客户端连在一个 follower 上
    • 没有验证:每个 RequestProcessor 内部的逻辑(没有读源码,第 99–101 篇再看)、Netty 模式、observer 的处理链、CommitProcessor 的并行度参数、指标单位的官方定义
    京ICP备2026067502号-1京公网安备11010502063487号