转载请注明出处: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. JAVA 不同类载入器命名空间的理解

                曾经一直有这样一个疑惑: 都说在JAVA中,由不同类载入器载入的类在虚拟机中位于不同的命名空间下,不同命名空间下的类相互不可见. 这让我产生了一个迷惑:假设有一个类A使用了ja ...

  2. django 笔记3

    FBV function base view url.py index -> 函数名 view.py def 函数(requset): ... CBV class base view /inde ...

  3. Oracle 审计初步使用

    新增一个表空间用于存储审计日志 SQL> CREATE tablespace audit_data datafile '/data/oradata/orcl/audit01.dbf' SIZE ...

  4. GPU流水线

    起点: 是一个三维模型,由顶点(vertices)构成.顶点列表中的每个顶点是三维坐标系中的坐标,并带有颜色信息.顶点列表(point list)即是流水线的输入数据. 顶点处理: 定点通过三角化(t ...

  5. 如何批量ping地址查看网络是否畅通

    测试环境搬迁后,需要批量去ping所有机器的IP,看网络是否畅通 测试思路: [weblogic@pays03pre_BankVerify luyantest]$ ping -c 1 172.29.1 ...

  6. NOIP 模拟赛

    NOIP 模拟赛 思路:求 n , m 的 gcd,然后用 n , m 分别除以 gcd:若 n 或 m 为偶数,则输出 1/2. 特别的,当 n = m = 1 时,应输出 1/1 #include ...

  7. 【Henu ACM Round#18 D】Looksery Party

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 假设现在每个人收到的信息条数存在cnt里面 那个人猜的条数为target 则如果cnt[i]==target[i] 则我们就让第i个 ...

  8. [Python] Create Unique Unordered Collections in Python with Set

    A set is an unordered collection with no duplicate items in Python. In this lesson, you will learn h ...

  9. [Python] Understand Mutable vs. Immutable objects in Python

    In this lesson, you will learn what mutable and immutable objects are, and the difference between th ...

  10. DB2物化视图(Materialized Query Tables, MQT)

    DB2的物化视图MQT是基于查询结果定义的一个表,MQT中包括的数据来自MQT定义所基于的一个或多个表, 使用MQT能够显著提高查询的操作性能. 数据库的视图和MQT都是基于一个查询来定义的.每当视图 ...