ZK处理客户端请求流程梳理


一、简介

ZK整体构成包括Leader、Follower、Observer以及客户端,其中Leader、Follower参与Leader竞选,并负责对于写请求进行投票。由于每次写请求,Leader都必须和所有Follower基于类似两阶段提交协议来决定写入是否成功,所以Follower节点不能过多。同时为了提高集群整体的读性能,进而引入了Observer节点。下图描述了从客户端发起一次请求到服务端响应的整个过程(假设客户端此时连接的是Follower节点,相比于连接Leader处理过程更为复杂)

二、读请求处理过程

  1. 客户端向直连的ZK发起一次请求
  2. ZK 服务端启动时候会创建 NIOServerCnxn(3.6版本支持Netty,可以采用NettyServerCnxn),来监听客户端读写请求。收到客户端请求后,经过一系列处理,最终交由 FollowerRequestProcessor 进行处理。(ZK中会有一系列 RequestProcessor,基于Java责任链模式,每个 RequestProcessor 会同时持有下一个待执行的 RequestProcessor。一般每个 RequestProcessor 会缓存一个待处理的请求队列,类似生产者消费者模型:若下一个 RequestProcessor 是耗时操作,当前 RequestProcessor 会把请求提交到下一个 Rrocessor 的队列当中,下一个 RequestProcessor 会有一个线程来轮询处理队列中的请求;若下一个操作是非耗时操作,会直接提交下一个RequestProcessor 进行处理 )
  3. FollowerRequestProcessor 将请求传递给 CommitProcessor,CommitProcessor 判断若是读请求,会直接交由一个线程池调用下一个 FinalRequestProcessor 进行处理。
  4. FinalRequestProcessor 直接查询本地zkDb中的数据,然后返回给客户端。

三、写请求处理过程

  1. (Follower处理)若 CommitProcessor 判断是写请求,会将客户端 request 缓存到叫 pendingRequests的队列,同时将写请求转发给 Leader 节点(Leader 节点会通过 Socket 与所有Follower和Observer建立一个双向通信链接,此时 Follower 会向Leader发送一个 Leader.Request Packet。)
  2. (Leader处理)Leader 节点收到请求Packet后,经过反序列化,最终由 LearnerHandler 将请求传递给 PrepRequestProcessor。对于写请求,会将其转换成对数据存储的操作,并最终由后续Processor进行处理
  3. (Leader处理)PrepRequestProcessor 将请求传递给 ProposalRequestProcessor ,Proposal 会向所有 Follower 发起第一阶段提交协议,即 Proposal 请求,然后调用下一个Processor CommitProcessor进行处理。同时自身也会调用 SyncRequestProcessor ,最终经由 AckRequestProcessor 调用 Leader.processAck 方法,该方法会判断是否有过半节点 ACK(包括leader自身),由于此时只有 Leader 处理成功,暂时不能提交。
  4. (Follower处理)Follower 节点收到 Leader 的Proposal 请求后,交由 SyncRequestProcessor 进行处理,SyncRequestProcessor 提交事务操作和写入快照snapshot后,将请求转发给 SendAckRequestProcessor,SendAckRequestProcessor 会向 Leader 发送 ACK Packet。
  5. (Leader处理)Leader 收到 ACK Packet 后,经过反序列化,最终调用 Leader.processAck 方法进行判断,同上述步骤3中判断,若过半节点 ACK 成功,则会向所有Follower发送二阶段提交请求 Commit,同时向所有 Observer 发送 Inform 请求(方便 Observer 及时更新最新数据)。然后将请求添加到 CommitProcessor 的 commitedRequests队列中,CommitProcessor 最终将请求传递给 FinalRequestProcessor,在 FinalRequestProcessor 中,会完成对 ZKDB数据的更新操作。
  6. (Follower处理)Follower 节点收到 Leader 的 Commit 请求后,经过反序列化后交由 CommitProcessor 进行处理。以上图中的 Follower 1为例,从 pendingRequests 中获取到最初客户端缓存的请求,然后交由 FinalRequestProcessor 进行处理,FinalRequestProcessor 完成 ZKDB 数据更新之后,即可将 response 返回给客户端。对于其他 Follower 节点,只需更新 ZKDB数据即可。
  7. (Observer处理)Observer 收到 Inform Packet 后,待补充

四、可优化点

  1. 当前除正常的写请求以外,所有的创建连接、关闭连接(全局链接,只要有写操作就是全局链接)请求也会转给给 Leader ,然后 Leader 进行两阶段提交。极端情况,若Leader检测到大量链接超时,会向所有 Follower 和 Observer 发起两阶段请求关闭链接(之前出过 case,一个重要原因还是之前 sgagent会直连 zk,导致 leader 节点全局链接过多),导致集群中多个节点不可用。

    改进点:创建连接和关闭连接应该不需要同步给集群中所有节点,只需要同步给指定节点。
  2. 对于所有的写请求,在二阶段提交的时候,都需要由 Leader 将请求同步给所有的 Observer,以 MNS ZK 集群为例,当前有 100多个 Observer,每次写请求 Leader 都需要转发 100多次请求。

    改进点:为了降低 Leader 压力,可以将 Inform 操作交由 Follower 节点。

文章作者: 叶明
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 叶明 !
评论
 上一篇
ZK架构设计与优化 ZK架构设计与优化
ZK,全称为 ZooKeeper,是一个分布式协调服务,由雅虎公司开发并开源。ZK 提供了一个高可用、高性能(Raptor测试链接同机房直连ZK节点Avg耗时0.1ms)、分布式的协调服务,用于解决分布式系统中的一些协调问题,如分布式锁、分布式协调、分布式配置中心、分布式队列等。被广泛地应用于诸如 Hadoop、HBase、Kafka 和 Dubbo 等大型开源分布式系统中。
2023-02-03
下一篇 
MySQL Binlog性能优化 MySQL Binlog性能优化
最近一段时间,一到业务午高峰,外卖集群的一些订阅机器就会出现Binlog消费大量延时。出现Binlog延时的原因主要是:一般11点开始,外卖业务进入中午午高峰,数据库的Binlog QPS会逐渐增加,一旦订阅服务出现性能瓶颈,处理Binlog的能力跟不上Binlog生成的速度,就会导致消费Binlog出现延时,并且延时时间会越来越长。业务在BCP上配置的核对规则一般最小是60s,一旦Binlog延时时间超过60s,那么规则就会大量误告。
2022-04-26
  目录