一、背景
mqtt-sync-server 服务作为 mqtt 协议客户端,使用 Paho-MQTT 库连接 EMQX,上行负责订阅车端 tbox 上报的数据,下行负责下发指令至终端设备。
该服务目前线上部署了8个节点
1、10.0.0.217
2、10.0.0.230
3、10.0.0.226
4、192.168.0.209
5、192.168.0.287
6、192.168.0.232
7、192.168.0.200
8、10.0.0.220
二、问题
8个节点其中6个出现了与 emqx 频繁断连的错误。例如 10.0.0.226 自上次发布至今3个月,已发生 500 多万次重连

剩余2个节点192.168.0.209和 192.168.0.232则是正常的,没出现断连情况。
三、排查
1、日志对比
分析正常节点日志与频繁断连节点的日志



Paho-MQTT 库 Client 的线程名会带上客户端 ID

而我们服务自定义的clientId构造规则如下:

可以发现,正常节点的clientID是完整的且节点ip能正常获取。
而有问题的节点,clientID出现两种情况,
异常一:ip获取到的是127.0.0.1Linux/root/127.0.0.1
异常二:缺少ipLinux/root/
| 节点 | clientID | |
|---|---|---|
| 192.168.0.09 | Linux/root/192.168.0.209 | 正常 |
| 192.168.0.32 | Linux/root/192.168.0.232 | 正常 |
| 192.168.0.87 | Linux/root/127.0.0.1 | 异常一 |
| 192.168.0.00 | Linux/root/127.0.0.1 | 异常一 |
| 10.0.0.26 | Linux/root/ | 异常二 |
| 10.0.0.30 | Linux/root/ | 异常二 |
| 10.0.0.17 | Linux/root/ | 异常二 |
| 10.0.0.20 | Linux/root/ | 异常二 |
2、EMQ Dashboard

EMQX后台的客户端监控页面,客户端ID以Linux开头的结果只有4个,期望应该是8个才对。
另外也会发现,ID Linux/root/127.0.0.1对应的ip地址不断在 192.168.0.287、192.168.0.200之间变换。
IDLinux/root/对应的ip地址则不断在10.0.0.226、10.0.0.230、10.0.0.217、10.0.0.220中变换。
四、原因分析
1、在构造clientID过程中,节点ip地址的获取方式是InetAddress.getLocalHost().getHostAddress()
这种方式依赖本机名去获取本机ip的,并不是一种可靠的方法。
因此会导致获取不到真实ip而导致出现重复的clientID。
2、使用同一客户端 ID 建立了多个连接,会导致已连接的设备断开连接。因为MQTT 规范只允许每个客户端 ID 有一个活动连接,因此当另一个节点使用同一客户端 ID 连接时,便会先踢掉先前的连接
五、解决方案
因为我们的服务在启动都会带上host.ipaddr这个参数,因此可以改为获取该参数值来得到ip

假设获取不到ip,可以使用当前时间戳作为兜底方案。

六、效果
可以看到客户端ID数量变为8个了,证明ID值已经是唯一了。

发布后,从服务日志显示没有重连的情况发生了
