【面试突击-分布式框架-Zookeeper核心源码解析】

面试突击-分布式框架-Zookeeper核心源码解析

恁爹说:Zookeeper作为当前主流的分布式框架,在分布式一致性处理方面有着独到的优势,属于必学知识!今天就跟着恁爹一起学习吧~

学习本章节前需具备ZK的使用技能

一、前言

1. 看源码的必要性

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

2. 看源码的方法

  1. 先使用:先看官方文档快速掌握框架的基本使用。
  2. 抓主线:找一个demo入手,顺藤摸瓜快速静态看一遍框架的主线源码,画出源码主流程图,切勿一开始就陷入源码的细枝末节,否则会把自己绕晕,凭经验猜。

相关技巧
1)源码中if判断后没多久就return的逻辑,初次不看,肯定是分支逻辑
2)类似Secure字样的权限校验类逻辑不看,肯定是分支逻辑

  1. 画图做笔记:总结框架的一些核心功能点,从这些功能点入手深入到源码的细节,边看源码边画源码走向图,并对关键源码的理解做
    笔记,把源码里的闪光点都记录下来,后续借鉴到工作项目中,理解能力强的可以直接看静态源码,也可以边看源码边debug源码执行过
    程,观察一些关键变量的值
  2. 整合总结:所有功能点的源码都分析完后,回到主流程图再梳理一遍,争取把自己画的所有图都在脑袋里做一个整合

3. 学完ZK源码后需具备的技能

  1. 启动或宕机Leader选举流程
  2. 客户端与服务端交互流程(NIO或Netty)
  • 此处主要讲NIO方面,当Netty讲完后再讲其相关的
  1. 写入数据的ZAB一致性协议(如何保证消息的顺序性)
  2. Watch监听触发机制

二、Zookeeper源码环境构建

  1. 源码地址https://github.com/apache/zookeeper,选择release-3.5.8TAG分支,如下图所示:
    1.ZK源码地址以及分支选择
  2. 使用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";
}
  1. 项目结构说明
    2.ZK源码项目结构
  • /bin:存放启动脚本
  • /conf:存放配置文件
  • /zookeeper-client:C语言的客户端源码
  • /zookeeper-jute:序列化代码
  • /zookeeper-recipes:示例代码
  • /zookeeper-server:服务端源码,也是本次解析的重点

三、通过Zookeeper源码启动ZK集群

3.1 通过启动脚本定位启动类

  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
  1. 设置启动类参数
  • 熟悉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
      3.ZK源码启动类参数配置

3.2 从源码里运行ZooKeeperMain客户端

仅适用于单机环境

  1. 需设置如下启动参数:
  • 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集群

  1. 复制3个zoo.cfg文件,修改对应集群配置

尤其注意dataDir(事务日志/文件目录)和clientPort(客户端端口)配置要不相同
4.ZK集群启动_配置1

  1. 在/data目录里分别建各自的myid文件填入机器id,并创建三个不同配置的启动节点
    5.ZK集群启动_配置2
  2. 使用【3.1 通过启动脚本定位启动类】的启动方式启动

四、Zookeeper集群Leader选举流程剖析

4.1 集群启动或Leader宕机后的Leader选举流程分析

  1. 图示
    6.启动或leader宕机选举leader流程
  2. 补充说明
  • 节点的初次投票必投自己(即自身节点的myid)

五、Zookeeper集群启动时Leader选举源码剖析

5.1 从QuorumPeerMain.main()开始以单机或集群模式运行

特别说明:
1)内部子逻辑所属流程为子流程,且仅对跳转后的首个子流程使用[[]]表示
2)==>表示必看的主体流程,-->表示次要流程,-.->表示需跨类跳转的流程
3)跳转到次要的子流程的说明,必须以X.X作为前缀,必看的子流程不受限制

  1. 图示
1.执行QuorumPeerMain.main()
2.执行run方法
3.解析启动配置文件config.parse(args[0])
3.1 解析属性到本地缓存parseProperties(cfg)
4. 定时任务purgeMgr定时清理/data目录
下的快照文件snapshot
5. 启动时有配置且配置成集群形式,
则以集群模式运行
结束
服务端启动类:QuorumPeerMain
QuorumPeerMain main = new QuorumPeerMain();
// 【执行run方法】
main.initializeAndRun(args);
QuorumPeerConfig config = new QuorumPeerConfig();
// 【解析启动配置文件】
config.parse(args[0]);
// 【定时任务purgeMgr定时清理/data目录下的快照文件snapshot】
DatadirCleanupManager purgeMgr = new DatadirCleanupManager(..);
purgeMgr.start();
// 【启动时有配置且配置成集群形式,则以集群模式运行】 [关联$1$]
if (args.length == 1 && config.isDistributed()) runFromConfig(config);
// 否则以单机模式运行
// else ZooKeeperServerMain.main(args);
配置文件解析类:QuorumPeerConfig.parse(String path)
// 加载指定目录的.cfg配置文件
File configFile = ...create(path);
// 使用配置文件生成属性对象
Properties cfg = new Properties();
FileInputStream in = new FileInputStream(configFile);
// 【解析属性到本地缓存】
parseProperties(cfg);
purgeMgr.start();
runFromConfig(config);
start
// 节点文件目录
dataDir = vff.create(value);
// 供客户端访问的端口
clientPort = Integer.parseInt(value);
// 这是??
secureClientPort = Integer.parseInt(value);
...
// 读取集群模式配置,从而确定是否使用集群模式启动 [关联$1$]
setupQuorumPeerConfig(dynamicCfg, false);
end
  1. 关联说明
  • $1$:根据zk.cfg配置文件中是否有server前缀的集群配置来决定是否采用集群模式:
    启动或leader宕机选举leader流程_如何确定是否以集群模式启动

5.2 初始化Server类

  1. 图示
6. 以集群模式运行
7. 以工厂方法模式创建ZK服务
// 【以集群模式运行】
runFromConfig(config);
// 【以工厂方法模式创建ZK服务】
cnxnFactory = ServerCnxnFactory.createFactory();
// 获取启动参数zookeeper.serverCnxnFactory(指定服务创建工厂)的值
String serverCnxnFactoryName =
System.getProperty(ZOOKEEPER_SERVER_CNXN_FACTORY);
// 未指定工厂类时默认以ZK自带的NIO工厂类NIOServerCnxnFactory来创建服务 [关联$2$]
if (serverCnxnFactoryName == null) {
serverCnxnFactoryName = NIOServerCnxnFactory.class.getName();
}
start
  1. 关联说明:
  • $2$:ZK官方更推荐使用Netty作为服务创建工厂(依赖Netty进行服务通信),也就是要在配置的启动参数中添加如下配置:
    • VM options:Dzookeeper.serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory

六、Zookeeper集群Leader宕机如何重新选举Leader

七、Zookeeper底层Leader选举多层队列架构剖析

1. ZooKeeper分布式系统框架

KK
链接
过来了
这是
长方形
圆角长方形
菱形
圆角长方形
输入
数据库
子流程
C
A
你说啥
有哪个大病
D
n2
n1
c2
c1
B
b2
b1
a2
a1
Yes
No
Haha
start
It's TURE?
OK
Rethink
End
这是啥
Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no
Created with Raphaël 2.3.0 Start My Operation Yes or No? catch something... End parallel tasks My Subroutine ganniniang yes no
  • 20
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值