一、前言

  前篇博客分析了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客户端的更多相关文章

  1. 【分布式】Zookeeper客户端基本的使用

    与mysql.redis等软件一样,zookeeper的软件包中也提供了客户端程序用于对服务器上的数据进行操作.本节我们就来学习zookeeper客户端的使用方法.不过在详细讲解zk客户端的使用方法之 ...

  2. zookeeper 客户端编程

    zookeeper是一个分布式的开源的分布式协调服务,用它可以来现同步服务,配置维护.zookeeper的稳定性也是可以保证的,笔者曾参与过的使用zookeeper的两个应用,一个是用zookeepe ...

  3. zookeeper客户端操作

    ZooKeeper客户端 zkCli.sh 节点的增删改查 在 bin 目录下的  zkCli.sh  就是ZooKeeper客户端 ./zkCli.sh -timeout 5000  -server ...

  4. Zookeeper客户端Curator基本API

    在使用zookeper的时候一般不使用原生的API,Curator,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连.反复注册Watcher和NodeExistsExceptio ...

  5. Zookeeper客户端Curator的使用,简单高效

    Curator是Netflix公司开源的一个Zookeeper客户端,与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeeper客户端的开发量. 1.引入依赖: ...

  6. ZooKeeper客户端 zkCli.sh 节点的增删改查

    zkCli.sh 在 bin 目录下的  zkCli.sh  就是ZooKeeper客户端 ./zkCli.sh -timeout 5000  -server 127.0.0.1:2181  客户端与 ...

  7. Zookeeper客户端Curator使用详解

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

  8. zookeeper(六):Zookeeper客户端Curator的API使用详解

    简介 Curator是Netflix公司开源的一套zookeeper客户端框架,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连.反复注册Watcher和NodeExistsEx ...

  9. Zookeeper客户端对比选择_4

    Zookeeper客户端对比选择 本文思维导图 使用框架的好处是自带一套实用的API,但是Zookeeper虽然非常强大,但是社区却安静的可怕,版本更新较慢,下面会先从zookeeper原生API的不 ...

随机推荐

  1. RxJS + Redux + React = Amazing!(译一)

    今天,我将Youtube上的<RxJS + Redux + React = Amazing!>翻译(+机译)了下来,以供国内的同学学习,英文听力好的同学可以直接看原版视频: https:/ ...

  2. solr服务中集成IKAnalyzer中文分词器、集成dataimportHandler插件

    昨天已经在Tomcat容器中成功的部署了solr全文检索引擎系统的服务:今天来分享一下solr服务在海量数据的网站中是如何实现数据的检索. 在solr服务中集成IKAnalyzer中文分词器的步骤: ...

  3. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  4. ASP.NET Core应用中如何记录和查看日志

    日志记录不仅对于我们开发的应用,还是对于ASP.NET Core框架功能都是一项非常重要的功能特性.我们知道ASP.NET Core使用的是一个极具扩展性的日志系统,该系统由Logger.Logger ...

  5. C# 索引器,实现IEnumerable接口的GetEnumerator()方法

    当自定义类需要实现索引时,可以在类中实现索引器. 用Table作为例子,Table由多个Row组成,Row由多个Cell组成, 我们需要实现自定义的table[0],row[0] 索引器定义格式为 [ ...

  6. bzoj1079--记忆化搜索

    题目大意:有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得 ...

  7. 设计模式C#合集--抽象工厂模式

    抽象工厂,名字就告诉你是抽象的了.上代码. public interface BMW { public void Drive(); } public class BMW730 : BMW { publ ...

  8. Jqprint实现页面打印

    好些项目需要实现页面打印,特别是一些后台管理类系统,下面介绍一款轻量级的打印插件: 1.实现页面打印要引入jQuery和Jqprint.点击下载Jqprint插件 <script languag ...

  9. CSS margin详解

    以下的分享是本人最近几天学习了margin知识后,大有启发,感觉以前对margin的了解简直太浅薄.所以写成以下文章,一是供自己整理思路:二是把知识分享出来,避免各位对margin属性的误解.内容可能 ...

  10. [Android]使用Dagger 2来构建UserScope(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6237731.html 使用Dagger 2来构建UserSco ...