使用阿里云aliyun-oss-java-sdk的 getObject方法返回的输入流未主动释放 导致http连接泄漏的线上问题排查

项目功能:基于netty的数据传输服务,接收客户端数据,存在本地磁盘;定时任务,定时处理本地的文件,并上传到阿里云OSS
线上问题:运维监控发现过去半个小时都没有记录写入到DB(因为我们每上传到OSS一次会DB记一条记录)
问题排查过程

1、运维将实时的进程的dump文件拷贝出来

2、使用mat工具分析dump文件(mat介绍:https://www.cnblogs.com/trust-freedom/p/6744948.html)

dump文件分析:

使用阿里云aliyun-oss-java-sdk的 getObject方法返回的输入流未主动释放 导致http连接泄漏的线上问题排查_第1张图片

3、分析占用内存最多、创建对象最多的对象.........分析了半天,并没有定位问题,病急乱投医:因为我们默认怀疑是项目性能有问题,就从gc、cpu等去排查,其实根据dump文件的大小才1.5G,而线上的配置是4G,说明并不是项目性能有问题,由于经验不足,希望能有实时线程的堆栈信息,但项目已经被运维重启,无法获取到线程的堆栈信息,问题排查陷入困境。后来怀疑是否是堆外内存有问题,因为我们的开启了DisableExplictGC这个参数,这个参数是禁用显示调用System.gc()的,因为堆外对象只能通过System.gc回收,禁用的话可能会导致堆外对象无法回收了,最终发现和这个没有太大关系,因为监控没有发现堆外内存使用过度,日志也没有OOM的异常

使用阿里云aliyun-oss-java-sdk的 getObject方法返回的输入流未主动释放 导致http连接泄漏的线上问题排查_第2张图片

4、后来有同事说,dump的文件里,现在默认都会把线程的堆栈信息打印出来,用Mat工具可以直接看,汗颜啊,经验不足,工具也不会用,如下的按钮即可点出来了:

5、分析处理操作OSS相关的线程,发现8个线程都part了,问题原因找到,那么为什么会part了

6、找到问题,就好解决了,有大神已经遇到过这个问题:https://github.com/aliyun/aliyun-oss-java-sdk/issues/10

从堆栈上是httpclient从连接池中获取连接卡住:
可能有以下原因:

1. 连接泄漏,使用了getObject返回的输入流,使用后一定要close;
2. 使用了getSimplifiedObjectMeta,2.2.3版本前有bug,没有关闭连接;
3. 使用了2.1.2前的sdk版本, 2.1.2前的sdk使用http client 4.4,http client 4.4有bug,请升级sdk到2.1.2以上。
如果还没有解决,请旺旺联系oss_support。

正好我们触发了第一条:“使用了getObject返回的输入流,使用后一定要close”,我们未关闭,导致http连接一直没有释放,前前后后排查问题耗时良久,主要还是经验不足,本次记录作为一次积累吧。

你可能感兴趣的:(性能问题分析及解决,性能优化,Java并发)