两个相同的client_id,先后请求订阅emqx,会反复报错142原因码(会话接管)

环境信息

  • EMQX 版本:4.4.4
  • 操作系统及版本:centos7
  • 其他

问题描述

两个相同的client_id,先后请求订阅emqx,会反复报错142原因码(会话接管),并且从控制台可以看出,反复收到持久会话中的消息,请问是什么原因?

配置文件及日志

你的客户端应该会在连接断开后自动重连吧?所以现在就陷入了反复互踢的情况。

重复收到持久回话中的消息是因为连接断开前 QoS 1 报文的流程尚未完成,所以客户端重连后 EMQX 会将该消息再次下发给客户端。


这是我刚刚抓包的情况,为什么会互踢呢?感觉不合理,而且在互踢的过程中,会反复pub并sub很久之前的最近一条pub消息

互踢的逻辑就是:

  1. 客户端 B 上线,把客户端 A 挤掉
  2. 客户端 A 断线重连,上线后把客户端 B 挤掉
  3. 客户端 B 断线重连…
    然后反复如此

如果收到的是很久之前的消息,你看下是不是一个保留消息?

如何避免这种互踢现象?我看一直在互踢,而且反复的新建连接,很耗服务器资源呢

确实是一个保留消息 :joy:

我把broker重启了。还是依旧不断的互踢,我的broker是haproxy+单节点伪分布式集群哈,这种互踢怎么避免呢?疯狂再给haproxy发请求,顶不住了。。。

首先业务上要避免多个客户端使用相同的 Client ID,如果不行的话可以先给客户端加一个最大重连限制。

当前的临时手段你可以手动封禁一下其中一个客户端的 IP 地址,禁止它再次连接,具体可以看下这部分的 API 文档:

那能不能client_id不传呢?很少有见过broker要客户端指定client_id的,连接不应该通过socket通信去绑定唯一连接吗?

也可以的,不过需要使用 MQTT 5.0 协议版本。你可以看下这篇文章:MQTT 5.0 连接属性 | EMQ

是的,我验证过是可以不传,但如果传的话,为了避免互踢,给客户端最大重连限制和客户端IP 地址黑名单,好像都不是合适的方法呢


线上业务使用时,也只能通过客户端处理,比如 Client ID 自动加入时间戳这种方式?

这样也可以的

所以最好就是直接避免出现这种使用相同 ClientID 的情况。

可是万一有人故意攻击咋办呢?故意用相同的client_id导致会话互踢,但又不想用白名单机制去临时解决

可以配合认证、TLS 等手段来保证安全性。