【Zookeeper专题】Zookeeper选举Leader源码解析
目录
- 前言
- 阅读建议
- 课程内容
- 一、ZK Leader选举流程回顾
- 二、源码流程图
- 三、Leader选举模型图
- 学习总结
前言
为什么要看源码?说实在博主之前看Spring源码之前没想过这个问题。因为我在看之前就曾听闻大佬们说过【JavaCoder三板斧:Java,Mysql,Spring】,所以我抱着积极的学习心态去看的。另外,我也发现了一个很有意思的现象:就是我们一群人在学习,但是每个人学习的【偏好】似乎是不一样的,或者说关注的重点不一样。所以,其实我也不知道自己关注的重点到底对不对,但总归是有收获的。
现在回过头来再看ZK源码,有必要学习吗?一开始我是觉得没必要的,因为不少人说ZK源码写的很抽象、不规范,但还是有人坚持说学习一下比较好。现在稍微学习了一小段之后,我突然间有点感悟:ZK源码还是值得学习阅读的,甚至所有市面上以Java编写的分布式中间件都值得学习。为什么呢?
首先,ZK服务端是以Java编写出来的程序,所以,我们在阅读ZK源码的时候,何尝不是一种进步呢?(咱可是直接在看行业大拿的源码啊)
其次,也可能是最重要的,如果我们想成为一个优秀的JavaCoder,甚至是架构师,这确实是一条必经之路,毕竟这些成熟、优秀的产品架构,肯定能让你学到很多东西(修炼内功);
还有啊,这些成熟、优秀的源码,难道不值得学习吗?这或许是世界上,Java里面最牛逼的源码之一了!
以上是我的一些思考。
同样,这个问题,我的老师也给出了他们的答案,在这里分享给大家:
Q1:为什么要学习源码?
答:
- 提升技术功底:学习源码里的优秀设计思想,比如一些疑难问题的解决思路,还有一些优秀的设计模式,整体提升自己的技术功底
- 深度掌握技术框架:源码看多了,对于一个新技术或框架的掌握速度会有大幅提升,看下框架demo大致就能知道底层的实现,技术框架更新再快也不怕
- 快速定位线上问题:遇到线上问题,特别是框架源码里的问题(比如bug),能够快速定位,这就是相比其他没看过源码的人的优势
- 对面试大有裨益:面试一线互联网公司对于框架技术一般都会问到源码级别的实现
- 知其然知其所以然:对技术有追求的人必做之事,使用了一个好的框架,很想知道底层是如何实现的
- 拥抱开源社区:参与到开源项目的研发,结识更多大牛,积累更多优质人脉
阅读建议
看源码方法:
- 先使用:先看官方文档快速掌握框架的基本使用
- 抓主线:找一个demo入手,顺藤摸瓜快速静态看一遍框架的主线源码,画出源码主流程图,切勿一开始就陷入源码的细枝末节,否则会把自己绕晕。实在看不懂的凭经验猜
- 画图做笔记:总结框架的一些核心功能点,从这些功能点入手深入到源码的细节,边看源码边画源码走向图,并对关键源码的理解做笔记,把源码里的闪光点都记录下来,后续借鉴到工作项目中,理解能力强的可以直接看静态源码,也可以边看源码边debug源码执行过程,观察一些关键变量的值
- 整合总结:所有功能点的源码都分析完后,回到主流程图再梳理一遍,争取把自己画的所有图都在脑袋里做一个整合
课程内容
我跟着老师看了一下源码,说实在,思考了很久实在不知道怎么给大家伙记下来分享给大家,有点无从下手的感觉,因为相关性太大了。所以,这里算是自结吧,主要是为了加深个人理解,以及方便后续回头看。
一、ZK Leader选举流程回顾
我在之前的笔记当中有写过选举原理,但是有点囫囵吞枣,后来才知道原来这个挺重要的,算是ZK比较重点的内容之一。现在这里重新讲解一番。
什么是Leader选举
ZooKeeper的Leader选举过程是基于投票和对比规则的,确保集群中选出一个具有最高优先级的服务器作为Leader来处理客户端请求,以及同步数据给集群中的其他节点。
选举规则
选举投票对比规则如下:
- 首先比较epoch,选取具有最大epoch的服务器。epoch用于区分不同的选举轮次,每次重新选举时都会增加epoch。
- 如果epoch相同,则比较zxid(事务ID),选取事务ID最大的服务器。zxid表示最后一次提交的事务ID。
- 如果zxid也相同,则比较myid(服务器ID),选取服务器ID最大的服务器。
epoch
:表示ZooKeeper服务器的逻辑时期(logical epoch),它是一个相对时间的概念,用于区分不同的Leader选举周期。
zxid
:是一个64位的整数,由高32位的epoch和低32位的counter组成。
counter
:是一个在每个时期(epoch)内递增的计数器,用于标识事务的顺序。
选举流程
首先得说明的是,ZK的Leader选举是分两步的,所以又叫:两阶段选举。为什么需要两个阶段?接下来我们看一下流程,这个流程是我们网上能搜索到的,大家都清楚的流程:(流程按照上面的模型图。即:假设集群中有3个节点,并且只启动了2个节点,第3个节点没启动)
- ZK集群刚启动的时候,由于他们仍未经历过选举,所以每一台ZK机器中,上面投票规则提到的
epoch
肯定是一样的,包括zxid
,毕竟还没有接受过客户端的读写,所以唯一的差异就在myId
上了 - 开始第一阶段选举:由于彼此还不知道谁的
epoch
、zxid
、myId
,所以会优先将票投给自己,并且广播出去;当然也能接收到别的服务器【投票自己的广播】。所以,myid=1
的机器按照投票规则,投票vote=(1, 0)
,并且收到myid=2
的投票vote=(2, 0)
;同时myid=2
的机器按照投票规则,投票vote=(2, 0)
,并且收到myid=1
的投票vote=(1, 0)
。显然,目前投票情况是服务1跟服务2各收到一张选票,所以Leader没办法选举出来 - 第二阶段选举:每个节点服务器收到投票广播后,按照投票选举规则,各自更新自己最新的投票。比如:
myid=1
的服务器经过比较之后,发现myid=2
比自己更适合当Leader,于是在第二轮投票的时候投票vote=(2,0)
;而myid=2
的服务也经过比较之后,觉得还是自己适合做Leader,于是在第二轮投票的时候投票vote=(2,0)
。就这样,myid=2
的服务收到了2张选票,2 > (3/2)
,符合【过半机制】,于是成为了Leader
- 接着
myid=3
的节点上线,发现已经有Leader了,那不用投票了,直接把自己置为Follower(也许有人问,为什么不重新选举?因为没必要啊,对于ZK集群来说,尽快对外服务才是重点,重新选举不是浪费时间嘛)
OK,流程回顾就到这里。相信大伙通过这个业务流程去理解代码,将会事半功倍。
二、源码流程图
说明:我估计很多人源码入口都找不到,给大家一个方法,也是很多源码阅读的办法。那就是从启动脚本找,比如ZK,我们知道它的启动脚本为zkServer.sh
,那就在里面找好了。
ZK源码入口类:org.apache.zookeeper.server.quorum.QuorumPeerMain
。
下面是是一个自结的源码流程图,不是很好看。感兴趣的大伙,可以跟着我的流程图看一遍源码
看完选举源码之后的一些总结与思考:
- 【总结】比较清晰的了解,为什么是二阶段选举,因为ZK在设计投票与选举的时候,是使用两个独立的业务领域类(独立的线程)来完成的(投票决策领域类 + 投票发送/接受领域类),也就是说,他们的数据并非是直接耦合在一起的(我描述的比较抽象,咱也不知道该怎么解释了)。
- 【总结】在投票、选举中,ZK新建了好几个业务线程,往往是,一个业务领域类本身就是一个线程子类,然后在
run
方法中实现各自领域的逻辑。每个线程通常各自维护了一条阻塞队列,线程之间交换数据是将消息发送至对应的阻塞队列中。也许,这就是JVM级别,不基于中间件的线程通信的可靠手段之一吧 - 【思考】Leader节点与Follower节点,节点之间投票都分别监听了独立的端口,使用独立的scoket进行通信交互。其实前者Leader节点与Follower节点数据同步采用socket长连接保持通信我是能理解的,但是选举方面,我发现这个需求本来就不是特别大,为什么也要用socket通信呢?为什么不是http?别笑我哈,我一直以为socket比起http是一种比较重度的通信手段。现在看来可能跟我想象的不一样。
sockert
是传输层协议,http
是应用层协议,且两者安全性方面前者更高。下面是来自gpt的回答:
- 【总结】BIO网络连接在简单的应用通信之间,还是很可靠的,人家ZK都这么玩
三、Leader选举模型图
接下来再给大家画一下,选举的相关模型图。
整个zookeeper选举底层可以分为【选举逻辑层】和【选举消息传输层】,【逻辑层】有自己的队列统一接收和发送选票,【传输层】也设计了自己的队列,但是按发送的机器分了队列,避免给每台机器发送消息时相互影响,比如某台机器如果出问题发送不成功则不会影响对正常机器的消息发送。
学习总结
- 学习了ZK底层选举源码,学习像JUC,阻塞队列、网络通信在这种优秀应用中的使用思路
- 学习了ZK源码设计思想。其实我看着很像是DDD的领域设计
相关文章:

【Zookeeper专题】Zookeeper选举Leader源码解析
目录 前言阅读建议课程内容一、ZK Leader选举流程回顾二、源码流程图三、Leader选举模型图 学习总结 前言 为什么要看源码?说实在博主之前看Spring源码之前没想过这个问题。因为我在看之前就曾听闻大佬们说过【JavaCoder三板斧:Java,Mysql&a…...

机器学习之自训练协同训练
前言 监督学习往往需要大量的标注数据, 而标注数据的成本比较高 . 因此 , 利用大量的无标注数据来提高监督学习的效果有着十分重要的意义. 这种利用少量标注数据和大量无标注数据进行学习的方式称为 半监督学习 ( Semi…...
ubuntu 通过apt-get快速安装 docker
在使用 apt-get 安装 Docker 之前,你需要确保你的系统已经准备好并且已经更新了软件包列表。以下是在 Ubuntu 系统上使用 apt-get 安装 Docker 的步骤: 更新软件包列表: sudo apt-get update 安装依赖软件包,以确保可以通过 HTTPS 使用存储库: sudo apt-get install apt-t…...

C++医院影像科PACS源码:三维重建、检查预约、胶片打印、图像处理、测量分析等
PACS连接DICOM接口的医疗器械(如CT、MRI、CR、DR、DSA、各种窥镜成像系统设备等),实现图像无损传输,实现DICOM胶片打印机回传打印功能,支持各种图像处理,可以进行窗技术调节,与登记台管理系统共…...
企业聊天应用程序使用 Kubernetes
1. 客户端-服务器工作流程 客户端:在我们的架构中,客户端可以分为三种类型:iOS 和 Android 移动应用程序以及 Web 聊天。移动应用程序首先通过 API 网关服务与服务器进行通信,其中客户端会生成一个访问令牌,该令牌将授…...

记录用命令行将项目打包成war包
记录用命令行将项目打包成war包 找到项目的pom.xml 在当前路径下进入cmd 输入命令 mvn clean package 发现报错了 Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.2:war (default-war) on project MMS: Error assembling WAR: webxml attribute is req…...
Linux基础知识笔记
Linux基础知识笔记 介绍/dev/null作用2>&1作用 介绍 记录linux基础知识,持续更新中… /dev/null作用 /dev/null 是一个特殊的设备文件,可以将数据重定向到这个文件中,从而实现将输出或错误信息丢弃的效果。在 Linux 系统中…...

Laya3.0 入门教程
点击play箭头 点击右边的开发者工具 就会弹出 chrome的调试窗口 然后定位到你自己的ts文件 直接在ts里断点即可 不需要js文件 如何自动生成代码? 比如你打开一个新项目 里面显示的是当前场景 只需要点击 UI运行时 右边的框就可以了 他会自动弹窗提示你 创建一个文…...

3D全景虚拟样板间展销系统扩展用户市场范围
VR样板间,能够真实还原现场,定制需要的场景。让一切比真实更真实。用户可以720度看房,自由行走在空间里,直观感受各空间的大小,看到自己家中的“未来样子”,同时通过操控手柄,控制整个智能家居系…...
如何编写lua扩展库
很多人都听过lua,也见过lua脚本,但可能不理解为什么lua脚本里面会有这么多没见过的函数, 而且这些函数功能是如此强大,能上天入地,无所不能 其实这些函数并不是lua自带的,都是由程序作者造出来的隐藏在了他们的主程序里 一般运行lua脚本,我们会使用自带的解释器,当你拿到一份…...

Java List 中存不同的数据类型
在最近的实践中,有人突然问了一个问题: 在 Java 的 List 中可以存不同的数据类型吗? 这个问题突然给问到了,我们都知道 Java 中的 List 中存的是对象,通常我们定义都会这样的定义: List<String> t…...
pyqt5:openpyxl 读取 Excel文件,显示在 QTableWidget 中
pip install openpyxl openpyxl-3.1.2-py2.py3-none-any.whl (249 kB) et_xmlfile-1.1.0-py3-none-any.whl (4.7 kB) 摘要:A Python library to read/write Excel 2010 xlsx/xlsm files pip install pyqt5; pip install pyqt5-tools; 编写 openpyxl_pyqt5.py 如…...
在RabbitMQ中使用新的MQTT 5.0功能
MQTT是物联网(IoT)的标准协议,是轻量级的,协议头很小,可以节省网络带宽。MQTT也很有效,与其他消息传递协议相比,客户端通过更短的握手进行连接和身份验证。 以下是本文介绍的MQTT 5.0功能列表&…...
flinkcdc 体验
0 flink版本 踩雷 java代码操作 flink Table/SQL API 和 DataStream API 编写程序后,打成jar包丢到flink集群运行,报错首选需要考虑flink集群版本和 jar包中maven依赖的版本是否一致。 目前网上flink、flinkcdc相关博文绝大部分是基于flink1.13、1.14编…...
Kafka知识补充
如何避免 Rebalance 最简单粗暴的就是 : 减少组成员数量发生变化 每个 Consumer 实例都会定期地向 Coordinator 发送心跳请求,表明它还存活着。如果某个 Consumer 实例不能及时地发送这些心跳请求,Coordinator 就会认为该 Consumer 已经“死…...
【MAC】升级 Mac os 后报错
背景 17 年买的 mac,发现很多软件都无法安装,于是升级 mac os 到 10.13,从官网下载 10.13 版本,之后升级,升级还算顺利。但使用 git 的时候发现出现问题了。 问题 使用 git 出现如下错误 xcrun: error: invalid ac…...

LeetCode(力扣)416. 分割等和子集Python
LeetCode416. 分割等和子集 题目链接代码 题目链接 https://leetcode.cn/problems/partition-equal-subset-sum/ 代码 class Solution:def canPartition(self, nums: List[int]) -> bool:sum 0dp [0]*10001for num in nums:sum numif sum % 2 1:return Falsetarget …...

Redis之缓存一致性
Redis之缓存一致性 1 缓存更新策略1.1 内存淘汰1.2 过期删除1.3 主动更新1.4 三种缓存更新策略的对比 2 更新缓存的两种方式3 缓存更新策略的实现方式3.1 先更新DB,后更新缓存3.2 先更新DB,后删除缓存3.3 先更新缓存,后更新DB3.4 先删除缓存&…...

LeetCode-199-二叉树的右视图
题目描述: 题目链接:LeetCode-199-二叉树的右视图 解题思路: 在 102 的基础之上进行改进,一维数组每次只保存 size1 时候的值 代码实现: class Solution {public List<Integer> rightSideView(TreeNode root) {i…...

二叉树的最近公共祖先
🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻强烈推荐优质专栏: 🍔🍟🌯C的世界(持续更新中) 🐻推荐专栏1: 🍔🍟🌯C语言初阶 🐻推荐专栏2: 🍔…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...