背景:使用thrif(版本0.9.3)对外提供服务,每隔一段时间thrif服务就挂掉。
问题定位过程:
1、查看日志,发现存在java.lang.OutOfMemoryError: Direct buffer memory异常,因为thrif用到nio,发现启动服务没有配置直接内存,想当然认为是直接内存过小,于是在jvm启动参数加大了直接内存的最大值(-XX:MaxDirectMemorySize),后续观察。过了一段时间,问题还是复现了。
2、再查日志还是报直接内存溢出,然后再仔细查看日志,发现直接内存溢出时,thrif尝试去解析一个(1个G多)字节数组,为什么会有这么大的对象,thrif都是用定义好的可序列话的对象,后发现向thrif监听的端口发送http请求(直接在浏览器地址栏输入http://ip:port/),就会复现解析大的字节数组,原来thrif用的是可序列话定义好的对象,而发送http请求的话,thrif无法解析http报文,解析出错造成直接内存区生成一个很大的字节数组,造成直接内存溢出。
解决:
1、直接修改thrift源码,设置单个请求报文最大值(修改AbstractNonblockingServer类的MAX_READ_BUFFER_BYTES属性,这个属性是long类型的最大值,相当于1045576TB,这等于没有限制),根据自己的业务场景来修改最大值。
2、也可以升级thrif的版本,高版本已解决这个问题(例:0.12.0 )。
验证:
再次向thrif服务发送http请求,该异常会被程序catch掉,提示
ERROR:Read a frame size of 1295726556, which is bigger than the maximum allowable buffer size for ALL connections.。
不会耗尽直接内存而造成内存溢出了。