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数据存在内存,吞吐极大,性能没有问题。

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

 

 

你可能感兴趣的:(mqtt)