系统主题询问

环境信息

  • EMQX 版本:4.4.1
  • 操作系统及版本:window10

问题描述

请问$SYS/brokers/emqx@127.0.0.1/clients/{clientid}/connected和$SYS/brokers/emqx@127.0.0.1/clients/{clientid}/disconnected这2个可以设置为retain为true的消息吗?

配置文件及日志

无特别配置

系统消息是不能设置的,retain是由客户端发布消息时设置的

建议可以加个$SYS/brokers/emqx@127.0.0.1/clients/{clientid}/online的系统主题,并且内部发送时是retain为true的或者说内部是有保留的,类似retain的,那用来做上下线感觉很不错

主要是订阅$SYS/brokers/emqx@127.0.0.1/clients/{clientid}/online主题,不管是哪个处理端什么时候要处理消息,那么当它订阅后,最新的客户端状态会发给它,这样实时性感觉会比较好,不然短暂切换服务,还要用http请求当前设备,在订阅connect和disconnect信息等,不太好同步起来

我们的设计是系统消息,包括事件消息,并不真正的一条MQTT的消息,因为它不是客户端业务,我们认为它是一种系统通知,仅仅是走了MQTT的方式流转出来,但系统通知是不能有太多属性的,会产生各种影响,你可以把MQTT订阅系统消息当作接受系统消息的一种方式,还有别的方式,比如webhook等。
举个例子:
系统通知,如果MQTT消息设置成了保留消息,那么 webhook 走的是http方式并没有相关的规定,该怎么处理历史消息呢?

webhook方式并不是很好用来做上下线,并且没启用webhook的接收服务器或服务异常,设备客户端都连不上EMQ,不是很灵活。还是订阅消息来处理相对灵活,谁想用谁订阅。我听前面也大概知道系统消息不是一条真正的MQTT消息,只是建议可以多一个内部类似retain的机制(内部保存),可以设置。当然这个只是建议下,有些内部的设计我不了解。

感谢你的建议,现在的业务行为已经是我们权衡之后的结果了,作为保留消息的意义不大,还会涉及到高并发的问题。比如大量的设备上下线行为,这时候保留消息里存储的设备信息就是大量刷新的,并且还要保证集群一致性,比较复杂

再举个例子,设备A离线,触发系统消息设备离线,然后设备A再次上线,如果系统消息设置为保留消息,这时系统消息创建了一个订阅,收到保留消息,消息称设备A离线了,但实际上此时设备A是在线的

感谢官方的详细解答。上面说的大量刷新和一致性等有道理,不过后面在线离线状态会错误说的好像不太对。既然原来设备上下线都会发布消息到一个系统主题(类似但不是真的MQTT消息),一个是到connected,一个是到disconnected,那么我的意思是整合到一个主题$SYS/brokers/emqx@127.0.0.1/clients/{clientid}/online,带retain性质,只会存在ram里,速度应该有保障,启动时是空的,有设备连接才有创建对应的(类似于java里的 ConcurrenHashMap创建新的键值),原来触发connected的现在为online发布一条payload含connected的信息。当此客户端断开,那么原来触发disconnected的现在为online发布一条payload含disconnected的信息。并且online主题是带retain性质的,那么我随便的判断在线的处理端连接emq,订阅connected,都会马上收到数据,迅速知道当前设备在线状态,并且是最新的,实时性好的,这个EMQ给我的反馈是自开机以来连接过的设备在当前的状态。原来我可能要先用http api请求所有在线设备一次或多次,在结合数据库,在结合订阅上下线,实时性有问题,同步性有问题,我可能要定时请求一次所有的设备状态才敢保证状态,如果设备还频繁上下线,那更不敢保证了,处理起来很麻烦。还有就是既然规则引擎可以写到数据库,按理来说更新ram上的值比更新数据库的开销小,所以我认为性能之说虽然对,但不够准确。受限于自身知识,言之有误的地方请谅解。

把设备上下线消息整合到一个主题中,是可以解决实时性问题,但需要用空间来换,也就是要保存大量的设备主题消息。
离线消息保留到数据库其实是把占用的空间转移到了数据库里(企业版功能),我们推荐的做法是,管理设备状态使用Redis之类的高性能库,EMQX 仅作为一个 broker。
你提到的主题$SYS/brokers/emqx@127.0.0.1/clients/{clientid}/online 现在已经改不动了,因为有大量的客户在使用 conn & disconn ,目前不好动他,要照顾老用户使用。
PS:如果你真的需要细致的设备信息管理,最好还是能从EMQX内部入手,欢迎给我们提交PR ,GitHub地址,代码上有任何问题,都可以在issue里提出,会有很多大牛提供帮助。也可以在此社区里提问,获取中文帮助

感谢,明白了

空间换取时间不是一个很好的方案,retain 可以持久到磁盘,但是也有不小的开销;同时,这个功能不具备普遍性所以不会纳入需求。

但按照你的思路还有一个使用方法:

规则引擎配置 SQL 处理上下线事件

SELECT 
 * 
FROM 
 "$events/client_connected", "$events/client_disconnect"


配置 消息重新发布 的 Action,将消息转发到自己想要的主题,同时设置 retain: true:

注意:当前版本 republish 暂时无法支持设置 retain 标志,我们会在后续 4.x 版本加上。

:+1: :+1:好办法,希望尽快加上,感谢