一个请求进入 ZooKeeper 之后经过哪些环节?与其读源码,不如直接看运行中的线程和 mntr 里每个环节的耗时。这篇用 jstack 和 mntr 把单机、leader、follower 的请求处理链还原出来。
['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 特有的线程: ['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 / 同步包)