把NIO事件转换成对channel unsafe的调用或NioTask的调用
processSelectedKeys()方法是处理NIO事件的入口:
private void processSelectedKeys() {
if (selectedKeys != null) {
processSelectedKeysOptimized();
} else {
processSelectedKeysPlain(selector.selectedKeys());
}
}
这个方法会调用processSelectedKeysOptimized或processSelectedKeysPlain开真正的NIO事件处理,这个两个方法的功能大致一样,不同的是前者是后者的优化版,优化点就在于它每次不用调用selector#selectedKeys()就能得到触发事件的SelectionKey。在processSelectedKeysOptimized中是通过遍历selectedKeys得到SelectionKey:
for (int i = 0; i < selectedKeys.size; ++i) {
final SelectionKey k = selectedKeys.keys[i];
selectedKeys.keys[i] = null;
final Object a = k.attachment();
if (a instanceof AbstractNioChannel) {
processSelectedKey(k, (AbstractNioChannel) a);
} else {
@SuppressWarnings("unchecked")
NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
processSelectedKey(k, task);
}
}
标红的代码就是processSelectedKeysOptimized和processSelectedKeysPlain的不同之处。
processSelectedKey(SelectionKey k, AbstractNioChannel ch) 方法会把NIO转换成Channel Unsafe方法的调用,转换规则如下:
NIO事件
Channel Unsafe方法
异常
close
SelectionKey.OP_CONNECT
finishConnect
SelectionKey.OP_WRITE
forceFlush
SelectionKey.OP_READ, SelectionKey.OP_ACCEPT
read
processSelectedKey(SelectionKey k, NioTask<SelectableChannel> task) 方法会把NIO事件转成对NioTask的方法调用:
NIO事件
Channel Unsafe方法
所有正常的NIO事件
channelReady
异常
channelUnregistered
控制线程执行I/O操作和排队任务的用时比例
在run方法中,通过ioRatio属性值来控制事件NIO和executor任务的时间比例。可以调用setIoRatio(int ioRatio)方法设置ioRatio的值,它的取值范围是[0, 100], 当它的值是100时:
try {
processSelectedKeys();
} finally {
runAllTasks();
}
此时会先处理完所有的NIO事件再执行所有的executor任务,等于完全没有用时控制。当它的值是[0, 100)时:
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
final long ioTime = System.nanoTime() - ioStartTime;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
此时会以处理NIO事件的时间为基准计算执行exeuctor任务的期望时间,之所以叫期望时间,原因是runAllTasks并不能有效地控制自己的执行时间,它每执行64个任务才会检查一次用时,如果这64个任务中有一个任务的执行时间过大,runAllTasks执行时间就会远大于期望时间。只有所有的executor任务执行时间足够短,runAllTasks才能较精确地控制自己的执行时间。为了能让这个时间控制机制有效地发挥作用,提交给NioEventLoop的任务应该是一些简单的任务,任务中尤其不能有导致线程阻塞的操作。
处理epoll selector cpu 100%的bug
在select方法中,如果调用selector.select(timeoutMillis)的调用次数大于SELECTOR_AUTO_REBUILD_THRESHOLD(它的值必须>0, 才有效),可以认为selector出现异常,此时会调用rebuildSelector方法重新创建selector。
SELECTOR_AUTO_REBUILD_THRESHOLD的值由-Dio.netty.selectorAutoRebuildThreshold决定,如果没有设置这个属性,SELECTOR_AUTO_REBUILD_THRESHOLD的默认值是512, 如这个值<0, SELECTOR_AUTO_REBUILD_THRESHOLD被设置成0。因此如果要SELECTOR_AUTO_REBUILD_THRESHOLD生效-Dio.netty.selectorAutoRebuildThreshold值必须>2或不设置这个属性。
正常情况下,在一次select调用中selector.select(timeoutMillis)被调用的次数不会大于2次,一次是正常的由于NIO事件或超时导致,另一次是在run方中的selector.wakeup()导致。如果selector.select(timeoutMillis)调用次数大于2,很有可能触发了JDK epoll selector cpu 100%的bug, NioEventLoop解决这个问题的办法是重新创建selector。
rebuildSelector方法是重新创建selector的入口,它调用rebuildSelector0方法执行真正的重建selector的操作,重建步骤如下:
1. 保存旧的selector
final Selector oldSelector = selector;
2. 调用openSelector方法创建新的selector
newSelectorTuple = openSelector();
3. 把旧selector上注册的Channel转移到新的selector上
for (SelectionKey key: oldSelector.keys()) {
Object a = key.attachment();
int interestOps = key.interestOps();
key.cancel();
SelectionKey newKey = key.channel().register(newSelectorTuple.unwrappedSelector, interestOps, a);
}
4. 关闭旧的selector
oldSelector.close();

netty源码解解析(4.0)-7 线程模型-IO线程EventLoopGroup和NIO实现(二)的更多相关文章

  1. netty源码解解析(4.0)-11 Channel NIO实现-概览

      结构设计 Channel的NIO实现位于io.netty.channel.nio包和io.netty.channel.socket.nio包中,其中io.netty.channel.nio是抽象实 ...

  2. netty源码解解析(4.0)-10 ChannelPipleline的默认实现--事件传递及处理

    事件触发.传递.处理是DefaultChannelPipleline实现的另一个核心能力.在前面在章节中粗略地讲过了事件的处理流程,本章将会详细地分析其中的所有关键细节.这些关键点包括: 事件触发接口 ...

  3. netty源码解解析(4.0)-17 ChannelHandler: IdleStateHandler实现

    io.netty.handler.timeout.IdleStateHandler功能是监测Channel上read, write或者这两者的空闲状态.当Channel超过了指定的空闲时间时,这个Ha ...

  4. netty源码解解析(4.0)-18 ChannelHandler: codec--编解码框架

    编解码框架和一些常用的实现位于io.netty.handler.codec包中. 编解码框架包含两部分:Byte流和特定类型数据之间的编解码,也叫序列化和反序列化.不类型数据之间的转换. 下图是编解码 ...

  5. netty源码解解析(4.0)-20 ChannelHandler: 自己实现一个自定义协议的服务器和客户端

    本章不会直接分析Netty源码,而是通过使用Netty的能力实现一个自定义协议的服务器和客户端.通过这样的实践,可以更深刻地理解Netty的相关代码,同时可以了解,在设计实现自定义协议的过程中需要解决 ...

  6. netty源码解解析(4.0)-4 线程模型-概览

    netty线程体系概览 netty的高并发能力很大程度上由它的线程模型决定的,netty定义了两种类型的线程: I/O线程: EventLoop, EventLoopGroup.一个EventLoop ...

  7. netty源码解解析(4.0)-15 Channel NIO实现:写数据

    写数据是NIO Channel实现的另一个比较复杂的功能.每一个channel都有一个outboundBuffer,这是一个输出缓冲区.当调用channel的write方法写数据时,这个数据被一系列C ...

  8. netty源码解解析(4.0)-12 Channel NIO实现:channel初始化

    创建一个channel实例,并把它register到eventLoopGroup中之后,这个channel然后处于inactive状态,仍然是不可用的.只有在bind或connect方法调用成功之后才 ...

  9. netty源码解解析(4.0)-5 线程模型-EventExecutorGroup框架

    上一章讲了EventExecutorGroup的整体结构和原理,这一章我们来探究一下它的具体实现. EventExecutorGroup和EventExecutor接口 io.netty.util.c ...

  10. netty源码解解析(4.0)-1 核心架构

    netty是java开源社区的一个优秀的网络框架.使用netty,我们可以迅速地开发出稳定,高性能,安全的,扩展性良好的服务器应用程序.netty封装简化了在服务器开发领域的一些有挑战性的问题:jdk ...

随机推荐

  1. Apache Beam编程指南

    术语 Apache Beam:谷歌开源的统一批处理和流处理的编程模型和SDK. Beam: Apache Beam开源工程的简写 Beam SDK: Beam开发工具包 **Beam Java SDK ...

  2. boost asio 学习(八) 网络基础 二进制写发送和接收

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=9 8. Net ...

  3. leveldb 学习记录(六)SSTable:Block操作

    block结构示意图 sstable中Block 头文件如下: class Block { public: // Initialize the block with the specified con ...

  4. trinitycore 魔兽服务器源码分析(一) 网络

    trinitycore是游戏服务器的开源代码 许多玩家使用魔兽的数据来进行测试 ,使用它来假设魔兽私服. 官方网址  https://www.trinitycore.org/ 类似的还有mangos ...

  5. 分布式协议学习笔记(一) Raft 选举

    Raft官网 官方可视化动画1 官方可视化动画2 论文中文翻译 论文英文地址 感觉作为paxos的升级精简版 Raft在设计之初就以容易理解为目标 看完资料 脑海里都有了大概的轮廓. 有了这些详细的资 ...

  6. error while loading shared libraries的解決方法

    我是在启动nginx的时候报这个错误,搜索这个错误时发现这篇文章,非本人(小渡博客)原创. 原文地址:http://blog.csdn.net/dumeifang/article/details/29 ...

  7. Unity3D连接本地或局域网MySQL数据库

    准备工作: 1.打开 Unity3D 安装目录,到这个路径下 Editor > Data > Mono > lib > mono > 2.0 拷贝出下图的五个动态链接库, ...

  8. tab下图片要求

    下面是每个tab的属性: 属性 类型 必填 说明 pagePath String 是 页面路径,必须在pages中先定义 text String 是 tab上按钮文字 iconPath String ...

  9. jenkins+donet core持续集成环境搭建

    一.Jenins+GitHub 参考 另外需要配置Global Tool Configuration 如果没有安装git,需下载安装,下载地址 二.jenkins发布donet core应用 1.配置 ...

  10. Git入门基础详情教程

    前言 写了一篇文章<一篇文章了解Github和Git教程>还觉得不错,继续写了<为了Github默默付出,我想了解你>,那么继续写Git 基础知识. Git 官网:https: ...