MQTT v5 共享订阅

MQTT5 共享订阅

MQTT 5.0 引入了共享订阅(Shared Subscription)的概念,这是一种新的订阅模式。

允许多个客户端共同订阅相同的主题,但只有一个客户端接收和处理该主题的消息。

示例

下面是一个 MQTT v5 中使用共享订阅的示例。

假设我们有多个 MQTT v5 客户端需要共同消费相同主题的消息,而不会重复接收到相同的消息。

为了实现这一点,客户端将使用 $share/{group_name}/{topic_filter} 的格式来订阅主题。

示例背景:

假设我们有一个 MQTT 代理(Broker),主题是 sensor/temperature,多个客户端需要订阅并处理这个主题的消息。

我们希望通过共享订阅,让多个客户端分担接收消息的负载。

共享订阅的格式:

共享订阅的订阅主题格式为:

$share/{group_name}/{topic_filter}

其中:

  • {group_name}:共享订阅的组名,表示多个客户端组成一个消费组。所有在同一个消费组中的客户端会平衡地接收到消息。
  • {topic_filter}:订阅的主题过滤器,与普通的 MQTT 订阅相同,表示客户端对消息的兴趣。

示例 1:共享订阅的具体操作

假设我们有 3 个 MQTT v5 客户端,它们分别属于同一个消费组 group1,并且都希望订阅 sensor/temperature 主题。它们将分别使用以下订阅:

  • 客户端 1(client1)订阅:$share/group1/sensor/temperature
  • 客户端 2(client2)订阅:$share/group1/sensor/temperature
  • 客户端 3(client3)订阅:$share/group1/sensor/temperature

详细步骤:

  1. 发布消息: 假设有一个 MQTT v3.1.1 或 v5 客户端(publisher)发布了消息到 sensor/temperature 主题,消息内容是:

    温度: 22°C
    
  2. 共享订阅: 这时,client1client2client3 都通过共享订阅的方式来订阅 sensor/temperature 主题。它们分别使用:

    $share/group1/sensor/temperature
    

    这些客户端不会收到相同的消息,而是通过负载均衡的方式,消息会均匀地分配给这三台客户端中的某一台。

  3. 负载均衡

    • 在这种设置下,client1client2client3将轮流接收消息。例如:
      • client1 可能首先接收到消息 温度: 22°C
      • 下一条消息将由 client2 接收。
      • 然后是 client3,依此类推。
    • 消息会被轮流分配给这些客户端,避免重复接收。
  4. 客户端断开和重连: 如果某个客户端(例如 client2)断开连接并重新连接,它将重新加入共享订阅组,Broker 会根据当前的负载均衡策略,决定将消息分配给哪个客户端。

通配符

是的,$share/{group_name}/{topic_filter} 格式在 MQTT v5 中是支持通配符的。

支持的通配符:

与普通的 MQTT 订阅一样,$share/{group_name}/{topic_filter} 也支持使用通配符来订阅多个主题。具体支持的通配符包括:

  • +(单层通配符):表示匹配主题层级中的单个元素。
  • #(多层通配符):表示匹配主题中的多个层级(包括零个层级)。

示例 1:单层通配符(+

假设你希望共享订阅所有以 sensor/ 开头的主题,比如 sensor/temperaturesensor/humidity 等。你可以使用单层通配符 + 来订阅:

$share/group1/sensor/+

这个订阅会匹配所有以 sensor/ 开头的主题,例如:

  • sensor/temperature
  • sensor/humidity
  • sensor/pressure

示例 2:多层通配符(#

如果你想订阅所有以 home/ 开头的主题,并且包含任意层级的子主题,可以使用多层通配符 #

$share/group1/home/#

这个订阅会匹配以下主题:

  • home/livingroom/temperature
  • home/kitchen/humidity
  • home/bedroom/airquality

注意事项:

  1. 通配符使用的限制+ 通配符只能替代一个主题层级,而 # 通配符只能出现在主题的末尾,且只能用一次(比如不能在中间或主题的其他部分使用 #)。
  2. 共享订阅组与通配符:使用通配符的共享订阅,多个客户端将会根据共享订阅的规则进行负载均衡。例如,$share/group1/sensor/+ 会将所有匹配 sensor/ 开头的主题的消息分配到共享订阅组 group1 中的客户端。

总结:

在 MQTT v5 中,$share/{group_name}/{topic_filter} 格式确实支持使用通配符。你可以灵活地订阅多个主题,确保消息的负载均衡和高效处理,尤其适用于需要处理大量不同主题的场景。

SpringBoot 代码

依赖

<!-- MQTT -->
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-mqtt</artifactId>
</dependency>

<!-- 使用 MQTT v5 版本 -->
<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.mqttv5.client</artifactId>
    <version>1.2.5</version>
</dependency>

代码

原来

    /**
     * 入站
     */
    @Bean
    public MessageProducer inbound() {
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter("consumerClient-" + UUID.randomUUID().toString(),
                mqttClientFactory(),  "/test/#");
        adapter.setCompletionTimeout(5000);
        DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();
        adapter.setConverter(defaultPahoMessageConverter);
        adapter.setQos(1);
        adapter.setOutputChannel(mqttInputChannel());
        return adapter;
    }

订阅主题通配符由 test/# 改为:$share/test-group/test/#,其他代码不修改。

    /**
     * 入站
     */
    @Bean
    public MessageProducer inbound() {
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter("consumerClient-" + UUID.randomUUID().toString(),
                mqttClientFactory(),  "$share/test-group/test/#");
        adapter.setCompletionTimeout(5000);
        DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();
        adapter.setConverter(defaultPahoMessageConverter);
        adapter.setQos(1);
        adapter.setOutputChannel(mqttInputChannel());
        return adapter;
    }

如果使用 MQTT 客户端测试,还可以订阅主题 test/#,不会影响共享订阅组。

订阅组名称

$share/test-group/test/# 的结构

  • $share/ 是 MQTT v5 中的一个特殊前缀,用于标识共享订阅。
  • test-group 是你为这个共享订阅组自定义的名称。可以自定义成任何字符串,用于区分不同的订阅组。
  • test/# 是你实际订阅的主题,# 是一个通配符,表示匹配 test/ 下的所有子主题。

特点和注意事项

共享订阅特点

这有助于分散负载和实现协同订阅的需求。

以下是 MQTT 5.0 共享订阅的主要特点:

  1. 订阅组(Subscription Group):在 MQTT 5.0 中,多个客户端可以共同订阅相同的主题,这些客户端被组织成一个订阅组。每个订阅组内只有一个客户端会接收到发布到该主题的消息
  2. 消息负载均衡:共享订阅允许多个客户端在一个订阅组内共享消息的负载。这意味着,当消息发布到被共享订阅的主题时,代理会选择订阅组内的一个客户端来接收消息,以实现负载均衡,确保不会让所有客户端都接收相同的消息。
  3. 组成员管理:MQTT 5.0 提供了一些机制来管理订阅组的成员。客户端可以加入或离开订阅组,以便灵活地控制哪个客户端会接收消息。
  4. 订阅选项:MQTT 5.0 的共享订阅引入了一些新的订阅选项,如"不公平"(Unfair)和"公平"(Fair)订阅。不公平订阅是默认的,它只发送消息给订阅组内的一个客户端,而公平订阅会轮流发送消息给不同的组成员,确保公平分配消息。
  5. 附加数据:MQTT 5.0 还允许在共享订阅时使用附加数据。这可以用于在选择哪个客户端接收消息时提供额外的信息或条件。

共享订阅的优势:

  • 负载均衡:通过共享订阅,多个客户端可以共同处理高频率的消息流,避免某一个客户端过载。
  • 消息不重复:多个客户端不必重复处理同一条消息,避免浪费计算资源。
  • 弹性扩展:可以根据需要增加或减少客户端,负载均衡会自动调整。

注意事项:

  • 共享订阅必须由 MQTT v5 客户端发起,MQTT v3.1.1 客户端无法使用共享订阅功能。
  • Broker 支持:不是所有的 MQTT Broker 都完全支持 MQTT v5 和共享订阅,因此需要确保你的 Broker 支持这些特性(例如,Eclipse Mosquitto、EMQX、HiveMQ 等 Broker 支持 MQTT v5 和共享订阅)。

总结

通过共享订阅,多个客户端可以高效地协作处理消息,避免重复消费,提高系统的吞吐量和性能。这种机制特别适用于需要横向扩展的消息处理场景。

posted @ 2024-12-25 21:55  ioufev  阅读(1066)  评论(0)    收藏  举报