Java nio 空轮询bug到底是什么
编者注:Java nio 空轮询bug也就是Java nio在Linux系统下的epoll空轮询问题。
epoll机制是Linux下一种高效的IO复用方式,相较于select和poll机制来说。其高效的原因是将基于事件的fd放到内核中来完成,在内核中基于红黑树+链表数据结构来实现,链表存放有事件发生的fd集合,然后在调用epoll_wait时返回给应用程序,由应用程序来处理这些fd事件。
使用IO复用,Linux下一般默认就是epoll,Java NIO在Linux下默认也是epoll机制,但是JDK中epoll的实现却是有漏洞的,其中最有名的java nio epoll bug就是即使是关注的select轮询事件返回数量为0,NIO照样不断的从select本应该阻塞的Selector.select()/Selector.select(timeout)中wake up出来,导致CPU 100%问题。如下图所示:

那么产生这个问题的原因是什么的?其实在 https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6670302 上已经说明的很清楚了,比如下面是bug复现的一个场景:
A DESCRIPTION OF THE PROBLEM :
The NIO selector wakes up infinitely in this situation..
0. server waits for connection
1. client connects and write message
2. server accepts and register OP_READ
3. server reads message and remove OP_READ from interest op set
4. client close the connection
5. server write message (without any reading.. surely OP_READ is not set)
6. server's select wakes up infinitely with return value 0
上面的场景描述的问题就是连接出现了RST,因为poll和epoll对于突然中断的连接socket会对返回的eventSet事件集合置为POLLHUP或者POLLERR,eventSet事件集合发生了变化,这就导致Selector会被唤醒,进而导致CPU 100%问题。根本原因就是JDK没有处理好这种情况,比如SelectionKey中就没定义有异常事件的类型。
class SelectionKey {
public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;
}
既然nio epoll bug存在,那么能不能规避呢?答案是有的,比如netty就很巧妙的规避了这个问题,它的处理机制就是如果发生了这种情况,并且发生次数超过了SELECTOR_AUTO_REBUILD_THRESHOLD(默认512),则调用rebuildSelector()进行Selecttor重建,这样就不用管之前发生了异常情况的那个连接了。因为重建也是根据SelectionKey事件对应的连接来重新注册的。
该问题最早在 Java 6 发现,随后很多版本声称解决了该问题,但实际上只是降低了该 bug 的出现频率,目前从网上搜索到的资料显示,Java 8 还是存在该问题(当 Thrift 遇到 JDK Epoll Bug)。
最后一起来分析下,nio epoll bug不是linux epoll的问题,而是JDK自己实现epoll时没有考虑这种情况,或者说因为其他系统不存在这个问题,Java为了封装(比如SelectionKey 中的4个事件类型)的统一而没去处理?
这里思考下,如果想要从java nio层面上来解决这个问题,该如何做呢?
一种是nio事件类型SelectionKey新加一种"错误"类型,比如针对linux epoll中的epollhup和epollerr,如果出现这种事件,建议程序直接close socket,但这种方式相对来说对于目前的nio SelectionKey改动有点大,因为SelectionKey的定义目前是针对所有jdk平台的;还有一种是针对jdk nio 对epoll的封装中,对于epoll的epollhup和epollerr事件,epoll封装内部直接处理,比如close socket,但是这种方案也有一点尴尬的是,可能上层应用代码还保留有出现问题的socket引用,这时最好是应用程序能够感知这种情况来处理比较好。
Java nio空转问题由来已久,一般程序中是通过新建Selector的方式来屏蔽掉了JDK5/6的这个问题,因此,对于开发者来讲,还是尽量将JDK的版本更新到最新,或者使用NIO框架如Netty,Grizzly等进行研发,以免出更多的问题。
推荐阅读
- Netty 入门,这一篇文章就够了
- Netty 启动流程解析
- Netty 处理连接那些事
- Java常见几种动态代理的对比
- 程序员必看| mockito原理浅析
- Eureka 原理分析
- MQ初窥门径【面试必看的Kafka和RocketMQ存储区别】
- java lambda 深入浅出
欢迎小伙伴关注【TopCoder】阅读更多精彩好文。
Java nio 空轮询bug到底是什么的更多相关文章
- jdk1.6空轮询Bug的原因及解决方法
简述 本文主要介绍一下jdk1.6版本中的NIO Selector空轮询BUG,描述一下BUG的现象及原因,以及Netty中如何巧妙的规避了这个bug. 为什么要写这篇文章,说来惭愧,很久以前面试官问 ...
- NIO的epoll空轮询bug
JDK NIO的bug,例如epoll bug,它会导致Selector空轮询,最终导致CPU 100%. Selector BUG出现的原因 若Selector的轮询结果为空,也没有wakeup或新 ...
- DK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU 100%。
NIO的epoll空轮询bug - Lost blog - 博客园 https://www.cnblogs.com/JAYIT/p/8241634.html NIO的epoll空轮询bug JDK ...
- Java多线程:Linux多路复用,Java NIO与Netty简述
JVM的多路复用器实现原理 Linux 2.5以前:select/poll Linux 2.6以后: epoll Windows: IOCP Free BSD, OS X: kqueue 下面仅讲解L ...
- java nio 写一个完整的http服务器 支持文件上传 chunk传输 gzip 压缩 使用过程 和servlet差不多
java nio 写一个完整的http服务器 支持文件上传 chunk传输 gzip 压缩 也仿照着 netty处理了NIO的空轮询BUG 本项目并不复杂 代码不多 ...
- java nio的一个严重BUG
java nio的一个严重BUG Posted on 2009-09-28 19:27 dennis 阅读(4588) 评论(5) 编辑 收藏 所属分类: java .源码解读 这个BU ...
- Java NIO通信框架在电信领域的实践
[http://www.codeceo.com/article/java-nio-communication.html] 华为电信软件技术架构演进 Java NIO框架在技术变迁中起到的关键作用 ...
- Java NIO 入门
本文主要记录 Java 中 NIO 相关的基础知识点,以及基本的使用方式. 一.回顾传统的 I/O 刚接触 Java 中的 I/O 时,使用的传统的 BIO 的 API.由于 BIO 设计的类实在太 ...
- 源码分析netty服务器创建过程vs java nio服务器创建
1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...
随机推荐
- C# Foreach循环本质与枚举器
对于C#里面的Foreach学过 语言的人都知道怎么用,但是其原理相信很多人和我一样都没有去深究.刚回顾泛型讲到枚举器让我联想到了Foreach的实现,所以进行一番探究,有什么不对或者错误的地方大家多 ...
- Spring基础(二)
一.使用注解配置Spring 1.1步骤 --配置文件中,指明注解位置 --要用的地方打上注解 --改对象的作用范围(修改掉默认的单例,变多例) --属性的注入(两种) 使用的反射实现 set方法实现 ...
- “零基础”如何快速掌握web前端核心技术?
前端开发要学的知识内容涉及的会很宽泛,虽然说主要是HTML.CSS和JavaScript这些基础知识点,今天想强调一下,学前端开发除了要学这些基础知识外,学员还要在这之上进行延伸和深入的去学,而且互联 ...
- java高并发_博客-网址-资料 推荐
大概说一下自己作为入门学习java高并发的博客地址,很不错在自己的博客里记录一下:如果能有刷到我的博客的骚年,又刚好想了解java高并发,强烈推荐看看 地址:http://www.itsoku.com ...
- 代码审计-MetInfo CMS任意文件读取漏洞
0x01 代码分析 发现在app\system\include\module\old_thumb.class.php疑似有任意文件读取漏洞 public function doshow(){ glob ...
- DeCantor Expansion (逆康托展开)
Background\text{Background}Background The \text{The }The Listen&Say Test will be hold on May 11, ...
- python 2.x中的中文
先不管一大堆的中文显示的原理,在这里记录下正确显示中文的方式,便于以后的查阅和深入学习. 方法1 a = {} a["哈哈哈"] = "啦啦啦啦啦啦啦" s1 ...
- jmeter-中文乱码问题
1.被测系统中问乱码 解决办法:接口请求时添加编码方式UTF-8
- unittest断言
assertEquals(expected,actual,msg=msg) # 判断 expected,actual是否一致,msg类似备注,可以为空
- Mobius反演学习
这篇文章参考了许多资料和自己的理解. 先放理论基础. 最大公约数:小学学过,这里只提一些重要的公式: $·$若$a=b$,则$\gcd(a,b)=a=b$: $·$若$\gcd(a,b)=d$,则$\ ...