mqtt服务线程资源泄露问题分析

1. 背景

我们的mqtt服务线上一实例出现OOM,通过日志发现,OOM具体原因是因为没有足够空间创建新线程。

image.png

通过监控发现,该实例线程数一直缓慢增长,并没有回收。

image.png

2. 分析线程文件

jstack命令生成线程dump文件,通过分析,发现MQTT客户端创建了大量线程,并且没有释放。

image.png

3. 源码分析

服务使用的mqtt客户端如下

<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>1.2.1</version>
</dependency>

使用方式如下:


image.png

主要问题出在对mqtt client连接处理的代码上。原有代码的连接过程大致如下:
新建一个MqttClient对象 --> 设置callback监听断连、收到消息和发送消息成功的回调逻辑 --> 调用connect()方法连接emqx broker --> 订阅topic。
在收到断连的回调消息后,会发起重连操作,把上述流程重走一遍

image.png

排查线上日志发现有不少断连,


image.png

问题在于每一次重连后,老的MqttClient对象没有close()掉。

一个client又会引用着4种线程,
1、ConnectBG:负责连接操作的
2、CommsReceiver:用于消息接收
3、CommsSender:用于消息发送
4、CommsCallback:执行回调通知

image.png

因此随着重连次数增加, 线程数也缓慢叠加。

4. 解决方案

断连后,旧的Mqttclient调用close()方法,关闭资源

5. 效果

发生重连前:


image.png

借用tcpkill,模拟关闭tcp连接。


image.png

日志显示已经发生了重连


image.png

重连前后的MQTT线程,旧的线程已经成功回收。


image.png

发布后线上环境的效果


image.png

参考:
Linux 使用tcpkill杀掉tcp连接

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容