Zookeeper 源码 集群启动 与 启动时 leader 选举

博文目录


准备

为什么要看源码

1、提升技术功底:学习源码里的优秀设计思想,比如一些疑难问题的解决思路,还有一些优秀的设计模式,整体提升自己的技术功底
2、深度掌握技术框架:源码看多了,对于一个新技术或框架的掌握速度会有大幅提升,看下框架demo大致就能知道底层的实现,技术框架更新再快也不怕
3、快速定位线上问题:遇到线上问题,特别是框架源码里的问题(比如bug),能够快速定位,这就是相比其他没看过源码的人的优势
4、对面试大有裨益:面试一线互联网公司对于框架技术一般都会问到源码级别的实现
5、知其然知其所以然:对技术有追求的人必做之事,使用了一个好的框架,很想知道底层是如何实现的
6、拥抱开源社区:参与到开源项目的研发,结识更多大牛,积累更多优质人脉

看源码方法

1、先使用:先看官方文档快速掌握框架的基本使用
2、抓主线:找一个demo入手,顺藤摸瓜快速静态看一遍框架的主线源码,画出源码主流程图,切勿一开始就陷入源码的细枝末节,否则会把自己绕晕,凭经验猜
3、画图做笔记:总结框架的一些核心功能点,从这些功能点入手深入到源码的细节,边看源码边画源码走向图,并对关键源码的理解做笔记,把源码里的闪光点都记录下来,后续借鉴到工作项目中,理解能力强的可以直接看静态源码,也可以边看源码边debug源码执行过程,观察一些关键变量的值
4、整合总结:所有功能点的源码都分析完后,回到主流程图再梳理一遍,争取把自己画的所有图都在脑袋里做一个整合

下载源码

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

源码导入idea后,org.apache.zookeeper.Version类会报错,需要建一个辅助接口 org.apache.zookeeper.version.Info (.gitignore里忽略了)

package org.apache.zookeeper.version;

public interface Info {
	int MAJOR = 1;
	int MINOR = 0;
	int MICRO = 0;
	String QUALIFIER = null;
	int REVISION = -1;
	String REVISION_HASH = "1";
	String BUILD_DATE = "2020-11-23";
}

找到主类

开源项目找入口类一般都是从启动脚本去找,可以从bin目录下的zkServer.sh或zkServer.cmd里找到启动主类 ZOOMAIN 即 org.apache.zookeeper.server.quorum.QuorumPeerMain

配置参数

在应用目录下创建 /data 目录, 并创建 /2181, /2182, /2183 3个子目录, 在其内新建 myid 文件, 分别填写 1,2,3

复制 zoo_sample.cfg 为 zoo.2181.cfg, 修改 dataDir 为 /data/2181 目录的绝对路径, 注意路径分割符需要使用 / 或者 \

直接运行主类就, 在 Configuration 里面新增一个配置

  • 修改该配置, 命名为 QuorumPeerMain 2181, 在 Program arguments 中把 zoo.2181.cfg 的绝对路径配置进去
  • zookeeper默认使用NIOServerCnxnFactory, 但是推荐使用NettyServerCnxnFactory, 可以配置如下VM参数来启用
    -Dzookeeper.serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory

启动之前需要先将zookeeper-server项目里pom.xml文件里依赖的包(除了jline)的scope为provided这一行全部注释掉

将conf文件夹里的log4j.properties文件复制一份到zookeeper-server项目的 \target\classes 目录下(没有的话先编译下工程),这样项目启动时才会打印日志
在这里插入图片描述

启动服务

启动第一台节点的时候, 会报错, 是因为首次启动, 也会选举leader, 因为其他服务还没启动, 所以第一台连接不到, 所以报错, 正常现象

还有一个报错是 zookeeper admin 启动了一个服务, 用于查看集群状态等配置, 在端口8080, 第一台服务启动后, 其他再次使用8080端口就会报错, 正常现象, 无需理会

理论上, 两台服务启动后, 已经满足大多数(配了3个节点, 1半是1, 大多数是一半加1即2)的条件, 选举将会成功

而且查看日志, 可观察到, 第一台启动的机子是follower, 第二台启动的机子是leader, 第三台启动的机子是follower

客户端连接

bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183

或者使用 客户端 org.apache.zookeeper.ZooKeeperMain, 注意配置参数 -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
在这里插入图片描述
然后在输出的地方直接使用 ls / 等命令即可正常执行

选举架构

在这里插入图片描述

leader 选举

选举周期: 每一个选举周期内会选出来一个leader, 不是发一次选票周期就加1
集群节点数: 配置文件中 server.id 配置的条数
集群选举节点数: 配置文件中 server.id 配置中, participant 配置(非observer配置)的条数
完成选举所需的最小节点数:
Leader节点被选出的判断公式: 某节点获得的选票数 >= 集群选举节点数 / 2 + 1, 注意除法截断小数

集群选举原理

参与集群选举的机器是在配置文件中配置的(observer节点不参与选举, 也不计入投票机器的总数半数中). 整个集群中有过半的机器启动成功即可完成Leader选举, 每一个节点会给所有参与选举的节点发送选票(包括它自己), 所以每一个节点都会拿到每一轮投票期内所有投票节点的所有选票, 选举可能在多轮投票后才会成功, 成功的条件就是某节点获得的选票超过半数. 每一个节点通过每一轮的所有投票自行判断自己该是什么状态(looking,leading,following,observing), 各自的判断都不会冲突

return ((newEpoch > curEpoch) ||
        ((newEpoch == curEpoch) &&
        ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId)))));

每一台节点内部维护着下次发送选票的信息, 包括 serverId:下次投票时选票的节点id, zxid:下次投票时选票的最大事务id, epoch:下次投票时的选举周期, 启动时会初始化serverId=myid, zxid=myMaxZxid, epoch=?, 当接收到的选票比自己维护的选票更新时(即上述判断为true), 把自己维护的选票信息更新一下

第一轮投票(启动时投票), 每台节点一定会提名自己成为leader, 接收到其他节点的投票后, 优先推举maxZxid最大的节点(数据最多)成为leader, 在首次启动的时候, 因为各节点都没有数据, 所以maxZxid都是0, 这时候会推举myid最大的节点成为leader

3节点集群, 先启动两台节点

先启动myid为1的机器, 再启动myid为2的机器, 两台机器成功连接并开始选举

第一轮投票: 1发送(1,0)给1和2, 2发送(2,0)给1和2, 这时1内投给1的票数是1, 投给2的票数是1, 2内投给1的票数是1, 投给2的票数是1, 两个节点的票数都没有超过集群半数(3节点,大多数指的是2), 需要第二轮投票. 因为是首轮投票, zxid都是0, 1发现在maxZxid一致的情况下, 2的id比较大, 所以下一轮计划投(2,0), 2也发现自己的id比较大, 下一轮也投(2,0)

第二轮投票: 1发送(2,0)给1和2, 2发送(2,0)给1和2, 这时1内投给1的票数是0, 投给2的票数是2, 2内投给1的票数是0, 投给2的票数是2, 2的选票数达到了集群半数, 2被选为集群leader, 1则自动成为follower

这时启动myid为3的机器, 仍然是looking状态, 任然会发送选票, 只不过epoch是0, 此时1和2已经不是LOOKING状态了, 都对比发现发现集群已有leader, 所以3自动成为follower

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值