环境:我的EMQX使用的是官方最新版本,部署环境是CentOS7。客户端是用的paho.mqtt.c编写的。
对于ClientID的处理,我之前按照自己的理解是这么做的:我把ClientID固定不变,用来确保客户端断链重连之后,也能收到断线期间,其它客户端发布的消息。
但是这样带来一个故障。
故障描述:断开MQTT客户端和EMQX的链接,MQTT发布了10几条消息(由于我在客户端中设置了持久性,因此发布的消息保存在了本地)之后,重新建链,建链之后,客户端会把缓存的消息都发出去,也会发出PINGREQ(我设置的心跳是15秒,但是实际发送时间为30秒左右),但是服务端只回复了一条消息的响应之后,就不回复了,而是陷入一个断开–>重连–>断开–>重连的死循环。
补充说明:
- 我的客户端代码中设置了重连,每次链接失败,都会进行重连。一直到连上为止。
- 如果本地缓存的消息只有几条的话,又不会出现这种失败场景,客户端会把缓存的消息全部发送出去,并且服务器也能收到,然后也会把收到的消息发送给订阅的主题。
- 我在建立链接的时候,cleanstart设置为0,sessionexpiry为两个月。
- 【重要】发现一个重要现象,当我断开的时间比较短,本地缓存的消息较少(只有几条)的时候,重连之后,所有消息都能成功发送出去,但是,如果断开时间长,本地缓存的消息较多(20多条)时,重连之后,就只能成功发布几条缓存的消息,然后一直不停地重传,最终导致死循环。我也尝试修改了max_mqueue_len和max_packet_size,但是并没有起作用。
观察EMQX日志发现,主要有两种断开原因:
- reason: keepalive_timeout
- reason: {shutdown,takenover}
综合分析来看,应该是由于我采用了相同的ClientID登录的原因,但是我的疑问是:
如果让ClientID变化(比如加上时间戳),那么,在客户端重连之后,还能收到断链期间,其它客户端发送的消息吗?另外,原来的客户端缓存的消息,还能发送出去吗?