Netty fix epoll bug

JDK NIOepoll bug,会导致Selector空轮询,最终导致CPU 100%

Bug出现的原因

Selector的轮询结果一直为空,没有新消息处理,则发生空轮询,CPU使用率100%(在selector中,即使是select轮询事件为0的话,照样不断的从select本应该阻塞状态下wake up出来)

Netty的解决方案

  • Selectorselect操作周期进行统计,每完成一次空的select操作进行一次计数
  • 若在某个周期内连续发生N次空轮询,则触发了epoll死循环bug。
  • 重建Selector,将出现bug的Selector上的channel重新注册到新的Selector上,并将原来的Selector关闭,使用新的Selector进行替换。

JDK源码分析:

JDK NIO执行代码如下:

执行selector.select()方法返回keys是0,所以本应该对key值进行遍历的事件处理根本没有执行,又回到最上面的while(true)循环,循环往复,不断的轮询,直到系统出现100%的CPU情况,最终导致程序崩溃。

Netty源码分析

具体位置在实现类NioEventLoop中:

netty会在每次进行 selector.select(timeoutMillis) 之前记录一下开始时间currentTimeNanos,在select之后记录一下结束时间,判断select操作是否至少持续了timeoutMillis时间;selectCnt记录空轮询次数

重建selector

当发生epoll bug,则创建一个新的Selector,将出现bug的Selector上的channel重新注册到新的Selector上,关闭bug的Selector,使用新的Selector进行替换 :

Netty的解决策略:

  • 根据该bug的特征,首先侦测该bug是否发生
  • 将问题Selector上注册的Channel转移到新建的Selector
  • 老的问题Selector关闭,使用新建的Selector替换

参考

NIO的epoll空轮询bug

Netty源码分析 解决NIO的epoll死循环bug

热评文章