面试突击-分布式框架-Zookeeper核心源码解析
恁爹说:Zookeeper作为当前主流的分布式框架,在分布式一致性处理方面有着独到的优势,属于必学知识!今天就跟着恁爹一起学习吧~
学习本章节前需具备ZK的使用技能
目录
一、前言
1. 看源码的必要性
- 提升技术功底:学习源码里的优秀设计思想,比如一些疑难问题的解决思路,还有一些优秀的设计模式,整体提升自己的技术功底。
- 深度掌握技术框架:源码看多了,对于一个新技术或框架的掌握速度会有大幅提升,看下框架demo大致就能知道底层的实现,技术框架更新再快也不怕。
- 快速定位线上问题:遇到线上问题,特别是框架源码里的问题(比如bug),能够快速定位,这就是相比其他没看过源码的人的优势。
- 对面试大有裨益:面试一线互联网公司对于框架技术一般都会问到源码级别的实现。
- 知其然知其所以然:对技术有追求的人必做之事,使用了一个好的框架,很想知道底层是如何实现的。
- 拥抱开源社区:对技术有追求的人必做之事,使用了一个好的框架,很想知道底层是如何实现的
2. 看源码的方法
- 先使用:先看官方文档快速掌握框架的基本使用。
- 抓主线:找一个demo入手,顺藤摸瓜快速静态看一遍框架的主线源码,画出源码主流程图,切勿一开始就陷入源码的细枝末节,否则会把自己绕晕,凭经验猜。
相关技巧:
1)源码中if
判断后没多久就return
的逻辑,初次不看,肯定是分支逻辑
2)类似Secure字样的权限校验类逻辑不看,肯定是分支逻辑
- 画图做笔记:总结框架的一些核心功能点,从这些功能点入手深入到源码的细节,边看源码边画源码走向图,并对关键源码的理解做
笔记,把源码里的闪光点都记录下来,后续借鉴到工作项目中,理解能力强的可以直接看静态源码,也可以边看源码边debug源码执行过
程,观察一些关键变量的值 - 整合总结:所有功能点的源码都分析完后,回到主流程图再梳理一遍,争取把自己画的所有图都在脑袋里做一个整合
3. 学完ZK源码后需具备的技能
- 启动或宕机Leader选举流程
- 客户端与服务端交互流程(NIO或Netty)
- 此处主要讲NIO方面,当Netty讲完后再讲其相关的
- 写入数据的ZAB一致性协议(如何保证消息的顺序性)
- Watch监听触发机制
二、Zookeeper源码环境构建
- 源码地址:
https://github.com/apache/zookeeper
,选择release-3.5.8
TAG分支,如下图所示:
- 使用IDEA导入项目后,如果
org.apache.zookeeper.Version
类报错,需要新增一个org.apache.zookeeper.version.Info
接口:
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‐10‐15";
}
- 项目结构说明:
- /bin:存放启动脚本
- /conf:存放配置文件
- /zookeeper-client:C语言的客户端源码
- /zookeeper-jute:序列化代码
- /zookeeper-recipes:示例代码
- /zookeeper-server:服务端源码,也是本次解析的重点
三、通过Zookeeper源码启动ZK集群
3.1 通过启动脚本定位启动类
- 入口的定位:
1)通常一个框架都会支持Shell脚本的形式启动,因此找启动类前先找脚本
2)脚本中一般用到$1
类似的参数,逐行排查出类似start这类表示启动的值。如果是Java框架,进一步定位到核心的$JAVA
启动参数
3)$JAVA
启动参数后面又以$CLASSPATH
参数为关键,其后必定包含启动类的全包名路径
- 定位到/bin目录下,因为剖析的核心代码是zk-server,因此打开
zkServer.sh
文件 - 找到参数
$1
,进一步找到$JAVA
的Java启动参数,定位到$CLASSPATH
后的ZOOMAIN
内部参数 - 确定集群启动类为:
org.apache.zookeeper.server.quorum.QuorumPeerMain
- 设置启动类参数:
- 熟悉ZK使用的都直到,zk启动的时候是需要指定启动配置文件的。
- zk源码在/conf目录下提供了配置样例
zoo_sample.cfg
,自己复制一个取名zoo.cfg
留待使用 - 点击Add Configurations,新增Application启动配置,具体如下:
- MainClass:
org.apache.zookeeper.server.quorum.QuorumPeerMain
- VM options:
Dzookeeper.serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory
(配置ZK服务以Netty进行服务创建和服务通信,当前暂时不配置该项,ZK会使用自带的NIO服务创建工厂NIOServerCnxnFactory
来创建服务并进行NIO通信) - Program arguments:
E:\17.markdown 笔记\2.技术\图灵学院\第四期系列专题\1.分布式框架\10.Zookeeper选举Leader源码剖析(一)\zk源码\zookeeper-release-3.5.8\conf\zoo.cfg
- Working directory:
E:\17.markdown 笔记\2.技术\图灵学院\第四期系列专题\1.分布式框架\10.Zookeeper选举Leader源码剖析(一)\zk源码\zookeeper-release-3.5.8
- Use classpath of module:zookeeper
- MainClass:
3.2 从源码里运行ZooKeeperMain客户端
仅适用于单机环境
- 需设置如下启动参数:
- MainClass:
org.apache.zookeeper.ZooKeeperMain
- Program arguments:-server localhost:2181
- Working directory:
E:\17.markdown 笔记\2.技术\图灵学院\第四期系列专题\1.分布式框架\10.Zookeeper选举Leader源码剖析(一)\zk源码\zookeeper-release-3.5.8
3.3 从源码里运行ZooKeeper集群
- 复制3个zoo.cfg文件,修改对应集群配置
尤其注意dataDir(事务日志/文件目录)和clientPort(客户端端口)配置要不相同
- 在/data目录里分别建各自的myid文件填入机器id,并创建三个不同配置的启动节点
- 使用【3.1 通过启动脚本定位启动类】的启动方式启动
四、Zookeeper集群Leader选举流程剖析
4.1 集群启动或Leader宕机后的Leader选举流程分析
- 图示:
- 补充说明:
- 节点的初次投票必投自己(即自身节点的myid)
五、Zookeeper集群启动时Leader选举源码剖析
5.1 从QuorumPeerMain.main()开始以单机或集群模式运行
特别说明:
1)内部子逻辑所属流程为子流程,且仅对跳转后的首个子流程使用[[]]
表示
2)==>
表示必看的主体流程,-->
表示次要流程,-.->
表示需跨类跳转的流程
3)跳转到次要的子流程的说明,必须以X.X作为前缀,必看的子流程不受限制
- 图示:
- 关联说明:
$1$
:根据zk.cfg配置文件中是否有server
前缀的集群配置来决定是否采用集群模式:
5.2 初始化Server类
- 图示:
- 关联说明:
$2$
:ZK官方更推荐使用Netty作为服务创建工厂(依赖Netty进行服务通信),也就是要在配置的启动参数中添加如下配置:- VM options:
Dzookeeper.serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory
- VM options: