emq实现向大量指定设备推送消息(九)

前言:最近完成了一个需求,向大量的指定设备推送消息。但是,实现过程中发生一些问题,导致不得不换了一种实现方式,故记录之,以供参考。


先说明下背景:emq集群为2个节点,配置为4核16G,同时在线设备量大概在10W左右(即每个节点负载约5W)。

需求就是:需要向这其中的某3万设备推送某个消息。

解读下需求:比如我现在有设备号码是 1-100000 的这么些设备,要推送 30000-60000 的这些设备一些消息。

怎么实现呢?

目前有两种思路,且听我一一道来。

思路一:利用emq的保留消息实现。这也是我第一次想到并付诸于实践的思路。

保留消息的特点是,发布到topic的消息如果是保留消息的话,那么订阅这个topic的设备上线后将收到此消息。

那么可以这样设计:

设备端,每个设备都订阅自己独有的topic,例如用自己唯一的设备号,比如

1号设备订阅:private/1

2号设备订阅:private/2

这样在发布的时候,就可以向上面 private/30000 到 private/60000 这些topic发布保留消息,然后也只有对应订阅了这些topic的设备能收到了。

但是,嘿嘿,凡事都有但是。这种实现有两个问题:

1,鉴于保留消息的机制(一个topic只保留一条最新消息),同时只能像某个设备推送一条消息,举个例子:

在向 private/1 发了保留消息推送第一条消息【1号1号,再不上线就分手!】时,若1号设备一直不在线,而这时候你等不及又推了第二条消息【都是你的错!分手吧!】。这时如果1号设备联网上线了,就只会收到第二条消息,到最后也不知道为啥被分了手。

2,emq服务器在上述背景下,推送几千条的保留消息,就会把cpu跑满!这个问题,我反馈咨询过emq的开发人员,emq存数据是用的mnesia数据库,如果有大量保留消息的时候,每个设备上线时,都会到这个库查看是否有此设备所订阅topic匹配的路由数据。我的理解是,emq在存在大量保留消息,且上下线频繁的场景下,还做的不够好。

思路二:利用 redis+emq的上下线数据 实现。

鉴于保留消息有以上的问题,肯定行不通了,后来有想到一种思路。解决了这个问题。

设计思路:

设备端,每个设备订阅自己独有的topic,这个不变。

而发布端,不再发保留消息到emq,而是发到redis。在redis内,为每个设备维护一个待推送数据列表。利用redis的set数据结构来实现。比如:

1号设备的待推送列表为set结构的,key的结构为:retain:1

然后往这个key里面存要发布的指令,然后再利用emq的上下线消息,一上线,就去redis查 retain:1 下有没有待推送数据,有就推送,这样就实现了向独立设备推送独立消息的需求。推完之后可以删掉此消息,或者再设计一个回执反馈,待设备发回了某些特定回执之后再删也可以。并且,set结构的key能够存多条数据,只要内容不一样,所以可以解决上面保留消息第一点的问题

至于上面第二点的问题,redis数据存在内存,吞吐极大,性能没有问题。

以上,笔者用第二种方式实现了上述背景下的需求,经过长时间验证,性能和可持久性都可靠。

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
要使用 Arduino Uno 来发布消息EMQ X Broker,您需要使用 MQTT 协议。首先,您需要在 Arduino IDE 上安装 MQTT 库。然后,您可以使用以下代码将消息发布到指定的主题: ```cpp #include <WiFi.h> #include <PubSubClient.h> // Replace the following with your WiFi and MQTT details const char* ssid = "your_SSID"; const char* password = "your_PASSWORD"; const char* mqttServer = "your_MQTT_SERVER"; const int mqttPort = 1883; const char* mqttUser = "your_MQTT_USER"; const char* mqttPassword = "your_MQTT_PASSWORD"; WiFiClient espClient; PubSubClient client(espClient); void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); client.setServer(mqttServer, mqttPort); client.setCallback(callback); while (!client.connected()) { Serial.println("Connecting to MQTT..."); if (client.connect("ArduinoClient", mqttUser, mqttPassword )) { Serial.println("connected"); } else { Serial.print("failed with state "); Serial.print(client.state()); delay(2000); } } } void loop() { client.loop(); String message = "Hello, world!"; client.publish("your_topic", message.c_str()); // replace "your_topic" with the topic you want to publish to } void callback(char* topic, byte* payload, unsigned int length) { // handle message received } ``` 在上面的代码中,`your_SSID` 和 `your_PASSWORD` 用于连接到 WiFi。`your_MQTT_SERVER` 是 EMQ X Broker 的地址,`mqttUser` 和 `mqttPassword` 用于认证。您需要将 `your_topic` 替换为您想要发布消息的实际主题。您可以将 `message` 替换为您要发布的消息。一旦上传到您的 Arduino Uno,它将开始发布消息

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值