作者:leesf    掌控之中,才会成功;掌控之外,注定失败。出处:http://www.cnblogs.com/leesf456/p/6098255.html 尊重原创,共同学习进步; 

一、前言

  前篇博客分析了Zookeeper的序列化和通信协议,接着继续学习客户端,客户端是开发人员使用Zookeeper最主要的途径,很有必要弄懂客户端是如何与服务端通信的。

二、客户端

  2.1 客户端组成

  Zookeeper客户端主要由如下核心部件构成。

  1. Zookeeper实例,客户端入口。

  2. ClientWatchManager, 客户端Watcher管理器。

  3. HostProvider,客户端地址列表管理器。

  4. ClientCnxn,客户端核心线程,内部包含了SendThread和EventThread两个线程,SendThread为I/O线程,主要负责Zookeeper客户端和服务器之间的网络I/O通信;EventThread为事件线程,主要负责对服务端事件进行处理。

  Zookeeper客户端初始化与启动环节,就是Zookeeper对象的实例化过程。客户端在初始化和启动过程中大体可以分为如下3个步骤

  1. 设置默认Watcher

  2. 设置Zookeeper服务器地址列表

  3. 创建ClientCnxn。

  若在Zookeeper构造方法中传入Watcher对象时,那么Zookeeper就会将该Watcher对象保存在ZKWatcherManager的defaultWatcher中,并作为整个客户端会话期间的默认Watcher。

  2.2 会话的创建

  下图表示了客户端与服务端会话建立的整个过程,包括初始化阶段(第一阶段)、会话创建阶段(第二阶段)、响应处理阶段(第三阶段)三个阶段。

  2.3 服务器地址列表

  在实例化Zookeeper时,用户传入Zookeeper服务器地址列表,如192.168.0.1:2181,192.168.0.2:2181,192.168.0.3:2181,此时,Zookeeper客户端在连接服务器的过程中,是如何从这个服务器列表中选择服务器的呢?Zookeeper收到服务器地址列表后,会解析出chrootPath和保存服务器地址列表。

  1. Chroot,每个客户端可以设置自己的命名空间,若客户端设置了Chroot,此时,该客户端对服务器的任何操作都将被限制在自己的命名空间下,如设置Choot为/app/X,那么该客户端的所有节点路径都是以/app/X为根节点。

  2. 地址列表管理,Zookeeper使用StaticHostProvider打散服务器地址(shuffle),并将服务器地址形成一个环形循环队列,然后再依次取出服务器地址。

  2.4 网络I/O

  ClientCnxn是Zookeeper客户端中负责维护客户端与服务端之间的网络连接并进行一系列网络通信的核心工作类,Packet是ClientCnxn内部定义的一个堆协议层的封装,用作Zookeeper中请求和响应的载体。Packet包含了请求头(requestHeader)、响应头(replyHeader)、请求体(request)、响应体(response)、节点路径(clientPath/serverPath)、注册的Watcher(watchRegistration)等信息,然而,并非Packet中所有的属性都在客户端与服务端之间进行网络传输,只会将requestHeader、request、readOnly三个属性序列化,并生成可用于底层网络传输的ByteBuffer,其他属性都保存在客户端的上下文中,不会进行与服务端之间的网络传输

  ClientCnxn维护着outgoingQueue(客户端的请求发送队列)和pendingQueue(服务端响应的等待队列),outgoingQueue专门用于存储那些需要发送到服务端的Packet集合,pendingQueue用于存储那些已经从客户端发送到服务端的,但是需要等待服务端响应的Packet集合。

  在正常情况下,会从outgoingQueue中取出一个可发送的Packet对象,同时生成一个客户端请求序号XID并将其设置到Packet请求头中去,然后序列化后再发送,请求发送完毕后,会立即将该Packet保存到pendingQueue中,以便等待服务端响应返回后进行相应的处理。

  客户端获取到来自服务端的完整响应数据后,根据不同的客户端请求类型,会进行不同的处理。

  1. 若检测到此时客户端尚未进行初始化,那么说明当前客户端与服务端之间正在进行会话创建,直接将接收的ByteBuffer序列化成ConnectResponse对象。

  2. 若当前客户端已经处于正常会话周期,并且接收到服务端响应是一个事件,那么将接收的ByteBuffer序列化成WatcherEvent对象,并将该事件放入待处理队列中。

  3. 若是一个常规请求(Create、GetData、Exist等),那么从pendingQueue队列中取出一个Packet来进行相应处理。首先会检验响应中的XID来确保请求处理的顺序性,然后再将接收到的ByteBuffer序列化成Response对象。

  SendThread是客户端ClientCnxn内部的一个核心I/O调度线程,用于管理客户端与服务端之间的所有网络I/O操作,在Zookeeper客户端实际运行中,SendThread的作用如下:

  1. 维护了客户端与服务端之间的会话生命周期(通过一定周期频率内向服务端发送PING包检测心跳),如果会话周期内客户端与服务端出现TCP连接断开,那么就会自动且透明地完成重连操作。

  2. 管理了客户端所有的请求发送和响应接收操作,其将上层客户端API操作转换成相应的请求协议并发送到服务端,并完成对同步调用的返回和异步调用的回调。

  3. 将来自服务端的事件传递给EventThread去处理。

  EventThread是客户端ClientCnxn内部的一个事件处理线程,负责客户端的事件处理,并触发客户端注册的Watcher监听。EventThread中的watingEvents队列用于临时存放那些需要被触发的Object,包括客户端注册的Watcher和异步接口中注册的回调器AsyncCallback。同时,EventThread会不断地从watingEvents中取出Object,识别具体类型(Watcher或AsyncCallback),并分别调用process和processResult接口方法来实现对事件的触发和回调。

三、总结

  本篇博文讲解了客户端的相关细节,本篇内容我没有看的很明白,先转发,等着以后再慢慢理解,该模块知识会为之后分析源码打下好的基础,

zookeeper系列(八)zookeeper客户端的底层详解的更多相关文章

  1. BootStrap 智能表单系列 八 表单配置json详解

    本章属于该系列的高级部分,将介绍表单中一些列的配置 1.config列的配置: 主要用于控制布局 :config:{autoLayout:true|'1,2,2,4'} true:根据配置项最里层的数 ...

  2. Zookeeper客户端Curator使用详解

    Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBoot.Curator.Bootstrap写了一个可视化的Web应用: zookeep ...

  3. 转:Zookeeper客户端Curator使用详解

    原文:https://www.jianshu.com/p/70151fc0ef5d Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBo ...

  4. Linux Shell系列教程之(八)Shell printf命令详解

    本文是Linux Shell系列教程的第(八)篇,更多shell教程请看:Linux Shell系列教程 在上一篇:Linux Shell系列教程之(七)Shell输出这篇文章中,已经对Shell p ...

  5. Python操作redis系列以 哈希(Hash)命令详解(四)

    # -*- coding: utf-8 -*- import redis #这个redis不能用,请根据自己的需要修改 r =redis.Redis(host=") 1. Hset 命令用于 ...

  6. Netty学习——服务器端代码和客户端代码 原理详解

    服务器端代码和客户端代码 原理详解:(用到的API) 0.Socket 连接服务器端的套接字 1.TcompactProtocol   协议层2.TFrameTransport   传输层3.THsh ...

  7. Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...

  8. Java 8新特性探究(八)精简的JRE详解

    http://www.importnew.com/14926.html     首页 所有文章 资讯 Web 架构 基础技术 书籍 教程 Java小组 工具资源 - 导航条 - 首页 所有文章 资讯 ...

  9. Android为TV端助力 转载:Android绘图Canvas十八般武器之Shader详解及实战篇(上)

    前言 Android中绘图离不开的就是Canvas了,Canvas是一个庞大的知识体系,有Java层的,也有jni层深入到Framework.Canvas有许多的知识内容,构建了一个武器库一般,所谓十 ...

随机推荐

  1. C 中 char、signed char 和 unsigned char 的区别

    C 中 char.signed char 和 unsigned char 的区别 来源:http://bbs.chinaunix.net/thread-889260-1-1.html 参考:https ...

  2. [转载]深入理解maven构建生命周期和各种plugin插件

    我就不复制博主文章了,到原文地址看吧.写这个只是为了自己搜索起来方便些: https://blog.csdn.net/zhaojianting/article/details/80321488 htt ...

  3. O027、看nova-scheduler如何选择计算节点

    参考https://www.cnblogs.com/CloudMan6/p/5441782.html   本节重点介绍 nova-scheduler 的调度机制和实现方法:即解决如何选择在那个计算节点 ...

  4. C# 知识点笔记:IEnumerable<>的使用,利用反射动态调用方法

    IEnumerable<T>的使用 创建一个IEnumerable对象 List<string> fruits = new List<string> { " ...

  5. tomcat启动程序乱码和tomcat启动程序的标题乱码处理

    启动程序运行中的文字乱码: 解决方案: 找到Tomcat目录下conf文件夹中的logging.properties文件, 打开logging.properties文件,找到文件中的java.util ...

  6. Python3简易接口自动化测试框架设计与实现(上)

    目录 1.开发环境 2.用到的模块 3.框架设计 3.1.流程 3.2.项目结构 5.日志打印 6.接口请求类封装 接口开发请参考:使用Django开发简单接口:文章增删改查 1.开发环境 操作系统: ...

  7. deep_learning_Function_tf.equal(tf.argmax(y, 1),tf.argmax(y_, 1))用法

    [Tensorflow] tf.equal(tf.argmax(y, 1),tf.argmax(y_, 1))用法 作用:输出正确的预测结果利用tf.argmax()按行求出真实值y_.预测值y最大值 ...

  8. DA_04_解决Xshell中文乱码问题

    一:解决Xshell中文乱码问题      二:解决克隆后eth0不见的问题 2.1:虚拟机克隆步骤:          1.直接修改  /etc/sysconfig/network-script/i ...

  9. C++中虚函数的作用和虚函数的工作原理

    1 C++中虚函数的作用和多态 虚函数: 实现类的多态性 关键字:虚函数:虚函数的作用:多态性:多态公有继承:动态联编 C++中的虚函数的作用主要是实现了多态的机制.基类定义虚函数,子类可以重写该函数 ...

  10. MyBatis 报错org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource

    报错如下: org.apache.ibatis.exceptions.PersistenceException: ### Error opening session. Cause: java.lang ...