Zookeeper源码分析(3)- Leader执行流程

本文深入分析Zookeeper中Leader的选举完成后的工作流程,包括创建Leader对象、恢复数据、启动Server、同步Follower、处理LearnerHandler线程交互,以及详解Zookeeper内部的请求处理机制和责任链模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

QuromPeer线程

  1. Leader选举完成之后,Peer确认了自己是Leader的身份,在QuromPeer的主线程中执行Leader的逻辑
  1. 创建Leader对象,并创建Server绑定在QuorumAddress上,用于和其他Follower之间相互通信
  1. 调用Leader::lead函数,执行Leader的真正的逻辑
    1. 调用ZooKeeperServer::loadData,从磁盘中恢复数据和session列表
    2. 启用新的epoch,zookeeper中的zxid64位,用于唯一标示一个操作,zxid的高32位是epoch,每次Leader切换加1,低32位为序列号,每次操作加1
    1. 启动绑定在QuorumAddress上的Server,为每个Follower的连接建立一个LearnerHandler,用于和Follower做交互,这里的逻辑另外单独论述
    1. 向所有的Follower发送一个NEWLEADER包,宣告自己额Leader身份,并在initLimit时间内等待大多数的Follower完成和Leader的同步,并发送ACK包,表示Follower已经和Leader完成同步并可以对外提供服务
    1. 这时LeaderClient之间的交互在cnxnFactoryServer中,LeaderFollower之间的交互在LearnerHandler所属的线程中
    1. 然后调用Leader::lead函数的QuromPeer线程在每个tickTime中都会发送2ping消息给其他的followerfollower在接收到ping消息后会回复一个ping消息,并附带上followersession tracker里的所有session信息,leader收到followerping消息后,根据传回的session信息更新自己的session信息

 

LearnerHandler线程

  1. LearnerHandler主要是处理LeaderFollower之间的交互,和每个Follower连接会维持一个长连接,并有一个单独的LearnerHandler线程和一个Follower进行交互
  2. FollowerLeader建立连接后,会先发一个FOLLOWERINFO包,包含了followerserver id和最近的一个zxid,即peerLastZxid
  1. 根据peerLastZxid来判断如何与Follower进行同步
    1. 如果peerLastZxid大于leader的最新的zxid,则给follower发送trunc包,让follower删掉多出来的事务,一般来说这种情况比较少
    2. 如果peerLastZxid小于leader的最新的zxid,则给follower发送diff包,让follower补齐和leader之间的差距

同步时发送包的顺序如下:

  • NEWLEADER(同步发送)
  • DIFF(同步发送)

以下包的发送在一个线程中异步发送

  • 循环发送写入磁盘的txncommit
  • 循环发送已经commit但还未写入磁盘的toBeApplied数组的txncommit
  • 循环发送已经提出proposal但还未commit的outstandingProposals数组中的txn,注意这里没有发送commit
  1. 为了和follower做快速的同步,leader会在内存中缓存一部分最近的事务,即minCommittedLog和maxCommittedLog之间的事务,如果peerLastZxid比minCommittedLog还小的话,leader就给follower发送一个snap包,把当前leader的镜像发给follower
  1. 同步等待第一个回复的ACK包,然后计算同步超时tickTime*syncLimit,同步的后续的ACK包在下面的循环中处理
  2. 循环处理和follower之间交互的包
    1. ACK包:调用leader.processAck方法,processAck函数的执行逻辑如下:
      1. 如果Ack包的zxid小于Leader的lastCommitted,则忽略
      2. 根据ack包的zxid,在outstandingProposals中找出对应的proposal
      1. ack包对应的followersid加入proposalackset,如果ackset中超过大多数,则表示这个proposal可以commit
      1. 从outstandingProposals中删除这个proposal,并把这个proposal加入到已经可以commit的toBeApplied数组中
      2. follower发送commit包,通知followerproposal提交
    1. PING包:用于和follower同步session信息
    2. REQUEST包:follower转发过来的修改状态的请求,调用ZooKeeperServer::submitRequest方法,这个方法后面单独论述

 

 

NIOServerCnxn::Factory线程

  1. 该线程主要负责serverclient的交互
  1. server是基于select的,当有客户端连接server时,会调用doIO逻辑,这里会把socket上的数据读取出来解析并处理(readPayload函数),并把需要写出的outgoingBuffers写入socket
  1. 如果是刚连接上,则调用readConnectRequest,这里会调用

submitRequest(cnxn,sessionId, OpCode.createSession, 0, to, null);

实际是发起一个创建session的请求

  1. 如果不是第一次连接,则调用readRequest函数,这里会从socket上读出Request数据,然后调用submitRequest

 

我们可以看到来自client的请求和来自其他server的请求都会调用submitRequest函数,这个函数会调用server上的RequestProcessor链,server实现的是责任链模式,每个请求都会经过责任链里所有RequestProcessor的处理

 

对于Leader来说,LeaderZooKeeperServer::setupRequestProcessors设置了Leader用到的责任链,按从前到后的顺序如下:


  • PrepRequestProcessor:创建和修改状态的Request关联的headertxn
  • ProposalRequestProcessor:将写请求发送proposal到所有的follower
  • SyncRequestProcessor:将发出去的proposal批量写入磁盘
  • AckRequestProcessor:当proposal真正写入了磁盘后,向本机发送ack
  • CommitProcessor:匹配本地submitted的请求和收到的committed的请求
  • ToBeAppliedRequestProcessor:把写入到磁盘的proposal从toBeApplied中删除
  • finalProcessor:把commitproposal写入到本机的内存状态中

 

每个RequestProcessor都会有专门的论述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值