MQTT实现集群分布式消费
今天被问到启用多个应用消费时,每个消费者都会受到订阅消息的事。很久前用过,这里梳理记录一下:
MQTT协议本身是支持共享订阅功能。
这里这个共享订阅比较特殊,他有点类似kafka的消费组的概念。但是设计和实现上区别比较大。
设计理念
MQTT 共享订阅:
主要是为了在 MQTT 的发布 / 订阅模式下,实现多个订阅者对同一主题消息的高效共享和负载均衡,确保消息能够被多个订阅者均匀接收和处理,同时避免消息的重复消费。
Kafka 消费组:
基于 Kafka 的分布式消息队列架构设计,旨在实现多个消费者对多个主题分区消息的并行消费,通过消费组内的消费者协调机制,提高消息处理的吞吐量和可扩展性。
实现方式
MQTT 共享订阅:
通过在订阅主题前添加 “$share/<group>/<topic>” 的形式来标识共享订阅组,其中<group>为共享订阅组的名称,<topic>为实际的订阅主题。当消息发布到该主题时,MQTT broker 会根据一定的算法将消息分配到不同的订阅者,实现负载均衡。
Kafka 消费组:
Kafka 将每个主题划分为多个分区,每个分区中的消息是有序的。消费者以消费组的形式进行组织,同一消费组内的消费者共同消费主题的所有分区。每个分区在同一时刻只能被一个消费者消费,不同消费组之间相互独立,互不影响。
消息分配策略
MQTT 共享订阅:
通常采用轮询或随机等简单的分配策略,将消息依次或随机分配给不同的订阅者。分配过程相对简单直接,主要考虑的是在多个订阅者之间实现基本的负载均衡。
Kafka 消费组:
采用的是基于分区分配策略,如范围分配、轮询分配等。根据消费者数量和分区数量的关系,将分区合理分配给不同的消费者,确保每个消费者能够均匀地处理消息,同时充分利用分区的并行性。
消费语义
MQTT 共享订阅:
一般遵循 “最多一次” 或 “至少一次” 的消息传递语义。在 “最多一次” 语义下,消息可能会丢失;在 “至少一次” 语义下,消息可能会被重复接收和处理,需要应用层自行处理去重等问题。
Kafka 消费组:
支持多种消费语义,如 “最多一次”“至少一次”“精确一次” 等。通过配置不同的参数和使用 Kafka 提供的事务机制等,可以实现不同的消费语义,满足不同应用场景的需求。
应用场景
MQTT 共享订阅:
适用于对实时性要求较高、消息量相对较小且需要多个订阅者共享消息的场景,如物联网设备数据的实时监控和分发,多个客户端需要同时接收并处理设备上报的实时数据。
Kafka 消费组:
更适合处理大规模的消息流,对消息的吞吐量和可扩展性要求较高的场景,如实时日志收集与分析、大数据流处理等,能够支持多个消费者并行处理大量的消息数据。
以上对比了下mqtt和kafka的实现区别。这里回归mqtt共享订阅的实现。
MQTT共享订阅实现
首先,MQTT共享订阅需要EMQx版本支持,EMQx5.0以上版本默认支持,一下版本需要部分需要配置,部分无法支持,这个需要的去官网确认。
然后就是上面介绍的共享订阅的规则。这边其实是订阅时路径的约定:
“$share/<group>/<topic>”
需要用"$share"标识是共享订阅,后面紧跟的第一个单词是group分组名称,在后面可以和普通topic一样使用。
需要注意的是,订阅的时候采用这个格式,但是发布消息的时候,topic需要正常设置。不需要配置“$share/<group>/”的信息。
共享订阅策略,就是配置是轮训、或者加权轮询、或者随机等负载方案了。
注意,这里推荐配合qos使用,避免消息的丢失。
以上。