Zookeeper ZAB协议-客户端源码解析
因为在Zookeeper的底层源码中大量使用了NIO,线程和阻塞队列,在了解之前对前面这些有个基础会更容易理解
ZAB 是Zookeeper 的一种原子广播协议,用于支持Zookeeper 的分布式协调一致性和奔溃恢复的一种,但是ZAB 协议的源码比上一篇Zookeeper的Leader选举算法要复杂一些,所以分多篇进行分析
首先来一张简单的架构图,对Zookeeper客户端架构有个基本概念
这里从客户端开始,我们来看一下zk 的一个简单使用,下面是创建zk客户端,然后创建一个节点
new Zookeeper
见Zookeeper
zookeeper.create
见zookeeper.create
Zookeeper客户端初始化
Zookeeper
createConnection
实际上是创建了一个ClientCnxn
对象,在这个对象中保存了一些数据,比如苏红zookeeper
自身引用,监视器,sessionId
,过期时间,配置信息, 这里我们需要重点关注的是创建了两个线程sendThread
,eventThread
,这两个线程一个是用于发送数据,一个是用于事件处理的,详见ClientCnxn
zk 客户端启动,详见cnxn.start
ClientCnxn
ClientCnxn#start
cnxn.start
这里很简单,就是直接启动了初始化创建的两个线程,sendThread
,eventThread
, 因为这是两个线程,start 方法实际上是调用了该线程的run 方法
sendThread见 sendThread.run
eventThread 见 sendThread.run
SendThread#run
sendThread.run
因为这里暂时只分析主流程,有些分支流程就暂时先跳过了
这里主要是做了几件事,
1:zookeeper服务端连接,见sendThrad.startConnect
2:发送数据,见 ClientCnxnSocketNIO.doTransport
3:保持心跳连接,见
SendThread#startConnect
sendThrad.startConnect
因为我们这里采用的是默认的模式,在上文中已经创建了ClientCnxnSocketNIO
这个对象, 实际上就是使用NIO 的方式进行连接,具体如下图,代码很简单,如果有NIO 的基础,应该很好理解,就不再深入分析
ClientCnxnSocketNIO#doTransport
ClientCnxnSocketNIO.doTransport
我们默认是client 已经和ZK server 连接成功了,,这里线程已经启动完成了,然后阻塞在select 方法上,下面我们走zookeeper.create
的逻辑zookeeper.create
当执行完create后,selector 被唤醒了,同时outgoingQueue队列中存在数据,然后会执行后续发送数据的IO 操作,我们来看doIO
ClientCnxnSocketNIO#doIO
Zookeeper.create
在create方法中,主要是构建了请求参数,然后调用socket 的submitRequest
,提交请求服务端,详情见clientCnxn.submitRequest
ClientCnxn.submitRequest
总结一下:这里主要干下面几件事
1: 将请求参数封装成一个Packet,然后放到outgoingQueue
阻塞队列中,然sendThread 处理
2: 将当前线程wait 住, 等待完成或者请求超时后唤醒
3: 请求超时后的一些处理
ClientCnxn.queuePacket
ClientCnxnSocketNIO#doIO
在这个方法中主要执行两个步骤,因为代码较长,所以这一块分开进行分析
1:执行写事件
总结一下:
1:从一个outgoingQueue
队列中拿到一个Packet 数据, 因为前面我们执行create 逻辑的时候,已经往outgoingQueue
中放入数据了,所以这里是存在数据的
2: 如果这个Packet没有创建ByteBuffer
,那么创建一个ByteBuffer,并且赋值给packet 对象的bb 属性
3: 利用socket将packet数据发送出去
4:发送完成后,将packet数据添加到一个等待服务端响应的链表中
2:执行读事件
因为zk 请求会先发4个字节作为整个报文的长度,所以会创建一个指定大小的buffer空间来接收后续请求。具体读取数据在SendThread#readResponse
SendThread#readResponse
SendThread#readResponse
总结一下:在上述代码中总共干了几件事
1: 根据返回的数据类型,会走一些其他逻辑,比如心跳,权限认证
2: 如果返回的类型是-1, 说明是监听了节点数据变动后返回的结果,那么会创建一个监听结果事件放入到eventThrad 的waitingEvents 队列中,见EventThread#queueEvent
3: 如果是普通的结果,那么会从等待响应队列pendingQueue
中删除这次请求的packet
4: 根据packet 重置一些属性,比如事务id,反序列化响应信息
5: 执行结束packet 的方法,然后执行一些逻辑, 见ClientCnxn#finishPacket
ClientCnxn#finishPacket
EventThread#run
下面来看一下事件处理线程
eventThread run 方法总共执行了两个功能
1: 循环从事件的阻塞队列中获取事件
2: 执行事件 ClientCnxn.processEvent
ClientCnxn.processEvent
// 这里if 判断比较多,所以只展示了其中的一个同步的逻辑,有些分支逻辑是异步回调的逻辑
if (event instanceof WatcherSetEventPair) {
// each watcher will process the event
WatcherSetEventPair pair = (WatcherSetEventPair) event;
for (Watcher watcher : pair.watchers) {
try { // 在这里调用了我们传入的watcher 的process方法,实现通知
watcher.process(pair.event);
} catch (Throwable t) {
LOG.error("Error while calling watcher ", t);
}
}
}
EventThread#queueEvent
Zookeeper ZAB协议-客户端源码解析的更多相关文章
- FileZilla客户端源码解析
FileZilla客户端源码解析 FTP是TCP/IP协议组的协议,有指令通路和数据通路两条通道.一般来说,FTP标准命令TCP端口号是21,Port方式数据传输端口是20. FileZilla作为p ...
- 设置ZooKeeper服务器地址列表源码解析及扩展
设置ZooKeeper服务器地址列表源码解析及扩展 ZooKeeper zooKeeper = new ZooKeeper("192.168.109.130:2181",SESSI ...
- Netty5客户端源码解析
Netty5客户端源码解析 今天来分析下netty5的客户端源码,示例代码如下: import io.netty.bootstrap.Bootstrap; import io.netty.channe ...
- Feign 客户端源码解析
Feign的使用非常简单,增加如下配置之后,便可以使用Feign进行调用.非常简单是不是.主要的工作由Feign框架完成.业务代码只提供了一个Interface, 然后由Feign动态生成代理类来实现 ...
- Spring Cloud系列(四):Eureka源码解析之客户端
一.自动装配 1.根据自动装配原理(详见:Spring Boot系列(二):Spring Boot自动装配原理解析),找到spring-cloud-netflix-eureka-client.jar的 ...
- 第零章 dubbo源码解析目录
第一章 第一个dubbo项目 第二章 dubbo内核之spi源码解析 2.1 jdk-spi的实现原理 2.2 dubbo-spi源码解析 第三章 dubbo内核之ioc源码解析 第四章 dubb ...
- [源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader
[源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader 目录 [源码解析] PyTorch 分布式(2) --- 数据加载之DataLoader 0x00 摘要 0x01 ...
- zookeeper集群搭建及Leader选举算法源码解析
第一章.zookeeper概述 一.zookeeper 简介 zookeeper 是一个开源的分布式应用程序协调服务器,是 Hadoop 的重要组件. zooKeeper 是一个分布式的,开放源码的分 ...
- dubbo源码解析-zookeeper创建节点
前言 在之前dubbo源码解析-本地暴露中的前言部分提到了两道高频的面试题,其中一道dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?在上周的dubbo源码 ...
- Zookeeper 源码(三)Zookeeper 客户端源码
Zookeeper 源码(三)Zookeeper 客户端源码 Zookeeper 客户端主要有以下几个重要的组件.客户端会话创建可以分为三个阶段:一是初始化阶段.二是会话创建阶段.三是响应处理阶段. ...
随机推荐
- 并发JUC
JUC初级 • 1.什么是 JUC • 2.Lock 接口 • 3.线程间通信 • 4.集合的线程安全 • 5.多线程锁 • 6.Callable 接口 • 7.JUC 三大辅助类: CountDow ...
- iperf3带宽性能检测工具
iperf3用来测试两个节点之间的带宽传输,无论是几百k,还是几个G,基本可以满足两端的带宽测速. 1.软件环境 iperf3常用 windows环境 官网下载安装包,下载完成后解压,使用时,切换到c ...
- 深入理解JVM - 自动内存管理
对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们既是拥有最高权力的"皇帝",又是从事最基础工作的劳动人民--既拥有每一个对象的"所有权",又担负着 ...
- C语言中关于宏定义的学习
1.C语言中宏定义的使用 2.GCC官方文档 3.C语言宏定义的几个坑和特殊用法
- Nacos配置管理
一.在Nacos添加公共配置 二.项目中读取方式 1. 引入nacos-config依赖 首先,在要使用 nacos 来管理配置的服务中,引入nacos-config 依赖: <!--nacos ...
- Linux,Lnmp配置Index of /索引页
其实很简单就是修改conf配置文件 进入域名对应的vhost修改conf文件: 第一种方法 cd /usr/local/nginx/vhost/ 在清楚当前域名所对用的conf文件可以试用 ll 列出 ...
- redis底层数据结构之压缩列表(ziplist)
压缩列表(ziplist) 压缩列表(ziplist)是redis 为了节约内存而开发的,由连续内存块组成的顺序型数据结构,适用于长度较小的值 存取的效率高,内存占用小,但由于内存是连续的,在修改的时 ...
- SAR成像(六):距离徙动矫正
1.什么是距离徙动? 距离徙动产生原因是合成孔径雷达的运动平台与目标之间的相对运动.对于地面一静止的点目标,当它处于雷达波束照射范围内的时间中时,随着飞行载体的运动,它与雷达飞行载体之间的距离会不断的 ...
- 蓝牙mesh组网实战(智能家居应用)
目录 蓝牙mesh组网目前存在有入门门槛高的问题,比如,嵌入式工程师需要考虑到标准mesh模型的兼容,app开发工程师需要了解mesh协议栈才能直接走mesh与芯片通信.而沁恒官方提供的透传模型简洁易 ...
- SpringBoot 启动报循环依赖问题
问题现象 Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating b ...