在 Java NIO 编程实践中,很多人都会选择 Netty 作为基础框架,而不是直接用 JDK 原生的 NIO API。
因为 JDK 原生的 NIO 框架内容过于繁杂、学习成本高、补齐可靠性的工作量和难度都很大、还有一些bug。
其中一个著名的bug就是 epoll Selector 空转问题。
相关Bug单
- 《JDK-6670302 : (se) NIO selector wakes up with 0 selected keys infinitely [lnx 2.4]》
- 《JDK-6403933 : (se) Selector doesn't block on Selector.select(timeout) (lnx)》
- 《JDK-2147719 : (se) Selector doesn't block on Selector.select(timeout) (lnx)》
问题表象
示例代码(仅做示例,未考虑异常处理):
while (true) { selector.select(); Iterator it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey) it.next(); int ops = key.interestOps(); if (0 != (ops & SelectionKey.OP_ACCEPT)) { // 处理新连接 } if (0 != (ops & SelectionKey.OP_READ)) { // 读取消息 } it.remove(); } }
在使用 JDK NIO 框架时我们通常会采用上述模式的代码来处理客户端请求。
执行 Selector.select() 方法时会一直阻塞,直到有 channel 就绪。
但是在实践中,可能:
- 没有 channel 就绪,该方法也会返回。(违反原来的阻塞行为设计)
- 因为没有 channel 就绪,所以内部的 while 循环不会执行。
- 继而不断执行外部的 while (true) 循环。
- 上述步骤不断重复就形成空转轮询,CPU占用率达到100%,无法执行其它任务,最终程序崩溃。
问题原因
在部分 Linux 内核中,在 poll 或 epoll 一个已连接的socket,且请求事件掩码为0 的情况下,如果连接被突然中断,那么 poll/epoll 会被唤醒,相应事件标识为 POLLHUP(或 POLLERR)。
继而Selector被唤醒,且 interest set 为0,没有相应的 Channel,select() 返回值也是0。
Netty 的解决方法
Netty 的解决方式是 重建一个新的 Selector,替代原来出错的 Selector。
大致方法如下:
- 在一个 select 周期中,统计 空select 操作 的次数。
- 当 空select 操作次数累计到阈值时,就认为触发了 epoll空转 bug。
- 然后重建 Selector:
新建一个 Selector;
将 原Selector 上的 Channel 注册到 新Selector;
关闭 原Selector。
上述判定阈值默认为 512。可通过JVM系统变量设置(io.netty.selectorAutoRebuildThreshold)。
可在 NioEventLoop 类中查看相关代码。
思考
可能因为此问题的根源在于底层Linux内核行为的不一致,所以Java官方一开始将其抛给了操作系统实现方,导致该bug存在了很久。也许Java官方相关决策者认为,此类bug最恰当的修复方案应该在底层操作系统,而不是由上层Java去糊一层,因为JDK有自己的设计原则,并不是无脑做得越多越好。
其实这种分层分治的思维方式是非常令人欣赏的。很多优秀产品的缔造者内心都秉持这个原则。
如,Robot Framework 的负责人 Pekka Klärck 认为 IronPython 处理全角空格的不同方式应该由 IronPython 实现者去修改,而不是让 Robot Framework 在上面糊一层:
《Support for 'IDEOGRAPHIC SPACE' (U+3000) in test data on IronPython》
反观很多产品经理,毫无原则,只会做附庸,客户说啥就是啥,领导说啥就是啥,自己也没有足够的知识和经验储备,尽出些拙劣的程序,根本不能称为产品。真的是“人人都是产品经理”。
相关推荐
视频分两部分:第一部分:深入浅出Netty源码剖析;第二部分:NIO+Netty5各种RPC架构实战演练(非加密)
【项目实战】Netty源码剖析&NIO;+Netty5各种RPC架构实战演练三部曲视频教程(未加密)
Netty NIO high performance高性能;Modbus Function sync/aync 同步/异步非阻塞;Modbus IoT Data Connector Supports工业物联网平台IoT支持。
NIO网络编程demo通过BIO,NIO,Netty三个方面写了javafx可视化聊天室,代码有注释
Java整合springboot2.3+modbusTcp协议+netty高性能物联网服务源码 1、Netty NIO high performance高性能. 2、Modbus Function sync/aync 同步/异步非阻塞。 3、Modbus IoT Data Connector Supports工业物联网平台IoT...
Java NIO,Ron Hitchens 著,中文版 裴小星 译,Pro Java 7 NIO.2,Anghel Leonard 著,pdf文字版带书签,无安全限制
可将此代码当做微服务中的一个服务,定制化自己的需求
java基于nio的通信实例,带UML结构图及server、client源码。
Java高级互联网架构师系统培训班课程Java高级互联网架构师系统培训班课程Java高级互联网架构师系统培训班课程
视频分两部分:第一部分:深入浅出Netty源码剖析;第二部分:NIO+Netty5各种RPC架构实战演练(非加密)
java NIO入门适合入门j
Java NIO学习资料+代码.zip
java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...
资源名称:Java_NIO框架Netty教程资源截图: 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。
Java NIO系列教程(一) Java NIO 概述 Java NIO系列教程(二) Channel Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道之间的数据传输 Java NIO系列教程(六)...
Java高并发编程代码(Netty NIO 实例)
netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty开发之nio netty...
基于springboot+netty实现的心跳检测源码+项目说明文档.zip (1),NioEventLoopGroup是一个处理I / O操作的多线程事件循环。 Netty为不同类型的传输提供各种EventLoopGroup实现。我们在此示例中实现了服务器端应用程序...
Netty:它使 NIO 编程更加容易,屏蔽了 Java 底层的 NIO 细节。 Protostuff:它基于 Protobuf 序列化框架,面向 POJO,无需编写 .proto 文件。 ZooKeeper:提供服务注册与发现功能,开发分布式系统的必备选择,同时...