MQTT客户端断链重连问题

环境:我的EMQX使用的是官方最新版本,部署环境是CentOS7。客户端是用的paho.mqtt.c编写的。
对于ClientID的处理,我之前按照自己的理解是这么做的:我把ClientID固定不变,用来确保客户端断链重连之后,也能收到断线期间,其它客户端发布的消息。
但是这样带来一个故障。

故障描述:断开MQTT客户端和EMQX的链接,MQTT发布了10几条消息(由于我在客户端中设置了持久性,因此发布的消息保存在了本地)之后,重新建链,建链之后,客户端会把缓存的消息都发出去,也会发出PINGREQ(我设置的心跳是15秒,但是实际发送时间为30秒左右),但是服务端只回复了一条消息的响应之后,就不回复了,而是陷入一个断开–>重连–>断开–>重连的死循环。

补充说明:

  1. 我的客户端代码中设置了重连,每次链接失败,都会进行重连。一直到连上为止。
  2. 如果本地缓存的消息只有几条的话,又不会出现这种失败场景,客户端会把缓存的消息全部发送出去,并且服务器也能收到,然后也会把收到的消息发送给订阅的主题。
  3. 我在建立链接的时候,cleanstart设置为0,sessionexpiry为两个月。
  4. 【重要】发现一个重要现象,当我断开的时间比较短,本地缓存的消息较少(只有几条)的时候,重连之后,所有消息都能成功发送出去,但是,如果断开时间长,本地缓存的消息较多(20多条)时,重连之后,就只能成功发布几条缓存的消息,然后一直不停地重传,最终导致死循环。我也尝试修改了max_mqueue_len和max_packet_size,但是并没有起作用。

观察EMQX日志发现,主要有两种断开原因:

  1. reason: keepalive_timeout
  2. reason: {shutdown,takenover}
    综合分析来看,应该是由于我采用了相同的ClientID登录的原因,但是我的疑问是:
    如果让ClientID变化(比如加上时间戳),那么,在客户端重连之后,还能收到断链期间,其它客户端发送的消息吗?另外,原来的客户端缓存的消息,还能发送出去吗?

在另一个帖子中看到 EMQ官方(t1ger)说:使用动态 Client ID 就没法使用持久会话了,这就造成一个矛盾问题:要想使用持久会话,就必须使用固定Client ID,而使用固定Client ID,又会导致断链重连的时候,频繁发生takenover,从而进入死循环。

如果同一个client id在其他设备上(或另一个客户端)已经连接,则这个设备再用同一个client id 进行连接,发生takeover 是正常的(先前连接被踢出)。如果是先前也是这个设备(同一个客户端)连接过,后来意外断网,而重新再连而出现 takeover, 则是broker端处理session state 有bug, 进入死循环就是更是bug.

是同一个客户端。

我们也出现了同一个客户端一直takeover的情况,请问有办法解决吗