当 Thrift 遇到 JDK Epoll Bug
博客专区 > 輕風 的博客 > 博客详情
当 Thrift 遇到 JDK Epoll Bug
輕風 发表于4个月前
当 Thrift 遇到 JDK Epoll Bug
  • 发表于 4个月前
  • 阅读 1873
  • 收藏 110
  • 点赞 6
  • 评论 24

腾讯云 技术升级10大核心产品年终让利>>>   

摘要: 将会擦出怎样的火花呢?

##前言 相信不少 Java server 端程序深受臭名昭著的 JDK Epoll Bug 其害。一旦触发所有 Selector 线程处于空转状态不能自拔,直至 cpu 跑满,不再处理外来连接。对于外部调用者来说这意味着服务不可用,这真是一场灾难。

笔者不才,前段时间在使用 Thrift 作为 server 端 rpc 框架对外提供服务时刚好触发了此 bug ,在此记录定位问题的过程和解决办法,供各位参考,望再有后来人碰到此问题不在受此困扰。话不多说,先来复盘。

问题定位

话说服务端程序都已开心码完,在做最后的压测时,突然发现压测程序请求不到服务直至访问超时。赶紧到所在服务器查看服务状况,结果发现多个 cpu 跑满了,如下图:

cpu run full

于是赶紧用 top -Hp $PID 查看下所在进程的线程情况,结果如下图:

thread info in progress

按 cpu 使用量排序后,发现前面几个线程 cpu 使用量接近 100% 。 Java 程序快用 jstack 查看这个线程在干嘛吧,定位到 pid=177 ( 0xb1 ) 的线程堆栈信息如下:

thread details

从堆栈信息可以看到触发点位于 Thrift 的 TThreadedSelectorServer.select() 方法中,查看源码可知其不过是调用了JDK Selector.select() 方法。(注:为描述方便笔者把实例方法调用使用类方法调用形式展示)

TThreadedSelectorServer.select()

看现象初步认为是压测时连接数过多导致 Selector 线程一直处于繁忙状态,可后来发现停掉压测 cpu 使用量还是居高不下。

笔者曾一度陷入困境,后经高人同事提点道:会不会是JDK Epoll Bug ?我一想这个 bug 官方不是修复了吗,后来查证发现:官方声称在JDK1.6版本的update18修复了该问题,然而只是降低了发生的概率而已,它并没有被根本解决。该 bug 以及相关的问题如下:

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6403933

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=2147719

笔者当时环境为:

work JRE

看来到 jdk 1.8 这个问题也没解决,为 Oracle 感到小小的尴尬啊。

解决办法

JDK 的 bug 让使用者极其的尴尬啊,因为我们又不能更改其源码。好在好的搜索引擎拉低了学习的门槛,在茫茫互联网中帮我找到了一位高人总结的解决办法,其中有详细写明触发原因及解决办法,详见:

应用服务器中对JDK的epoll空转bug的处理

笔者简述下解决办法:

  1. 确认程序触发 epoll bug :在一定时间间隔内触发了设定阈值次数的空转,则认定触发 epoll bug
  2. 修复:通过重建 Selector 方式,新 Selector 注册问题 Selector 所有事件后替换它。

定位到问题及知道解决办法后,接下来就赶紧修复它吧。

按照 Thrift 官方 Developers 贡献指南一步步来:

至此问题修复完成。感兴趣者可以关注上述 issue 来获取官方修复的最新进展。

参考博客:

应用服务器中对JDK的epoll空转bug的处理

Java NIO通信框架在电信领域的实践

转载此博客请注明来源:https://my.oschina.net/johnnyliao/blog/1507141

标签: Thrift JDK epoll
共有 人打赏支持
粉丝 5
博文 2
码字总数 1601
评论 (24)
javadeveloper
:+1:
蓝水晶飞机
已阅
andersonoy
netty解决了这个bug,解决方法就是你上面提到的一样,你可以看看netty源码,里面有详细介绍这个bug及期解决方案
andersonoy
所以很多底层通信都是用netty
輕風

引用来自“andersonoy”的评论

netty解决了这个bug,解决方法就是你上面提到的一样,你可以看看netty源码,里面有详细介绍这个bug及期解决方案
对的,就是参考netty源码,修复Thrift中未解决的epoll bug
輕風

引用来自“andersonoy”的评论

所以很多底层通信都是用netty
考虑到对外接口层的多语言支持性才选用Thrift的
鈈哓锝
好文!
强子哥哥
赞,顺便让它把0.10.0的System.out.println去掉吧
Raphael_goh
官方说这是linux2.4的bug,而且不打算合并你的pr:joy::joy::joy:
Raynor1

引用来自“Raphael_goh”的评论

官方说这是linux2.4的bug,而且不打算合并你的pr:joy::joy::joy:
我觉得楼主搞错了一个地方就是在压力大的时候。其实是可以有Cpu 100%的。。说明是处理事件呀。。而oracle 的那个bug是说。当触发了这一个事件后。他的cpu 100%怎么样都下不了的问题(无法再解放),所以造成楼主这一个问题应该是逻辑处理慢造成所并不是上面的这一个地方的处理造成的哈。
FPE
厉害了,java把epoll弄得像select一样。文章所说的“连接数过多导致 Selector 线程一直处于繁忙状态”,这绝对是select模型,一定是用select实现了一个假epoll,哈哈哈。我用epoll(c++)测试接受连接(还是用虚拟机测试),不到5秒就能接受50000个新连接。所以你是平均每秒有10000个连接请求导致一直卡顿吗?
Raynor1

引用来自“Raphael_goh”的评论

官方说这是linux2.4的bug,而且不打算合并你的pr:joy::joy::joy:
而且文章的同学也把一些理解的概念给混了 。若是处在处理的状态。应该Cpu是100而且是在100 RUNNING的状态哈。。。。。状态就是这样的哈。就主明了他的这一个线程是没有用。若出现上述的100%的情况。应该线程是一直在RUNNITNG的状态。。 block 是应该没有事件过来。。。好吧。。我是不是说得太多了。
輕風

引用来自“强子哥哥”的评论

赞,顺便让它把0.10.0的System.out.println去掉吧
可以给他们提个issue
輕風

引用来自“Raphael_goh”的评论

官方说这是linux2.4的bug,而且不打算合并你的pr:joy::joy::joy:
当时环境内核版本为 3.10.0
輕風

引用来自“Raphael_goh”的评论

官方说这是linux2.4的bug,而且不打算合并你的pr:joy::joy::joy:

引用来自“Raynor1”的评论

我觉得楼主搞错了一个地方就是在压力大的时候。其实是可以有Cpu 100%的。。说明是处理事件呀。。而oracle 的那个bug是说。当触发了这一个事件后。他的cpu 100%怎么样都下不了的问题(无法再解放),所以造成楼主这一个问题应该是逻辑处理慢造成所并不是上面的这一个地方的处理造成的哈。
可能没表诉清楚,后面说了停掉压测后无外来连接时cpu还是跑满状态的
輕風

引用来自“FPE”的评论

厉害了,java把epoll弄得像select一样。文章所说的“连接数过多导致 Selector 线程一直处于繁忙状态”,这绝对是select模型,一定是用select实现了一个假epoll,哈哈哈。我用epoll(c++)测试接受连接(还是用虚拟机测试),不到5秒就能接受50000个新连接。所以你是平均每秒有10000个连接请求导致一直卡顿吗?
java 的 Selector(选择器)有多种实现方式,实现了 poll epoll 等多种模型。无业务情况下测过qps 轻松上 10w 的,性能是没问题的,主要是触发了 jdk 的 bug 导致其处于空转状态而不能处理外来连接。
Raphael_goh

引用来自“Raphael_goh”的评论

官方说这是linux2.4的bug,而且不打算合并你的pr:joy::joy::joy:

引用来自“Raynor1”的评论

我觉得楼主搞错了一个地方就是在压力大的时候。其实是可以有Cpu 100%的。。说明是处理事件呀。。而oracle 的那个bug是说。当触发了这一个事件后。他的cpu 100%怎么样都下不了的问题(无法再解放),所以造成楼主这一个问题应该是逻辑处理慢造成所并不是上面的这一个地方的处理造成的哈。

引用来自“輕風”的评论

可能没表诉清楚,后面说了停掉压测后无外来连接时cpu还是跑满状态的
这问题我也遇到过,我们的日志库发送日志到kafka的时候参数没有调整好,压测2分钟后,tps就降到1/10甚至到0,几乎不响应请求(此时停止压测可以恢复),再持续压测几分钟后,就完全无法恢复了。调整kafka Client的buffer大小或改小kafka的timeout时间可以解决这个问题。
orpherus
去oracle报jdk bug吧
輕風

引用来自“orpherus”的评论

去oracle报jdk bug吧
准备去,然而这么多年来官方给出的办法也就是重建 Selector(JDK-6403933),所以最快的办法还是在框架中屏蔽。
orpherus

引用来自“輕風”的评论

引用来自“orpherus”的评论

去oracle报jdk bug吧
准备去,然而这么多年来官方给出的办法也就是重建 Selector(JDK-6403933),所以最快的办法还是在框架中屏蔽。

jdk团队认为只有2.4内核有这个问题,而且他们认为已经修复了,这个issue值得关注
×
輕風
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: