Zookeeper集群中server数量总是确定的,所以集群中的server交互采用比较可靠的bio长连接模型;不同于集群中sever间交互zookeeper客户端其实数量是未知的,为了提高zookeeper并发性能,zookeeper客户端与服务器端交互采用nio模型。下面我们主要来讲讲zookeeper的服务器端与客户端的交互。读者对nio不了解的话不妨抽点时间去了解下,对于一些nio框架如netty,mina再如一些web容器如tomcat,jetty底层都实现一套nio框架,对于实现nio框架模型大家不妨去谷歌百度搜一下Doug Lea的scalable io in Java 这个ppt。

客户端

ClientCnxnSocketNIO是zookeeper的nio通讯层的客户端部分,下面伪代码示例其核心代码:

ClientCnxnSocketNIO{

doTransport() {

if (如果之前连接没有立马连上,则在这里处理OP_CONNECT事件) {

sendThread.primeConnection();

} else {

doIO

}

//队列中有发送的消息, 开启写

}

doIO() {

if (sockKey.isReadable()) {

sendThread.readResponse(incomingBuffer);

updateLastHeard();

}

if(sockKey.isWritable()) {

Packetp = outgoingQueue.getFirst() //从发送队列取

updateLastSend

p.requestHeader.setXid(cnxn.getXid());//设置客户端的xid

序列化

发送

从发送队列删除

加入到pendingQueue队列

}

}

}

ClientCnxn 是客户端操作ClientCnxnSocketNIO的工具,维护了发送任务线程SendThread,事件任务线程EventThead, 发送队列OutgoingQueue以及请求消息的等待队列PendingQueue。下面以伪代码来示例其核心代码

ClientCnxn {

outgoingQueue//待向服务器端发送的队列, 客户端提交请求放入这个队列

pendingQueue //发送以后等待响应的队列,

submitRequest(){

//client端一个封装成一个packet

outgoingQueue.add(packet);

selector.wakeup();

packet.wait(); //如果是同步调用wait,应该反馈后会

}

SendThread {

run() {

1.设置clientCnxnSocket 最后发送时间,最后的心跳时间

2. if(!clientCnxnSocket.isConnected()) {

startConnect()  //主要工作clientCnxnSocket做

} else {

计算下次ping的时间, 发送心跳

委托给 clientCnxnSocket.doTranspor进行底层的nio传输

}

}

primeConnection(){

//构建ConnectRequest

//组合成通讯层的Packet对象,添加到发送队列,对于ConnectRequest其requestHeader为null

outgoingQueue.addFirst

clientCnxnSocket.enableReadWriteOnly();//确保读写事件都监听

}

readResponse(){

1.先读响应头,先对特殊的xid进行处理

2. packet = pendingQueue.remove() //由于client和server都是单线程处理,多队列处理,所以认为全局有序

3. 反序列化响应体response, 并设置到packet上

4.finishPacket 1)同步notifyAll,结束 2)异步加入到event线程的队列

}

}

EventThread{ //主要支持异步的回调

run() {

}

}

}

大家观察客户端操作类Zookeeper里面的操作类主要分为两个参数不带callback的同步方法和参数带callback的异步方法。

1.      同步调用方法实现类似Future同步转异步模式实现

1)  Client提交请求对象封装成packet对象放入OutgoingQueue队列,并调用packet.wait()阻塞当前线程。

2)  每个Client都只有一个SendThread线程是线性处理OutgoingQueue中的请求消息的,SendThread线程通过ClientCnxnSocketNIO工具顺序从OutgoingQueue队列中取请求消息发送到服务器端,同时将请求packet加入到PendingQueue中

3)  ClientCnxnSocketNIO工具接收处理服务器端响应

4)  从PendingQueue队列取出对应的packet,并调packet.notifyAll()唤醒阻塞的线程完成同步调用

2.      异步调用的总体流程跟同步类似关键区别在于

1)  向OutgoingQueue队列提交请求后,不会调用packet.wait()阻塞当前线程,主流程继续执行

2)  同同步调用

3)  同同步调用

4)  从PendingQueue队列取出对应的packet,并调packet.callback方法完成回调处理

Zookeeper服务器端

NIOServerCnxnFactory工厂类,zookeeperserver用来启动监听客户端连接,每当有客户端请求连接进来,NIOServerCnxnFactory都会为这个链接构建NIOServerCnxn 实例来单独处理与这个客户端的交互

NIOServerCnxn封装了处理读取客户端请求数据与及向客户端响应数据

下面通过伪代码来实例:

NIOServerCnxnFactory  {

configure {

绑定端口

作为server监听

注册selectkey 的连接时间

}

run {  //起到accept的作用

1. OP_ACCEPT, 将NIOServerCnxn(handler) attach到selectkey以便被读写事件使用

2. OP_READ 和 OP_WRITE取出handler NIOServerCnxn,并调doIo

}

}

NIOServerCnxn {

构造器 {

//设置selectkey对read感兴趣

}

doIo {

if(k.isReadable()) {

1. 读前四个字节, 代表请求内容长度,不包括自己的4字节

2. 读取到字节数组中

3. zkServer.processPacket()或者zkServer.processConnectRequest()

}

if(k.isWritable()) {

1.从outgoingBuffers取ByteBuffer

2.发送bytes

}

}

}

zookeeper原理解析-客户端与服务器端交互的更多相关文章

  1. 浅析Java web程序之客户端和服务器端交互原理(转)

    转载自http://www.cnblogs.com/lys_013/archive/2012/05/05/2484561.html 1. 协议 a. TCP/IP整体构架概述 TCP/IP协议并不完全 ...

  2. [转]HTTP报文接口及客户端和服务器端交互原理

    1. 协议 a. TCP/IP整体构架概述 TCP/IP协议并不完全符合OSI的七层参考模型.传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务.该模型的目的 ...

  3. 浅析Java web程序之客户端和服务器端交互原理

    原文链接: https://www.iteye.com/topic/470019 1. 协议 a. TCP/IP整体构架概述 TCP/IP协议并不完全符合OSI的七层参考模型.传统的开放式系统互连参考 ...

  4. Request 接收参数乱码原理解析一:服务器端解码原理

    “Server.UrlDecode(Server.UrlEncode("北京")) == “北京””,先用UrlEncode编码然后用UrlDecode解码,这条语句永远为true ...

  5. zookeeper原理解析-服务器端处理流程

    1)处理器链 这部分内容我们主要讲解zookeeper请求在zookeeper server端的处理流程,对于不同角色的zookeeper具有不同的处理流程, ZookeepeerServer的sta ...

  6. zookeeper原理解析-数据存储

    Zookeeper内存结构 Zookeeper是怎么存储数据的,什么机制保证集群中数据是一致性,在网络异常,当机以及停电等异常情况下恢复数据的,我们知道数据库给我们提供了这些功能,其实zookeepe ...

  7. zookeeper原理解析-选举

    1)QuorumPeerMain加载 Zookeeper集群启动的入口类是QuorumPeerMain来加载配置启动QuorumPeer线程.首先我们来看下QuorumPeer, 谷歌翻译quorum ...

  8. zookeeper原理解析-序列化

    1)底层通信数据封装与操作           BinaryInputArchive& BinaryOutputArchive底层通信数据封装与操作     BinaryInputArchiv ...

  9. TCP网络协议通信原理(客户端和服务器端)

    下面直接用代码来说明TCP协议的基础知识: 服务器端代码块: from socket import * from time import ctime ''' 指定主机地址.工作端口号.接收缓存的长度 ...

随机推荐

  1. jQuery fsBanner 手风琴

    fsbanner是一款自定义功能丰富的响应式网站Banner手风琴特效jQuery插件.该手风琴特效兼容性很好,支持点击和鼠标滑过等触发事件,并且可添加标题或描述. 在线实例 默认 带标题 鼠标滑过 ...

  2. 实现一个基于 SharePoint 2013 的 Timecard 应用(下)

    现在,基于 Timecard 数据来一点儿数据分析. 应用需求 对于 Timecard,分析下面 2 个方面: 对于单个项目,分析其中每个成员的工时占比,以此了解工作量分配,为组间人员调度提供参考. ...

  3. ArcGIS Engine开发之地图基本操作(4)

    ArcGIS Engine开发中数据库的加载 1.加载个人地理数据库数据 个人地理数据库(Personal Geodatabase)使用Miscrosoft Access文件(*.mdb)进行空间数据 ...

  4. 仿喜马拉雅实现ListView添加头布局和脚布局

     ListView添加头布局和脚布局 之前学习喜马拉雅的时候做的一个小Demo,贴出来,供大家学习参考: 如果我们当前的页面有多个接口.多种布局的话,我们一般的选择无非就是1.多布局:2.各种复杂滑动 ...

  5. GitLab CI持续集成配置方案(补)

    上篇文章介绍了GitLab CI的持续集成配置方法,本篇文章将主要介绍NUnit的持续集成和遇到的一些坑 1.NUnit单元测试持续集成 下载NUnit.3.4.1.msi,https://githu ...

  6. HTML之DocType的几种类型 -转载

    HTML之DocType的几种类型转载 doctype类型详细doctype的几种类型html之doctype 分类: 前端文摘  在默认情况下,FF和IE的解释标准是不一样的,也就是说,如果一个网页 ...

  7. 当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式。

    当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式.比如 select * from T_Employee where FNumber not in ( select top 5*  ...

  8. SQL必知必会 14-22(完)

    博主依然不想打字,又向你仍来了一堆代码... 13(续) 在SELECT中用COUNT()以及联合 mysql> SELECT customers.cust_id,COUNT(orders.or ...

  9. JS--浏览器兼容之new Date

    Js 中有一个Date属性. 我们可以通过new Date(formatString) 来生命日期. 不过生命日期里面有一个坑就是. new Date('2016-05-13'), Chrome 和 ...

  10. JavaScript自动生成博文目录导航

    转载于:JavaScript自动生成博文目录导航 我们在写博客的时候,如果博文里面有目录,会给人结构清晰.一种一目了然的感觉,看目录就知道这篇博文要讲解的内容,并且点击目录标题就可以跳转到 具体的内容 ...