前言(问题重现)
滔滔的座右铭:明镜止水 举重若轻
最近在解决客户问题时,出现了mqtt消息阻塞的问题。与客户沟通后了解。他是用的是activemq。一个mqtt服务器挂载了将近200台设备。但是只有一台服务节点进行消费mqtt的数据。假如门禁设备上报数据多的时候,mqtt服务器的内存居高不下,甚至会出现缓存数据量反向增长的问题。
解决方法(提供多节点方案)
根据之前的项目经验,我这总结出了几点建议。首当其冲的就是消费者多节点方案,通过增加消费客户端,增加并行消费节点的方式。简单点来说就是 mqtt像一个水桶,增加节点 就是多增加几个出水管。以防水桶里的水满溢出。
遇到的问题(幂等性问题)
多节点确确实实能解决mqtt的消息堆积的问题,但是紧接着又出现了问题,同一个门禁机的同一条消息不可以被多个节点重复消费。违反了我们创建多节点消费的初衷。这里介绍下我之前项目解决此类问题的方法。
1.阿里云的rocketmq
在之前我们在社区场景里,门禁机每天的上报的数据量极大。如果全部进行实时处理,服务器的压力过于庞大。所以我们采用了阿里云开源的消息队列技术“Rocketmq”我们将设备模块上报的数据统一输出到消息队列中,再由多节点服务进行挨个消费并进行业务处理。
大体流程图:![在这里插入图片描述](https://img-blog.csdnimg.cn/706ea658461341f98fbc439d20107f9d.png)
2.关于emqx的共享订阅
但是上面的解决方案是基于消息队列的方案进行消息分流,那有没有其他的方法能将mqtt的消息发散到每一个多节点进行消费,也要保证每一条消息不会被重复消费呢。如果你使用的是emqx的mqtt服务,就可以使用共享订阅功能。
点击进入官网文档地址
总的来说 “共享订阅是在多个订阅者之间实现负载均衡的订阅方式”
原理其实很简单,在消费端的topic前加入指定的前缀(
s
h
a
r
e
/
share/
share/queue),emqx会将按照前缀进行消费分区,每个分区相互隔离,同时也能保证每个分区进行负载均衡 相同的消息只能被一个消费服务器收到。避免出现重复消费的问题。
同时emqx支持带分组的共享订阅 以及非分组的共享订阅
3.开始演示
建议使用mqttx进行测试,(具体的mqttx教程,可以在官网上直接找到,我就不多bb了)
首先自定义一个mqtt的topic进行下发。
以及创建一个消费订阅,注意在这里需要再监听topic之前面添加前缀,启动共享订阅功能。
我们继续在启动一个订阅消费端,(我用java写了一个工具类)
接下来我么开始下发测试
这里可以看到,在mqttx发送了消息。我的java客户端收到并消费信息,但是我的mqttx却没有收到,保证了消息的唯一性。
在后面继续发送,mqttx有概率会收到并消费消息,但我的java客户端并没有收到。
4.总结
本次只是大概讲了下关于emqx关于共享订阅的基本应用,其实保证mqtt或者rocketmq幂等性还有很多方法例如规定唯一消息id进行是否存在查询来保证是否收到重复消息等,后续我会补充关于消息队列的相关博客,我们下个文章见。