个人随笔
目录
九、Zookeeper源码分析
2020-12-14 22:37:50

一、启动流程

1、源码环境搭建

源码环境搭建可参考:https://www.suibibk.com/topic/788094914020769792

2、启动宏观流程图

单机服务端:ZooKeeperServerMain
集群服务端:QuorumPeerMain
客户端:ZooKeeperMain

3、集群启动详细流程

装载配置:

  1. # zookeeper 启动流程堆栈
  2. >QuorumPeerMain#initializeAndRun //启动工程
  3. >QuorumPeerConfig#parse // 加载config 配置
  4. >QuorumPeerConfig#parseProperties// 解析config配置
  5. >new DatadirCleanupManager // 构造一个数据清器
  6. >DatadirCleanupManager#start // 启动定时任务 清除过期的快照

代码堆栈 :

  1. >QuorumPeerMain#main //启动main方法
  2. >QuorumPeerConfig#parse // 加载zoo.cfg 文件
  3. >QuorumPeerConfig#parseProperties // 解析配置
  4. >DatadirCleanupManager#start // 启动定时任务清除日志
  5. >QuorumPeerConfig#isDistributed // 判断是否为集群模式
  6. >ServerCnxnFactory#createFactory() // 创建服务默认为NIO,推荐netty
  7. //***创建 初始化集群管理器**/
  8. >QuorumPeerMain#getQuorumPeer
  9. >QuorumPeer#setTxnFactory
  10. >new FileTxnSnapLog // 数据文件管理器,用于检测快照与日志文件
  11. /** 初始化数据库*/
  12. >new ZKDatabase
  13. >ZKDatabase#createDataTree //创建数据树,所有的节点都会存储在这
  14. // 启动集群:同时启动线程
  15. > QuorumPeer#start //
  16. > QuorumPeer#loadDataBase // 从快照文件以及日志文件 加载节点并填充到dataTree中去
  17. > QuorumPeer#startServerCnxnFactory // 启动netty 或java nio 服务,对外开放2181 端口
  18. > AdminServer#start// 启动管理服务,netty http服务,默认端口是8080
  19. > QuorumPeer#startLeaderElection // 开始执行选举流程
  20. > quorumPeer.join() // 防止主进程退出

流程说明:

  1. main方法启动
  2. 1. 加载zoo.cfg 配置文件
  3. 2. 解析配置
  4. 3. 创建服务工厂
  5. 4. 创建集群管理线程
  6. 1. 设置数据库文件管理器
  7. 2. 设置数据库
  8. 3. ....设置设置
  9. 5. start启动集群管理线程
  10. 1. 加载数据节点至内存
  11. 2. 启动netty 服务,对客户端开放端口
  12. 3. 启动管理员Http服务,默认8080端口
  13. 4. 启动选举流程
  14. 6. join 管理线程,防止main 进程退出

4、netty 服务启动流程

服务UML类图

设置netty启动参数

  1. -Dzookeeper.serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory

初始化:

关键代码:

  1. #初始化管道流
  2. #channelHandler 是一个内部类是具体的消息处理器。
  3. protected void initChannel(SocketChannel ch) throws Exception {
  4. ChannelPipeline pipeline = ch.pipeline();
  5. if (secure) {
  6. initSSL(pipeline);
  7. }
  8. pipeline.addLast("servercnxnfactory", channelHandler);
  9. }

channelHandler 类结构

执行堆栈:

  1. NettyServerCnxnFactory#NettyServerCnxnFactory // 初始化netty服务工厂
  2. > NettyUtils.newNioOrEpollEventLoopGroup // 创建IO线程组
  3. > NettyUtils#newNioOrEpollEventLoopGroup() // 创建工作线程组
  4. >ServerBootstrap#childHandler(io.netty.channel.ChannelHandler) // 添加管道流
  5. >NettyServerCnxnFactory#start // 绑定端口,并启动netty服务

创建连接:

每当有客户端新连接进来,就会进入该方法 创建 NettyServerCnxn对象。并添加至cnxns对例

执行堆栈

  1. CnxnChannelHandler#channelActive
  2. >new NettyServerCnxn // 构建连接器
  3. >NettyServerCnxnFactory#addCnxn // 添加至连接器,并根据客户端IP进行分组
  4. >ipMap.get(addr) // 基于IP进行分组

读取消息:
执行堆栈

  1. CnxnChannelHandler#channelRead
  2. >NettyServerCnxn#processMessage // 处理消息
  3. >NettyServerCnxn#receiveMessage // 接收消息
  4. >ZooKeeperServer#processPacket //处理消息包
  5. >org.apache.zookeeper.server.Request // 封装request 对象
  6. >org.apache.zookeeper.server.ZooKeeperServer#submitRequest // 提交request
  7. >org.apache.zookeeper.server.RequestProcessor#processRequest // 处理请求

二、快照与事务日志存储结构

1、概要

ZK中所有的数据都是存储在内存中,即zkDataBase中。但同时所有对ZK数据的变更都会记录到事物日志中,并且当写入到一定的次数就会进行一次快照的生成。已保证数据的备份。其后缀就是ZXID(唯一事物ID)。

  • 事物日志:每次增删改,的记录日志都会保存在文件当中
  • 快照日志:存储了在指定时间节点下的所有的数据

2、存储结构

zkDdataBase 是zk数据库基类,所有节点都会保存在该类当中,而对Zk进行任何的数据变更都会基于该类进行。zk数据的存储是通过DataTree 对象进行,其用了一个map 来进行存储。

UML 类图:

读取快照日志:

  1. org.apache.zookeeper.server.SnapshotFormatter

读取事物日志:

  1. org.apache.zookeeper.server.LogFormatter

3、快照相关配置

dataLogDir 事物日志目录
zookeeper.preAllocSize 预先开辟磁盘空间,用于后续写入事务日志,默认64M
zookeeper.snapCount 每进行snapCount次事务日志输出后,触发一次快照,默认是100,000
autopurge.snapRetainCount 自动清除时 保留的快照数
autopurge.purgeInterval 清除时间间隔,小时为单位 -1 表示不自动清除。

4、快照装载流程

  1. >ZooKeeperServer#loadData // 加载数据
  2. >FileTxnSnapLog#restore // 恢复数据
  3. >FileSnap#deserialize() // 反序列化数据
  4. >FileSnap#findNValidSnapshots // 查找有效的快照
  5. >Util#sortDataDir // 基于后缀排序文件
  6. >persistence.Util#isValidSnapshot // 验证是否有效快照文件
 566

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2