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

目录

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

前言

为什么要看源码?当然是装逼啊!哈哈
说实在博主之前看Spring源码之前没细想过这个问题,只是听大佬们说【Spring是一个非常优秀的源码】,甚至【Java程序员一定要看的系列】的地步。于是奔着这些噱头,我还是抱着积极的心态去认真学习的(3分为装逼,7分为学习)。
那ZK源码,有必要学习吗?Spring再怎么说也是基石之一,还可以说的过去,ZK呢?它在市面上又并非是无可替代的。所以一开始我是觉得没必要去学习的,而且不少人还评价ZK源码写的很抽象、不规范,可读性差。但是我的培训老师们又比较力推,所以就跟着学习了部分源码。此后,我突然间有点明悟,为什么要学习ZK源码了。原因如下:

  1. ZK服务端是以Java编写出来的程序。所以,看ZK源码,其实是等于看一个行业大拿的优秀代码
  2. 学习ZK,在没有依赖其他中间件的情况下,如何实现高可用架构。或许,如果我们想成为一个优秀的JavaCoder,甚至是架构师,这确实是一条必经之路,毕竟这些成熟、优秀的产品架构,肯定能让你有所收获
  3. 不止是ZK,所有以Java编写的市面上优秀的源码都值得学习。毕竟这种能够在Java生态圈里面占据重要地位的应用,称它们为【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的领域设计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/158032.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

15. Java反射和注解

Java —— 反射和注解 1. 反射2. 注解 1. 反射 动态语言:变量的类型和属性可以在运行时动态确定,而不需要在编译时指定 常见动态语言:Python,JavaScript,Ruby,PHP,Perl;常见静态语言…

【云备份项目】

文章目录 [TOC](文章目录) 一、项目框架定义1.项目需求2. 服务端框架搭建思想3.客户端框架搭建思想 二、环境搭建1.gcc编译器升级2.安装第三方库 三、认识第三方库1.json库使用2.bundle库使用3.httplib库使用4.简单服务器搭建5.简单客户端搭建 四、文件使用工具类设计1.类的功能…

3. Windows下C++/MFC调用hiredis库操作redis示例

一、头文件目录 将之前下载和编译好的Redis目录拷贝到新建好的工程目录下面,再点击测试工程的右键/属性,点击C/常规,附加包含目录添加以下路径,注意如果原先有多个路径,在末尾处添加分号后再粘贴: 点击C/常…

树莓派玩转openwrt软路由:11.OpenWrt安装NodeRed

1、更新软件源 opkg update2、安装nodered docker run -it -p 1880:1880 --name mynodered nodered/node-red3、安装完整性测试 实现一个打印hello world的demo,每隔1秒打印一次

css 星星闪烁加载框

今天带来的是普灵普灵的loader闪烁加载框 效果如下 开源精神给我们带来了源码 ,源码如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, in…

Spring framework Day10:JSR330注入注解

前言 JSR330是Java社区标准化进程&#xff08;Java Community Process&#xff0c;简称JCP&#xff09;中的一个规范&#xff0c;全名为"Dependency Injection for Java"&#xff0c;即Java的依赖注入规范。它定义了一组注解和相关的规范&#xff0c;用于实现依赖注…

python每日一练(7)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

Visual Studio 错误CS0006:未能找到元数据文件踩坑记录

前言 在写项目的时候&#xff0c;添加了个新的Nuget包&#xff0c;突然就不行&#xff0c;然后就是报错&#xff0c;找不到文件、 出现的原因是因为项目之间互相引用出现了问题&#xff0c;比如如下情况 先版本回退 如果有Git仓库 第一时间去看Git 文件比较&#xff0c;找到…

YOLOv5算法改进(11)— 主干网络介绍(MobileNetV3、ShuffleNetV2和GhostNet)

前言:Hello大家好,我是小哥谈。主干网络通常指的是深度学习中的主干模型,通常由多个卷积层和池化层组成,用于提取输入数据的特征。在训练过程中,主干网络的参数会被不断优化以提高模型的准确性。YOLOv5算法中的主干网络可以有多种替换方案,为了后面讲解的方便,本篇文章就…

自动驾驶学习笔记(三)——场景设计

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《2023星火培训【感知专项营】》免费课程—>传送门 文章目录 前言 场景设计平台 场景地图 场景基本…

【NLTK系列01】:nltk库介绍

一、说明 NLTK是个啥&#xff1f;它是个复杂的应用库&#xff0c;可以实现基本预料库操作&#xff0c;比如&#xff0c;、将文章分词成独立token&#xff0c;等操作。从词统计、标记化、词干提取、词性标记&#xff0c;停用词收集&#xff0c;包括语义索引和依赖关系解析等。 …

Android---java线程优化 偏向锁、轻量级锁和重量级锁

java 中的线程是映射到操作系统原生线程之上的&#xff0c;如果要阻塞或唤醒一个线程就需要操作系统的帮忙&#xff0c;这就需要从用户态转换到核心态。状态转换需要花费很多时间&#xff0c;如下代码所示&#xff1a; private Object lock new Object();private int value;p…

异星工场入门笔记-01

两年前玩过一点&#xff0c;不看教程&#xff0c;单纯地开放世界自己探索&#xff0c;没有同类游戏经验&#xff0c;因此很难有获得感所以放弃了。现在正版游戏涨到130&#xff0c;看在逆势上涨的份上&#xff0c;我倒想继续探索下这个游戏的价值。 玩魔方&#xff0c;记教程步…

Kubernetes使用OkHttp客户端进行网络负载均衡

在一次内部Java服务审计中&#xff0c;我们发现一些请求没有在Kubernetes&#xff08;K8s&#xff09;网络上正确地实现负载均衡。导致我们深入研究的问题是HTTP 5xx错误率的急剧上升&#xff0c;由于CPU使用率非常高&#xff0c;垃圾收集事件的数量很多以及超时&#xff0c;但…

【UE 插件】UE4 虚幻引擎 插件开发(带源码插件打包、无源码插件打包) 有这一篇文章就够了!!!

目录 0 引言1 快速入门1.1 新建插件的前提1.2 创建插件步骤1.3 打包插件 2 无源代码的插件制作3 插件详细介绍3.1 插件的使用方法3.1 UE 预置插件模版3.1.1 空白3.1.2 纯内容3.1.3 编辑器独立窗口3.1.4 编辑器工具栏按钮3.1.5 编辑器模式3.1.6 第三方库3.1.7 蓝图库 3.2 插件中…

华为OD机试 - 最大括号深度 - 栈stack(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷+B卷)》。 刷的越多,

本、硕、博区别真的辣么大吗?

61&#xff1a; 发际线已经说明了一切…… Super Mario&#xff1a; 小学&#xff0c;老师告诉学生&#xff1a;“森林里有只老虎&#xff0c;已经被我关在笼子里&#xff0c;我会带你去那个地方&#xff0c;然后给你一把猎枪&#xff0c;告诉你猎枪怎么用&#xff0c;并开枪…

搭建一个vscode+uni+vue的小程序项目

我们使用 vue2 创建工程作为示例&#xff0c;uni-app中Vue2版的组件库和插件也比较多&#xff0c;稳定、问题少&#xff0c;可以先参考下官方文档:uni-app官网 既然是使用vue脚手架&#xff0c;那肯定要全局安装vue/cli&#xff0c;已安装的可以跳过。 注意&#xff1a;Vue2创…

day05-前后端项目上传到gitee、后端多方式登录接口、发送短信功能、发送短信封装、短信验证码接口、短信登录接口

1 前后端项目上传到gitee 2 后端多方式登录接口 2.1 序列化类 2.2 视图类 2.3 路由 3 发送短信功能 4 发送短信封装 4.0 目录结构 4.1 settings.py 4.2 sms.py 5 短信验证码接口 6 短信登录接口 6.1 视图类 6.2 序列化类 1 前后端项目上传到gitee # 我们看到好多开源项目…

解决react使用css module无法重写bootstrap样式的问题

react使用css module虽然能够解决样式污染&#xff0c;但是同时也失去了写css样式的灵活性&#xff0c;特别是&#xff1a;在.module.css文件中当子元素是非变量的静态class类&#xff08;比如bootstrap&#xff09;, 此时使用css选择器对该子元素的样式不会起作用的 比如下面…