Java IO:SocketChannel和Selector在ZooKeeper中应用
转载请注明出处: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中应用的更多相关文章
- hbase异常:java.io.IOException: Unable to determine ZooKeeper ensemble
项目中用到hbase,有时候可能会报一些异常,比如java.io.IOException: Unable to determine ZooKeeper ensemble 等等,当出现这个问题时,根据个 ...
- Java IO:如何得到Jar包中内嵌Jar包的时间戳
ClassLoader bladeClassLoader = BladeCLI.class.getClassLoader(); URL url = bladeClassLoader.getResour ...
- Java IO流及应用(一)
IO流 IO流概述及FileWriter类的使用 FileReader类使用 缓冲流介绍和使用 IO流相关案例 NO.one IO流概述及FileWriter类使用 1.1 IO流概述及分类 IO流用 ...
- 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 ...
- JDK1.8 java.io.Serializable接口详解
java.io.Serializable接口是一个标志性接口,在接口内部没有定义任何属性与方法.只是用于标识此接口的实现类可以被序列化与反序列化.但是它的奥秘并非像它表现的这样简单.现在从以下几个问题 ...
- java IO流 (一) File类的使用
1.File类的理解* 1. File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)* 2. File类声明在java.io包下* 3. File类中涉及到关于文件或文件目录的创建.删除.重 ...
- 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?
原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...
- HBase中此类异常解决记录org.apache.hadoop.ipc.RemoteException(java.io.IOException):
ERROR: Can't get master address from ZooKeeper; znode data == null 一定注意这只是问题的第一层表象,真的问题是: File /hb ...
- zookeeper报错: org.I0Itec.zkclient.exception.ZkMarshallingError: java.io.EOFException
zookeeper报错: org.I0Itec.zkclient.exception.ZkMarshallingError: java.io.EOFException 主要因为是没有序列化. 可以使用 ...
随机推荐
- 使用GitHub+Hexo建立个人网站,并绑定自己的域名(Ubuntu环境下)
参考链接: youngzn.github.io hexo官网 博客:从jekyll到hexo hexo建站小结 全过程 简洁过程 使用GitHub+Hexo建立个人网站,并绑 ...
- 【SRM 717 div2 A】 NiceTable
Problem Statement You are given a vector t that describes a rectangular table of zeroes and ones. Ea ...
- quick 3.3载入Spine问题
近期项目要升级到Quick 3.3, 而且使用了Spine作为动画编辑器, 在此把升级过程中.有关quick 3.3 载入Spine遇到的坑在此记录一下. 1.Spine版本号问题 首先Quick 3 ...
- HTML5学习笔记简明版(11):新增的API
HTMLDocument上的扩展 HTML5在DOM Level 2 HTML上扩展了一些HTMLDocument的接口.这些接口在全部实现了Document接口的元素对象上进行了实现. HTML5在 ...
- Programming Languages - Coursera 整理
找到并学习这门课的原因: 想要学习 functional programming Week1 Introduction and Course-Wide Information week1 很轻松, 主 ...
- 111.final与override
#include <iostream> using namespace std; class myclass { public: //后面加一个final,则禁止虚函数被子类重写 //fi ...
- Ubuntu18.04上使用LLDB调试Chromium Android C++代码。
###动机###Chromium Android源代码庞大且复杂.在调试器LLDB下能帮助我们更好的理解代码流程.介绍使用LLDB调试器调试android上chromium的C++代码. [1] 编译 ...
- 昼猫笔记 从此告别复杂代码--JavaScript
昼猫笔记--给你带来不一样的笔记 不止是笔记 更多的是思考 大家好,我是一只来自喵星的前端初学者,由于我们喵星人科技较为落后,昼猫从今天开始带着使命来到地球学习前端知识. 从今天开始,猫猫我就从Jav ...
- python数据处理技巧二
python数据处理技巧二(掌控时间) 首先简单说下关于时间的介绍其中重点是时间戳的处理,时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00 ...
- iterator的使用和封个问题
这篇文章的内容还是不错的: http://www.cnblogs.com/zhuyf87/archive/2012/12/08/2808290.html for (vector<int>: ...