当前位置: 首页 > news >正文

【Zookeeper专题】Zookeeper选举Leader源码解析

目录

  • 前言
  • 阅读建议
  • 课程内容
    • 一、ZK Leader选举流程回顾
    • 二、源码流程图
    • 三、Leader选举模型图
  • 学习总结

前言

为什么要看源码?说实在博主之前看Spring源码之前没想过这个问题。因为我在看之前就曾听闻大佬们说过【JavaCoder三板斧:Java,Mysql,Spring】,所以我抱着积极的学习心态去看的。另外,我也发现了一个很有意思的现象:就是我们一群人在学习,但是每个人学习的【偏好】似乎是不一样的,或者说关注的重点不一样。所以,其实我也不知道自己关注的重点到底对不对,但总归是有收获的。
现在回过头来再看ZK源码,有必要学习吗?一开始我是觉得没必要的,因为不少人说ZK源码写的很抽象、不规范,但还是有人坚持说学习一下比较好。现在稍微学习了一小段之后,我突然间有点感悟:ZK源码还是值得学习阅读的,甚至所有市面上以Java编写的分布式中间件都值得学习。为什么呢?
首先,ZK服务端是以Java编写出来的程序,所以,我们在阅读ZK源码的时候,何尝不是一种进步呢?(咱可是直接在看行业大拿的源码啊)
其次,也可能是最重要的,如果我们想成为一个优秀的JavaCoder,甚至是架构师,这确实是一条必经之路,毕竟这些成熟、优秀的产品架构,肯定能让你学到很多东西(修炼内功);
还有啊,这些成熟、优秀的源码,难道不值得学习吗?这或许是世界上,Java里面最牛逼的源码之一了!
以上是我的一些思考。

同样,这个问题,我的老师也给出了他们的答案,在这里分享给大家:

Q1:为什么要学习源码?
答:

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

阅读建议

看源码方法:

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

课程内容

我跟着老师看了一下源码,说实在,思考了很久实在不知道怎么给大家伙记下来分享给大家,有点无从下手的感觉,因为相关性太大了。所以,这里算是自结吧,主要是为了加深个人理解,以及方便后续回头看。

一、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个节点没启动)

  1. ZK集群刚启动的时候,由于他们仍未经历过选举,所以每一台ZK机器中,上面投票规则提到的epoch肯定是一样的,包括zxid,毕竟还没有接受过客户端的读写,所以唯一的差异就在myId上了
  2. 开始第一阶段选举:由于彼此还不知道谁的epochzxidmyId,所以会优先将票投给自己,并且广播出去;当然也能接收到别的服务器【投票自己的广播】。所以,myid=1的机器按照投票规则,投票vote=(1, 0),并且收到myid=2的投票vote=(2, 0);同时myid=2的机器按照投票规则,投票vote=(2, 0),并且收到myid=1的投票vote=(1, 0)。显然,目前投票情况是服务1跟服务2各收到一张选票,所以Leader没办法选举出来
  3. 第二阶段选举:每个节点服务器收到投票广播后,按照投票选举规则,各自更新自己最新的投票。比如:myid=1的服务器经过比较之后,发现myid=2比自己更适合当Leader,于是在第二轮投票的时候投票vote=(2,0);而myid=2的服务也经过比较之后,觉得还是自己适合做Leader,于是在第二轮投票的时候投票vote=(2,0)。就这样,myid=2的服务收到了2张选票,2 > (3/2),符合【过半机制】,于是成为了Leader
  4. 接着myid=3的节点上线,发现已经有Leader了,那不用投票了,直接把自己置为Follower(也许有人问,为什么不重新选举?因为没必要啊,对于ZK集群来说,尽快对外服务才是重点,重新选举不是浪费时间嘛)

OK,流程回顾就到这里。相信大伙通过这个业务流程去理解代码,将会事半功倍。

二、源码流程图

说明:我估计很多人源码入口都找不到,给大家一个方法,也是很多源码阅读的办法。那就是从启动脚本找,比如ZK,我们知道它的启动脚本为zkServer.sh,那就在里面找好了。

ZK源码入口类:org.apache.zookeeper.server.quorum.QuorumPeerMain
下面是是一个自结的源码流程图,不是很好看。感兴趣的大伙,可以跟着我的流程图看一遍源码
在这里插入图片描述
看完选举源码之后的一些总结与思考:

  1. 【总结】比较清晰的了解,为什么是二阶段选举,因为ZK在设计投票与选举的时候,是使用两个独立的业务领域类(独立的线程)来完成的(投票决策领域类 + 投票发送/接受领域类),也就是说,他们的数据并非是直接耦合在一起的(我描述的比较抽象,咱也不知道该怎么解释了)。
  2. 【总结】在投票、选举中,ZK新建了好几个业务线程,往往是,一个业务领域类本身就是一个线程子类,然后在run方法中实现各自领域的逻辑。每个线程通常各自维护了一条阻塞队列,线程之间交换数据是将消息发送至对应的阻塞队列中。也许,这就是JVM级别,不基于中间件的线程通信的可靠手段之一吧
  3. 【思考】Leader节点与Follower节点,节点之间投票都分别监听了独立的端口,使用独立的scoket进行通信交互。其实前者Leader节点与Follower节点数据同步采用socket长连接保持通信我是能理解的,但是选举方面,我发现这个需求本来就不是特别大,为什么也要用socket通信呢?为什么不是http?别笑我哈,我一直以为socket比起http是一种比较重度的通信手段。现在看来可能跟我想象的不一样。sockert是传输层协议,http是应用层协议,且两者安全性方面前者更高。下面是来自gpt的回答:
    在这里插入图片描述
    在这里插入图片描述
  4. 【总结】BIO网络连接在简单的应用通信之间,还是很可靠的,人家ZK都这么玩

三、Leader选举模型图

接下来再给大家画一下,选举的相关模型图。
整个zookeeper选举底层可以分为【选举逻辑层】和【选举消息传输层】,【逻辑层】有自己的队列统一接收和发送选票,【传输层】也设计了自己的队列,但是按发送的机器分了队列,避免给每台机器发送消息时相互影响,比如某台机器如果出问题发送不成功则不会影响对正常机器的消息发送。
在这里插入图片描述

学习总结

  1. 学习了ZK底层选举源码,学习像JUC,阻塞队列、网络通信在这种优秀应用中的使用思路
  2. 学习了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 系统中&#xf…...

Laya3.0 入门教程

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

3D全景虚拟样板间展销系统扩展用户市场范围

VR样板间,能够真实还原现场,定制需要的场景。让一切比真实更真实。用户可以720度看房,自由行走在空间里,直观感受各空间的大小,看到自己家中的“未来样子”,同时通过操控手柄,控制整个智能家居系…...

如何编写lua扩展库

很多人都听过lua,也见过lua脚本,但可能不理解为什么lua脚本里面会有这么多没见过的函数, 而且这些函数功能是如此强大,能上天入地,无所不能 其实这些函数并不是lua自带的,都是由程序作者造出来的隐藏在了他们的主程序里 一般运行lua脚本,我们会使用自带的解释器,当你拿到一份…...

Java List 中存不同的数据类型

在最近的实践中&#xff0c;有人突然问了一个问题&#xff1a; 在 Java 的 List 中可以存不同的数据类型吗&#xff1f; 这个问题突然给问到了&#xff0c;我们都知道 Java 中的 List 中存的是对象&#xff0c;通常我们定义都会这样的定义&#xff1a; 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) 摘要&#xff1a;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是物联网&#xff08;IoT&#xff09;的标准协议&#xff0c;是轻量级的&#xff0c;协议头很小&#xff0c;可以节省网络带宽。MQTT也很有效&#xff0c;与其他消息传递协议相比&#xff0c;客户端通过更短的握手进行连接和身份验证。 以下是本文介绍的MQTT 5.0功能列表&…...

flinkcdc 体验

0 flink版本 踩雷 java代码操作 flink Table/SQL API 和 DataStream API 编写程序后&#xff0c;打成jar包丢到flink集群运行&#xff0c;报错首选需要考虑flink集群版本和 jar包中maven依赖的版本是否一致。 目前网上flink、flinkcdc相关博文绝大部分是基于flink1.13、1.14编…...

Kafka知识补充

如何避免 Rebalance 最简单粗暴的就是 &#xff1a; 减少组成员数量发生变化 每个 Consumer 实例都会定期地向 Coordinator 发送心跳请求&#xff0c;表明它还存活着。如果某个 Consumer 实例不能及时地发送这些心跳请求&#xff0c;Coordinator 就会认为该 Consumer 已经“死…...

【MAC】升级 Mac os 后报错

背景 17 年买的 mac&#xff0c;发现很多软件都无法安装&#xff0c;于是升级 mac os 到 10.13&#xff0c;从官网下载 10.13 版本&#xff0c;之后升级&#xff0c;升级还算顺利。但使用 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&#xff0c;后更新缓存3.2 先更新DB&#xff0c;后删除缓存3.3 先更新缓存&#xff0c;后更新DB3.4 先删除缓存&…...

LeetCode-199-二叉树的右视图

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

二叉树的最近公共祖先

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…...

C++ 补充 反向迭代器的实现

阅前提要&#xff1a; 本文主要是对list和vector的实现的补充&#xff0c;以代码实现为主&#xff0c;注释为辅&#xff0c;如果对vector&#xff0c;list底层实现感兴趣的可以自行阅读&#xff0c;代码量有点大&#xff0c;请大家耐心查看&#xff0c;对理解语言很有帮助&…...

JVM第一讲:JVM相关知识体系详解+面试(P6熟练 P7精通)

JVM相关知识体系详解面试(P6熟练 P7精通) 面试时常常被面试官问到JVM相关的问题。本系列将给大家构建JVM核心知识点全局知识体系&#xff0c;本文是JVM第一讲&#xff0c;JVM相关知识体系详解和相关面试题梳理。 文章目录 JVM相关知识体系详解面试(P6熟练 P7精通)1、JVM学习建议…...

深度学习DAY3:FFNNLM前馈神经网络语言模型

1 神经网络语言模型NNLM的提出 文章&#xff1a;自然语言处理中的语言模型预训练方法&#xff08;ELMo、GPT和BERT&#xff09; https://www.cnblogs.com/robert-dlut/p/9824346.html 语言模型不需要人工标注语料&#xff08;属于自监督模型&#xff09;&#xff0c;所以语言…...

JavaSE学习值之--String类

&#x1f495;"不要同情自己&#xff0c;同情自己是卑劣懦夫的勾当&#xff01;"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;JavaSE学习值之--String类 目录 前言&#xff1a; 一.String类 1.String类的属性 2.字符串的构造 注意&#xf…...

【LeetCode高频SQL50题-基础版】打卡第6天:第31~35题

文章目录 【LeetCode高频SQL50题-基础版】打卡第6天&#xff1a;第31~35题⛅前言员工的直属部门&#x1f512;题目&#x1f511;题解 判断三角形&#x1f512;题目&#x1f511;题解 连续出现的数字&#x1f512;题目&#x1f511;题解 指定日期的产品价格&#x1f512;题目&am…...

基于单片机的汽车智能仪表的设计

基于单片机的汽车智能仪表的设计 摘要&#xff1a;汽车的汽车系统。速度测量以及调速是我们这次的设计所要研究的对象&#xff0c;本次设计的基础核心的模块就是单片机&#xff0c;其应用的核心的控制单元就是stc89c52单片机&#xff0c;用到的测速模块是霍尔传感器&#xff0c…...

【Docker 内核详解】namespace 资源隔离(一):进行 namespace API 操作的 4 种方式

namespace 资源隔离&#xff08;一&#xff09;&#xff1a;进行 namespace API 操作的 4 种方式 1.通过 clone() 在创建新进程的同时创建 namespace2.查看 /proc/[pid]/ns 文件3.通过 setns() 加入一个已经存在的 namespace4.通过 unshare() 在原先进程上进行 namespace 隔离5…...

【技术研究】环境可控型原子力显微镜超高真空度精密控制解决方案

摘要&#xff1a;针对原子力显微镜对真空度和气氛环境精密控制要求&#xff0c;本文提出了精密控制解决方案。解决方案基于闭环动态平衡法&#xff0c;在低真空控制时采用恒定进气流量并调节排气流量的方法&#xff0c;在高真空和超高真空控制时则采用恒定排气流量并调节进气流…...

【Vuex+ElementUI】Vuex中取值存值以及异步加载的使用

一、导言 1、引言 Vuex是一个用于Vue.js应用程序的状态管理模式和库。它建立在Vue.js的响应式系统之上&#xff0c;提供了一种集中管理应用程序状态的方式。使用Vuex&#xff0c;您可以将应用程序的状态存储在一个单一的位置&#xff08;即“存储”&#xff09;中&#xff0c;…...

python经典百题之简单加密数据

题目:某个公司采用公用电话传递数据&#xff0c;数据是四位的整数&#xff0c;在传递过程中是加密的&#xff0c;加密规则如下&#xff1a; 每位数字都加上5,然后用和除以10的余数代替该数字&#xff0c;再将第一位和第四位交换&#xff0c;第二位和第三位交换 程序分析 对于…...