转载请注明出处:jiq•钦's technical Blog

假设不了解SocketChannel和Selector。请先阅读我的还有一篇博文:点击打开链接

ZooKeeper的启动从QuorumPeerMain类的main函数開始:

调用顺序是: Main -> initializeAndRun-> runFromConfig

一、默认的NIOServerCnxnFactory通信方式

当中runFromConfig主要做了两件事情:

(1)初始化client与服务端的网络通信处理类ServerCnxnFactory:

ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();

而createFactory函数的内部实现是:

if (serverCnxnFactoryName == null) {
serverCnxnFactoryName = NIOServerCnxnFactory.class.getName();
} try {
return(ServerCnxnFactory) Class.forName(serverCnxnFactoryName).newInstance();
} catch (Exception e) {
IOException ioe = new IOException("Couldn't instantiate "
+ serverCnxnFactoryName);
ioe.initCause(e);
throw ioe;
}

能够看到默认初始化的ServerCnxnFactory是NIOServerCnxnFactory,这是Java NIO方式的网络通信,另外还有NettyServerCnxnFactory类提供Netty通信方式。

(2)启动QuorumPeer:

quorumPeer.start();

内部会调用初始化好的ServerCnxnFactory类的start函数:

cnxnFactory.start();

二、NIOServerCnxnFactory.start()方法

@Override
publicvoidstart() {
stopped = false;
if (workerPool == null){
workerPool = new WorkerService(
"NIOWorker", numWorkerThreads, false);
} //先启动一堆selector线程
for(SelectorThread thread : selectorThreads) {
if (thread.getState() == Thread.State.NEW) {
thread.start();
}
} //再启动accept线程
if (acceptThread.getState() == Thread.State.NEW) {
acceptThread.start();
} //最后启动expire线程
if (expirerThread.getState() ==Thread.State.NEW){
expirerThread.start();
}
}

三、NIOServerCnxnFactory中几个线程类的关系

NIOServerCnxnFactory中包括了三个类:

(1)AbstractSelectThread:SelectorThread类和AcceptThread类的共同父类,维护了一个selector选择器对象

(2)AcceptThread:管理新的ZooKeeper client连接请求,实际上就是利用父类的选择器selector监听ServerSocketChannel的“SelectionKey.OP_ACCEPT”事件,一旦来新的请求,负责建立好和client的连接SocketChannel,并从SelectorThread线程池分配一个线程。将该SocketChannel连接放入SelectorThread线程维护的acceptedQueue队列中。

(3)SelectorThread:监听AcceptThread分配的已经建立的SocketChannel连接上发生的数据读写事件,并运行实际数据读写。

实际上就是利用父类的选择器selector监听在acceptedQueue队列中建立好的连接的数据读写事件。一旦读写事件发生,调用handleIO函数处理读写请求。

以下是读写事件监听线程的线程池selectorThreads的初始化:

for(inti=0; i<numSelectorThreads;++i) {
selectorThreads.add(newSelectorThread(i));
}

以下是新连接管理线程acceptThread的初始化:

this.ss =ServerSocketChannel.open();
ss.socket().setReuseAddress(true);
LOG.info("binding to port " + addr);
ss.socket().bind(addr);
ss.configureBlocking(false);
acceptThread= newAcceptThread(ss, addr, selectorThreads);

然后NIOServerCnxnFactory.start()将会启动这些线程。

AcceptThread的run函数非常easy。就是监听连接SelectionKey.op_accept事件,然后建立SocketChannel连接。并分配一个SelectorThread线程来处理该连接,详细就不详述了。

SelectorThread的run函数核心就是监听到SelectionKey.OP_READ事件后运行handleIO函数,详细怎样和client进行数据交互计划放在其它文章中介绍。

Java IO:SocketChannel和Selector在ZooKeeper中应用的更多相关文章

  1. hbase异常:java.io.IOException: Unable to determine ZooKeeper ensemble

    项目中用到hbase,有时候可能会报一些异常,比如java.io.IOException: Unable to determine ZooKeeper ensemble 等等,当出现这个问题时,根据个 ...

  2. Java IO:如何得到Jar包中内嵌Jar包的时间戳

    ClassLoader bladeClassLoader = BladeCLI.class.getClassLoader(); URL url = bladeClassLoader.getResour ...

  3. Java IO流及应用(一)

    IO流 IO流概述及FileWriter类的使用 FileReader类使用 缓冲流介绍和使用 IO流相关案例 NO.one IO流概述及FileWriter类使用 1.1 IO流概述及分类 IO流用 ...

  4. kafka启动时出现FATAL Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer) java.io.IOException: Permission denied错误解决办法(图文详解)

    首先,说明,我kafk的server.properties是 kafka的server.properties配置文件参考示范(图文详解)(多种方式) 问题详情 然后,我启动时,出现如下 [hadoop ...

  5. JDK1.8 java.io.Serializable接口详解

    java.io.Serializable接口是一个标志性接口,在接口内部没有定义任何属性与方法.只是用于标识此接口的实现类可以被序列化与反序列化.但是它的奥秘并非像它表现的这样简单.现在从以下几个问题 ...

  6. java IO流 (一) File类的使用

    1.File类的理解* 1. File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)* 2. File类声明在java.io包下* 3. File类中涉及到关于文件或文件目录的创建.删除.重 ...

  7. 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?

    原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...

  8. HBase中此类异常解决记录org.apache.hadoop.ipc.RemoteException(java.io.IOException):

    ERROR: Can't get master address from ZooKeeper; znode data == null   一定注意这只是问题的第一层表象,真的问题是: File /hb ...

  9. zookeeper报错: org.I0Itec.zkclient.exception.ZkMarshallingError: java.io.EOFException

    zookeeper报错: org.I0Itec.zkclient.exception.ZkMarshallingError: java.io.EOFException 主要因为是没有序列化. 可以使用 ...

随机推荐

  1. 紫书 例题 10-21 UVa 11971(连续概率)

    感觉这道题的转换真的是神来之笔 把木条转换成圆,只是切得次数变多一次 然后只要有一根木条长度为直径就租不成 其他点的概率为1/2^k 当前这个点的有k+1种可能 所以答案为1 - (k+1)/2^k ...

  2. 题解 UVA10328 【Coin Toss】

    这道题目其实就是说有N张纸牌,问至少连续K张正面朝上的可能性是多少. 可以用递推做.首先我们将题目所求从 至少K张 转化为 总数 - 至多K张 (为什么要这样自己想) 设F[i][j]为前i个纸牌至多 ...

  3. vector容器的实现

    简单实现了构造.析构.push_back.pop_back.operator=.operator[].clear等函数 template<class T> class my_vector ...

  4. POJ 3150 Cellular Automaton(矩阵高速幂)

    题目大意:给定n(1<=n<=500)个数字和一个数字m,这n个数字组成一个环(a0,a1.....an-1).假设对ai进行一次d-step操作,那么ai的值变为与ai的距离小于d的全部 ...

  5. JSR 303 - Bean Validation 简单介绍及用法

    一.JSR-303简单介绍 JSR-303 是 JAVA EE 6 中的一项子规范.叫做 Bean Validation,官方參考实现是Hibernate Validator. 此实现与 Hibern ...

  6. Spark修炼之道(高级篇)——Spark源代码阅读:第十二节 Spark SQL 处理流程分析

    作者:周志湖 以下的代码演示了通过Case Class进行表Schema定义的样例: // sc is an existing SparkContext. val sqlContext = new o ...

  7. 【HeadFirst设计模式——开篇】

    近期在看HeadFirst,接下来的一段时间会陆续更新有关HeadFirst设计模式相关的文章.记得非常久之前在学习大话设计模式的时候,仅仅是走马观花的大致走过一遍.至于里面非常多东西都掌握的不是非常 ...

  8. Gym - 100637A Nano alarm-clocks 模拟

    题意:有n个时钟,只能顺时针拨,问使所有时间相同的最小代价是多少 思路:将时间排序,枚举拨动到每一个点的时间就好了,容易证明最终时间一定是其中之一 #include <iostream> ...

  9. 机器学习(三) Jupyter Notebook, numpy和matplotlib的详细使用 (上)

    工欲善其事,必先利其器.在本章,我们将学习和机器学习相关的基础工具的使用:Jupyter Notebook, numpy和matplotlib.大多数教程在讲解机器学习的时候,大量使用这些工具,却不对 ...

  10. [Chromium文档转载,第004章]Mojo Synchronous Calls

    For Developers‎ > ‎Design Documents‎ > ‎Mojo‎ > ‎ Synchronous Calls Think carefully before ...