zookeeper选举(一)-相关API分析

1. QuorumCnxManager选举通信管理类

1.1 作用

  • 管理与集群中其他节点的连接
  • 选举通信的通道

1.2 核心内部类

  • Listener
  1. QuorumCnxManager初始化时创建
  2. 创建ServerSocket对象绑定选举port(2888端口), 用来接收其他节点的选票
  3. accept其他节点的socket后, 读取sid为其创建SendWorker和RecvWorker对象, 将SendWorker放到this.senderWorkerMap中管理, 创建对应的消息发送队列ArrayBlockingQueue放到this.queueSendMap管理. 同时启动创建的SendWorker和RecvWorker线程
  4. 因为Socket对象可读可写, 既可发送选票信息也可接收选票信息. 所以初始化连接时做了优化, 两个节点节点直连只维护sid单向连接(sid小的作为server)
  • RecvWorker
    接收指定节点选票信息的线程
    Long sid;//只接收该sid节点的消息
    Socket sock;//该sid节点的连接
    final DataInputStream din;//该sid节点的连接
    final QuorumCnxManager.SendWorker sw;//该RecvWorker对应的SendWorker
    核心功能:阻塞读取对应节点连接的选票信息放到recvQueue队列
    所有RecvWorker接收到的选票信息都放在同一个recvQueue队列

  • SendWorker
    给指定节点发送选票信息的线程

  1. 从this.queueSendMap.get(this.sid)各自的队列获取选票消息并发送出去
  2. 维护this.lastMessageSent.put(this.sid, b)
  3. 通过维护的流对象发送选票信息
    不同的节点对应不同的RecvWorker队列, 通过各自的流发消息.
  • Message
    接收到的其他节点选票信息的抽象(原始消息只有buffer没有sid)
    ByteBuffer buffer;//消息内容(包含length+消息字节数组)
    long sid;//消息来源或目的节点sid

  • QuorumConnectionReceiverThread
    Listener异步方式创建SendWorker和RecvWorker的执行任务
    final Socket sock;//Socket对应节点的sid
    final Long sid;//sid

  • QuorumConnectionReqThread
    Listener异步方式创建SendWorker和RecvWorker的执行任务
    final Socket sock;//Socket对应节点的sid
    final Long sid;//sid

1.3 核心属性

  • mySid
    final long mySid, 当前节点的sid. 从myid配置文件中读取
  • view
    Map<Long, QuorumServer> view, zoo.cnf配置文件中的集群配置
  • senderWorkerMap
    ConcurrentHashMap<Long, QuorumCnxManager.SendWorker>
    当前节点需发送到其他节点的选票信息发送线程, 内部封装流对象
  • queueSendMap
    ConcurrentHashMap<Long, ArrayBlockingQueue>
    当前节点需发送到其他节点的选票信息
  • lastMessageSent
    ConcurrentHashMap<Long, ByteBuffer> lastMessageSent
    维护当前节点需发送到其他节点的当前最新消息
  • recvQueue
    <QuorumCnxManager.Message> recvQueue, 接收到的其他节点发送的选票信息队列
  • connectionThreadCnt
    异步方式创建的SendWorker和RecvWorker的数量和
    AtomicInteger connectionThreadCnt
    所有节点全部存活的情况下, 该数量也小于所有节点数量*2, 因为Listener创建连接时有单向连接的优化.
  • threadCnt
    同步方式创建的SendWorker和RecvWorker的数量和
    AtomicInteger threadCnt
    所有节点全部存活的情况下, 该数量也小于所有节点数量*2, 因为Listener创建连接时有优化.
  • connectionExecutor
    ThreadPoolExecutor connectionExecutor
    异步方式创建SendWorker和RecvWorker的执行线程池

1.4 重点方法

  • toSend (Long sid, ByteBuffer b)
    1.本节点需发送到其他节点的选票信息添加到对应sid的队列ArrayBlockingQueue
    2.若目的sid是本机, 则直接放到recvQueue队列
    3.若该sid与当前节点无连接, 则创建连接并初始化相关对象
    toSend方法描述

2. FastLeaderElection选举leader类

2.1 功能

单一节点视觉的leader选举抽象
负责选举过程及选举状态维护

2.2 核心内部类

  • Messenger
    选举时选票信息处理对象, 内部维护了一个WorkerSender和WorkerReceiver线程
    FastLeaderElection.Messenger.WorkerSender ws;
    FastLeaderElection.Messenger.WorkerReceiver wr;

  • WorkerSender
    选举时当前节点需发出的选票信息处理线程.
    职责是从this.sendqueue队列里取出选票信息, 调用manager的toSend方法发送选票信息. 将选票信息对象格式转换成字节格式发出

  • WorkerReceiver
    选举时选票信息接收处理线程, 从manager.pollRecvQueue获取消息,
    1.将接收的字节格式选票信息转换成内部Notification对象格式
    2.若当前节点是LOOKING状态, 则把选票放到recvqueue队列
    3.若当前节点和投票人节点均是LOOKING状态且投票人节点周期小于当前节点, 则将当前节点的推选人信息发送到sendqueue队列
    4.若当前节点不是LOOKING状态但消息来源节点是LOOKING状态, 将当前节点已选定的leader信息放到sendqueue队列

总结:
当收到选票信息时WorkerReceiver逻辑:
1.当前节点为LOOKING状态时, 无脑接收投票人节点选票
2.当前节点非LOOKING状态, 投票人为LOOKING时, 无脑发送LEADER信息
3.双方节点均为LOOKING状态时, 届期大的节点向对端节点发送推选人信息

  • ToSend
    选举时需要发到其他节点选票信息对象格式
    long leader;//推选节点id
    long zxid;//候选节点事务id
    long electionEpoch;//当前选举周期
    ServerState state;//当前发送节点的状态
    long sid;//当前发送节点sid
    long peerEpoch;//当前发送节点周期

  • Notification
    选举时接收到其他节点的选票信息对象格式
    int version;//数据版本
    long leader;//推选节点id
    long zxid;//推选节点事务
    long electionEpoch;//推选节点周期
    ServerState state;//消息发送者的状态
    long sid;//消息发送者等待sid
    long peerEpoch;//消息发送者的周期

2.3 核心属性

  • manager
    QuorumCnxManager manager;//选举通信管理对象
  • sendqueue
    LinkedBlockingQueue<FastLeaderElection.ToSend>
    当前节点选举时需要发送出的选票信息队列
  • recvqueue
    LinkedBlockingQueue<FastLeaderElection.Notification> recvqueue;
    当前节点选举时从其他节点接收到的选票信息对象格式
  • self
    QuorumPeer self;当前选举参与者节点
  • messenger
    FastLeaderElection.Messenger messenger;//当前选举选票处理对象
  • logicalclock
    AtomicLong logicalclock = new AtomicLong();
    当前节点视觉的选举周期
  • proposedLeader
    long proposedLeader;//当前节点推选人节点(选票)的sid
  • proposedZxid
    long proposedZxid;//当前节点推选人节点(选票)的事务id
  • proposedEpoch
    long proposedEpoch;//当前节点推选人节点(选票)的周期

2.4 核心方法

  • 构造方法-初始化
    1.初始化推选人节点的信息
    2.初始化选票信息队列
    3.初始化选票信心处理生产/消费线程

  • buildMsg
    根据选举时选票信息对象格式构建字节格式选票信息
    在这里插入图片描述
    在这里插入图片描述

  • Vote lookForLeader()真实选举过程
    投票过程中的两个核心选票容器
    HashMap<Long, Vote> recvset = new HashMap();
    投票箱A. 接收两类选票:
    1.投票人节点为LOOKING状态且选票周期不小于当前周期的选票
    2.投票人节点状态为FOLLOWING/LEADING且选票周期等于当前周期的选票
    HashMap<Long, Vote> outofelection = new HashMap();
    投票箱B. 仅接收状态为FOLLOWING/LEADING的投票人节点(任何周期)的选票

投票结束的条件:
1.超过一半的节点的选票为同一个节点且200ms内没有新的选票
2.先判断投票箱A, 再判断投票箱B
核心选举流程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • sendNotifications
    将当前节点的选票信息形成消息放入sendqueue队列,在集群内广播

在这里插入图片描述

3. QuorumPeer选举参与者

3.1 功能

集群节点的抽象
管理服务端口, 维护节点状态
管理选举端口, 维护自动选举流程

3.2 核心内部类

  • ResponderThread
    交流leader信息的线程.
    通过3888端口发送UDP包, 和其他节点交流leaderId和zxid. 已经弃用

  • LearnerType
    节点类型枚举
    PARTICIPANT,//参与选举者的节点
    OBSERVER;//不参与选举的节点

  • ServerState
    选举参选者的状态枚举
    LOOKING,//选举状态所有节点的状态(包括所有类型的节点)
    FOLLOWING,//具有参选权且当前节点是从节点时的状态
    LEADING,// 具有参选权且当前节点是主(leader)节点时的状态
    OBSERVING;//不具有参选权且当前节点是从节点时的状态(提高选过程)

  • QuorumServer
    选举时的节点对象
    public InetSocketAddress addr;
    public InetSocketAddress electionAddr;
    public String hostname;
    public int port = 2888;
    public int electionPort = -1;
    public long id;
    public QuorumPeer.LearnerType type;

3.3 核心属性

private QuorumPeer.LearnerType learnerType;//当前节点类型
private long myid;//当前节点的sid
private volatile Vote currentVote;//当前已选定的主节点
//参与选举的所有节点,从配置文件中读取
protected Map<Long, QuorumPeer.QuorumServer> quorumPeers;
private QuorumPeer.ServerState state;//当前节点选举状态
DatagramSocket udpSocket;//3888端口各节点交流leader信息的通道
Election electionAlg;//选举对象,默认为FastLeaderElection
public Leader leader;//选出来的leader
public Follower follower;//当前节点状态对应的对象,状态失效置为null
public Leader leader; //当前节点状态对应的对象,状态失效置为null
public Observer observer; //当前节点状态对应的对象,状态失效置为null

3.4 核心方法

  • 初始化
    先初始化为LOOKING状态

  • start方法
    1.初始化数据
    2.初始化服务端口
    3.初始化选举对象并启动
    4.启动选举流程
    在这里插入图片描述

  • createElectionAlgorithm选举初始化
    1.创建选举连接对象
    2.启动选举连接外部消息相关线程
    3.初始化选举端口, 监听其他节点的消息. 启动消息接收/发送线程
    4.启动选举状态下的内部格式消息处理线程
    在这里插入图片描述

  • run方法启动选举流程
    轮询当前节点状态, 根据状态不同
    1.LOOKING:调用FastLeaderElection的lookForLeader方法完成选举
    2.LEADING:创建Leader对象阻塞调用其lead方法, 直到状态失效更新为LOOKING
    3.FOLLOWING:创建Follower对象阻塞调用其followLeader方法, 直到状态失效更新为LOOKING
    4.OBSERVING:创建Observer对象阻塞调用其observeLeader方法, 直到状态失效更新为LOOKING

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值