线上MQTT报错问题排查

zmisgod 发布于 2019-2-5 13:05:04 阅读 37 评论 0

线上服务器在2天前出现了大量的MQTT的报错,报错信息如下所示:

20:45:04.048 ERROR [MQTT Rec: teacherMoreClient_production] o.s.i.m.o.MqttPahoMessageHandler:211-[] > Lost connection; will attempt reconnect on next request

于是我们就开始对此问题展开了排查。

线上的服务器使用的是两台的服务器,通过一台slb进行负载均衡。两台都是java的环境。每台java启动内存为2G。

首先我们怀疑是因为请求的数量多时,开启很多线程建立mqtt连接后消耗了系统资源,导致了oom。于是我们在预发布的环境进行了模拟线上环境发送mqtt消息的测试。

ab -c100 -n10000 127.0.0.1/test

于是出现了和线上同样的报错,于是我们先搜索了下相关的mqtt的报错信息。但是没有搜索到相关的信息,但是搜索到了一个特别重要的线索:使用多个MQTT调试工具mqtt.fx连接同个服务器地址报错,只能连接一个,修改Client ID即可

于是我到我们的代码库区看是否是因为client id相同导致两个相同的client id 到了mqtt服务器,然后导致链接失败,然后出现了lost connection。我们在连接mqtt的时候,client id 是固定的,但是两台服务器在同一时间链接时可能会导致上面的问题,接连不上。

于是我们先在开发环境测试了一下,还是使用的是ab压力测试,重现了Lost connection,然后将client id前面加了一个uuid,然后再次测试,就没有这个问题了。

mqtt的官网有一句

Response
If a client with the same Client ID is already connected to the server, the "older" client must be disconnected by the server before completing the CONNECT flow of the new client.

也就是如果同一时间如果有一个相同的client id连接了mqtt server,最先的一个客户端必须断开连接,后面的客户端才能连接上。也就是导致了线上出现大量报错了Lost connection的错误。

至于oom,也就是因为我们用的java的包,这个mqtt的包默认使用10个线程池,如果同一时间超过了10个连接,则默认就可以开辟intger的最大值(也就是 2147483647)个线程。然后我们这边没有使用队列,导致有多少请求,就会新开这么多的线程进行链接mqtt server,应该是这个导致的。所以我们在后续的代码需要把这块考虑进去。

最后,祝大家新年快乐!!!