上一篇介绍了zookeeper的单机启动,集群模式下启动和单机启动有相似的地方,但是也有各自的特点。集群模式的配置方式和单机模式也是不一样的,这一篇主要包含以下内容:

  • 概念介绍:角色,服务器状态

  • 服务器组件启动

  • leader选举

概念介绍:角色,服务器状态

集群模式会有多台server,每台server根据不同的角色会有不同的状态,server状态的定义如下

public enum ServerState {
LOOKING, FOLLOWING, LEADING, OBSERVING;
}

LOOKING:表示服务器处于选举状态,说明集群正在进行投票选举,选出leader

FOLLOWING:表示服务器处于following状态,表示当前server的角色是follower

LEADING:表示服务器处于leading状态,当前server角色是leader

OBSERVING:表示服务器处于OBSERVING状态,当前server角色是OBSERVER

对应server的角色有:

leader

投票选出的leader,可以处理读写请求。处理写请求的时候收集各个参与投票者的选票,来决出投票结果

follower

作用:

  1. 参与leader选举,可能被选为leader
  2. 接收处理读请求
  3. 接收写请求,转发给leader,并参与投票决定写操作是否提交

observer

为了支持zk集群可扩展性,如果直接增加follower的数量,会导致投票的性能下降。也就是防止参与投票的server太多,导致leader选举收敛速度较慢,选举所需时间过长。

observer和follower类似,但是不参与选举和投票,

  1. 接收处理读请求
  2. 接收写请求,转发给leader,但是不参与投票,接收leader的投票结果,同步数据

这样在支持集群可扩展性的同时又不会影响投票的性能

服务器组件启动

集群模式下服务器启动的组件一部分和单机模式下类似,只是启动的流程和时机有所差别

  • FileTxnSnapLog
  • NIOServerCnxnFactory
  • Jetty

也是会启动上面三个组件,但是因为集群模式还有其他组件需要启动,所以具体启动的逻辑不太一样。

除了上面这些组件外,集群模式下还有一些用来支撑集群模式的组件

  • QuorumPeer:用来启动各个组件,是选举过程的mainloop,在loop中判断当前server状态来决定做不同的处理
  • FastLeaderElection:默认选举算法
  • QuorumCnxManager:选举过程中的网络通信组件

QuorumPeer

解除出来的QuorumPeerConfig配置都设置到QuorumPeer对应的属性中,主线程启动完QuorumPeer后,调用该线程的join方法等待该线程退出。

QuorumCnxManager

负责各个server之间的通信,维护了和各个server之间的连接,下面的线程负责与其他server建立连接

org.apache.zookeeper.server.quorum.QuorumCnxManager.Listener

还维护了与其他每个server连接对应的发送队列,SendWorker线程负责发送packet给其他server

final ConcurrentHashMap<Long, ArrayBlockingQueue<ByteBuffer>> queueSendMap;

这个map的key是建立网络连接的server的myid,value是对应的发送队列。

还有接收队列,RecvWorker是用来接收其他server发来的Message的线程,将收到的Message放入队列中

org.apache.zookeeper.server.quorum.QuorumCnxManager#recvQueue

leader选举

选举入口在下面的方法中

org.apache.zookeeper.server.quorum.FastLeaderElection#lookForLeader

判断投票结果的策略

上面这个是其中的一种选举算法,选举过程中,各个server收到投票后需要进行投票结果抉择,判断投票结果的策略有两种

// 按照分组权重
org.apache.zookeeper.server.quorum.flexible.QuorumHierarchical // 简单按照是否是大多数,超过参与投票数的一半
org.apache.zookeeper.server.quorum.flexible.QuorumMaj

选票的网络传输

zookeeper中选举使用的端口和正常处理client请求的端口是不一样的,而且由于投票的数据和处理请求的数据不一样,数据传输的方法也不一样。选举使用的网络传输相关的类和数据结构如下

选举过程

  • 各自初始化选票

    • proposedLeader:一开始都是选举自己,myid

      • proposedZxid:最后一次处理成功的事务的zxid
      • proposedEpoch:上一次选举成功的leader的epoch,从currentEpoch 文件中读取
  • 发送自己的选票给其他参选者

  • 接收其他参选者的选票

    • 收到其他参选者的选票后会放入recvqueue,这个是阻塞队列,从里面超时获取

      • 如果超时没有获取到选票vote则采用退避算法,下次使用更长的超时时间

      • 校验选票的有效性,并且当前机器处于looking状态,开始判断是否接受

        • 如果收到的选票的electionEpoch大于当前机器选票的logicalclock

            • 进行选票pk,收到的选票和本机初始选票pk,如果收到的选票胜出则更新本地的选票为收到的选票

                • pk的算法

                    • org.apache.zookeeper.server.quorum.FastLeaderElection#totalOrderPredicate

                      • 选取epoch较大的
                      • 如果epoch相等则取zxid较大的
                      • 如果zxid相等则取myid较大的
              • 如果本机初始选票胜出则更新为当前机器的选票

              • 更新完选票之后重新发出自己的选票

        • 如果n.electionEpoch < logicalclock.get()则丢弃选票,继续准备接收其他选票
        • 如果n.electionEpoch == logicalclock.get()并且收到的选票pk(pk算法totalOrderPredicate)之后胜出

            • 更新本机选票并且,发送新的选票给其他参选者
          • 执行到这里,说明收到的这个选票有效,将选票记录下来,recvset

          • 统计选票

            • org.apache.zookeeper.server.quorum.FastLeaderElection#getVoteTracker

              • 看看已经收到的投票中,和当前机器选票一致的票数
          • 判断投票结果

            • org.apache.zookeeper.server.quorum.SyncedLearnerTracker#hasAllQuorums

              • 根据具体的策略判断

                • QuorumHierarchical

                  • QuorumMaj,默认是这个

                    • 判断投该票的主机数目是否占参与投票主机数的大部分,也就是大于1/2
              • 如果本轮选举成功

                • 如果等finalizeWait时间后还没有其他选票的时候,就认为当前选举结束

                  • 设置当前主机状态
                  • 退出本轮选举

选举的整个流程为

总结

集群启动过程其实就是在单机启动的部分基础上,增加了关于集群的一些组件,而且有leader的选举。

zookeeper源码 — 二、集群启动—leader选举的更多相关文章

  1. ZooKeeper集群与Leader选举

    说说你对ZooKeeper集群与Leader选举的理解?   ZooKeeper是一个开源分布式协调服务.分布式数据一致性解决方案.可基于ZooKeeper实现命名服务.集群管理.Master选举.分 ...

  2. Dubbo 源码分析 - 集群容错之 LoadBalance

    1.简介 LoadBalance 中文意思为负载均衡,它的职责是将网络请求,或者其他形式的负载"均摊"到不同的机器上.避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况.通 ...

  3. Dubbo 源码分析 - 集群容错之 Router

    1. 简介 上一篇文章分析了集群容错的第一部分 -- 服务目录 Directory.服务目录在刷新 Invoker 列表的过程中,会通过 Router 进行服务路由.上一篇文章关于服务路由相关逻辑没有 ...

  4. Dubbo 源码分析 - 集群容错之 Cluster

    1.简介 为了避免单点故障,现在的应用至少会部署在两台服务器上.对于一些负载比较高的服务,会部署更多台服务器.这样,同一环境下的服务提供者数量会大于1.对于服务消费者来说,同一环境下出现了多个服务提供 ...

  5. zookeeper源码 — 三、集群启动—leader、follower同步

    zookeeper集群启动的时候,首先读取配置,接着开始选举,选举完成以后,每个server根据选举的结果设置自己的角色,角色设置完成后leader需要和所有的follower同步.上面一篇介绍了le ...

  6. zookeeper源码 — 一、单机启动

    zookeeper一般使用命令工具启动,启动主要就是初始化所有组件,让server可以接收并处理来自client的请求.本文主要结构: main入口 配置解析 组件启动 main入口 我们一般使用命令 ...

  7. ZK集群的Leader选举源码阅读

    前言 ZooKeeper对Zab协议的实现有自己的主备模型,即Leader和learner(Observer + Follower),有如下几种情况需要进行领导者的选举工作 情形1: 集群在启动的过程 ...

  8. Dubbo源码学习--集群负载均衡算法的实现

    相关文章: Dubbo源码学习文章目录 前言 Dubbo 的定位是分布式服务框架,为了避免单点压力过大,服务的提供者通常部署多台,如何从服务提供者集群中选取一个进行调用, 就依赖Dubbo的负载均衡策 ...

  9. Dubbo 源码分析 - 集群容错之 Directory

    1. 简介 前面文章分析了服务的导出与引用过程,从本篇文章开始,我将开始分析 Dubbo 集群容错方面的源码.这部分源码包含四个部分,分别是服务目录 Directory.服务路由 Router.集群 ...

随机推荐

  1. MySQL 忘记root密码解决方法,基于Ubuntu 14.10

    忘记MySQL root密码解决方法,基于Ubuntu 14.10 忘了mysql密码,从网上找到的解决方案记录在这里. 编辑mysql的配置文件/etc/mysql/my.cnf,在[mysqld] ...

  2. Hbase出现ERROR: Can't get master address from ZooKeeper; znode data == null正确找到解决思路

    第一次配置时出现这样的错误,也很懵的,到处上网找博客看资料,都试了个遍,但是问题还是存在,以下这些博客写的或许是解决一类问题的方式. https://blog.csdn.net/whbo111/art ...

  3. Python3实现ICMP远控后门(上)_补充篇

    ICMP后门(上)补充篇 前言 在上一篇文章Python3实现ICMP远控后门(上)中,我简要讲解了ICMP协议,以及实现了一个简单的ping功能,在文章发表之后,后台很多朋友留言,说对校验和的计算不 ...

  4. CSS——LESS【转】

    原文链接:http://www.w3cplus.com/css/less 去年就初次接触了LESS,并用他制作了一个Less.org的首页页面,但由于CSS的固有模式,没有让自己喜欢上他.由于前段时间 ...

  5. 洛谷 P1430 解题报告

    P1430 序列取数 题目描述 给定一个长为\(n\)的整数序列\((n<=1000)\),由\(A\)和\(B\)轮流取数(\(A\)先取).每个人可从序列的左端或右端取若干个数(至少一个), ...

  6. CentOS在线安装RabbitMQ3.7

    一.通过yum命令在线安装RabbitMQ yum在线安装,简单.快捷.自动安装相关依赖包. 1.安装Erlang环境(RabbitMQ由Erlang语言开发) 1.1)下载rpm安装包 官方地址:h ...

  7. C语言 > 字符串和字符串函数

    输入 gets() 函数 : 1.gets() 从标准输入设备读取字符串,以回车结束读取,使用'\0'结尾,回车符'\n'被舍弃没有遗留在缓冲区. 2.可以用来输入带空格的字符串. 3.可以无限读取, ...

  8. ES6 中的 iterator

    [简介] 遍历器/迭代器.任何数据结构只要部署 Iterator 接口,就可以完成遍历操作.这种数据结构是“可遍历的”(iterable). 如何判断是否可遍历? typeof target[Symb ...

  9. 敏捷(Agile)——“说三道四”

    可以这么理解:一种以人为本.团队合作.快速响应变化和可工作的软件作为宗旨的开发方法.亦可理解为在一个高度协作的环境中,不断地使用反馈进行自我调整和完善,持续交付用户想要的软件的过程.敏捷开发提倡通过多 ...

  10. Unity3D学习(一):简单梳理下Unity跨平台的机制原理

    前言 首先需要了解的是,Unity3D的C#基础脚本模块是通过Mono来实现的. 什么是Mono? 参考下百度百科:Mono是一个由Novell公司(由Xamarin发起)主持的项目,并由Miguel ...