本文介绍MQTT主题的工作方式、如何在主题字符串中使用通配符,并提供示例,帮助您在MQTT部署中有效使用该特性。
主题
在MQTT中,主题是通信模型的基础。它们作为寻址机制,使发布者和订阅者能够交换消息。 主题分两类:
- 主题名称(Topic Names)。发布者用于发送消息。不得包含通配符或以
$开头(此类主题保留给TBMQ系统用途)。 - 主题过滤器(Topic Filters)。订阅者用于接收消息,可包含通配符字符如
#和+。
请注意,MQTT主题长度不得超过65535字节。 此外,主题至少1个字符长,且不得包含空字符。
MQTT主题具有层级结构,使用正斜杠或分隔符(/)作为主题层级分隔符。
该分隔符将主题树划分为“主题层级”。
例如,主题可为 sensors/livingroom/temperature,其中 sensors、livingroom 和 temperature 为主题层级。
此结构便于有效控制消息路由,尤其在主题中使用通配符时。
通配符
MQTT主题中的通配符提供强大机制,用于简化对多主题的订阅并降低动态环境中管理主题订阅的复杂度。订阅者可使用模式以单一订阅匹配多个主题层级。
MQTT支持两类通配符:
- 多层通配符(
#) ——匹配主题字符串末尾任意数量的层级。 - 单层通配符(
+) ——匹配主题层级中的一层。
多层通配符
井号(#)是匹配主题层级中所有剩余层级的通配符。它代表父级及任意数量的子层级。
| 订阅主题过滤器 | 匹配的主题 | 不匹配的主题 |
| sensors/# |
sensors sensors/ sensors/livingroom sensors/livingroom/window |
/sensors |
多层通配符 # 必须:
- 仅使用一次。
- 位于主题过滤器末尾。
- 前接分隔符(
/)。
以下主题过滤器无效,因 # 通配符未正确置于主题过滤器末尾或未由分隔符正确前接:
#sensors#/sensorssensors/#/sensors/#/temperature
单层通配符
加号(+)表示主题层级中的单层。可用于在特定层级上以共同模式订阅主题。
| 订阅主题过滤器 | 匹配的主题 | 不匹配的主题 |
| sensors/+/temperature |
sensors/livingroom/temperature sensors/bedroom/temperature |
sensors/livingroom/window/temperature sensors/temperature |
单层通配符 + 必须:
- 位于主题过滤器开头或紧跟正斜杠
/。 - 位于主题过滤器末尾或被正斜杠
/紧跟。
以下主题过滤器无效,因 + 通配符相对分隔符的位置不正确:
+sensorssensors+sensors/home+sensors/+home
通配符使用示例
以下示例展示在MQTT主题中单层与多层通配符不同位置上,订阅模式所具有的灵活性与深度。
| 订阅主题过滤器 | 匹配的主题 |
| sensors/+/temperature/# |
sensors/livingroom/temperature sensors/bedroom/temperature sensors/livingroom/temperature/status |
| sensors/+/sensor/# |
sensors/kitchen/sensor/temperature sensors/bedroom/sensor/humidity sensors/livingroom/sensor/light/intensity |
| +/house/# |
north/house/livingroom/temperature south/house/kitchen/humidity east/house/garden/light/intensity |
| factory/+/status/# |
factory/machine1/status factory/machine2/status factory/machine1/status/error |
| +/devices/+/battery |
home/devices/laptop/battery office/devices/phone/battery car/devices/gps/battery |
| building/+/room/+/temperature |
building/1stfloor/room/101/temperature building/2ndfloor/room/201/temperature building/3rdfloor/room/301/temperature |
最佳实践
设计MQTT主题时,遵循最佳实践有助于保证清晰、一致和可维护。
- 避免空白和特殊字符(除
/外)。虽未明确禁止,但可能引起混淆或错误。 - 避免驼峰命名。统一使用小写以避免大小写混淆。主题区分大小写,即
sensors/temperature与Sensors/Temperature视为不同主题。 - 避免主题以正斜杠(
/)开头或结尾。易造成理解困难和不一致。例如sensors/home与/sensors/home视为不同主题。 - 避免订阅所有主题。订阅
#表示客户端将接收broker上发往任一提主题的每条消息,可能很快被大量消息淹没,导致性能问题甚至崩溃。 - 避免过深的层级结构,随时间推移难以维护。使用清晰、描述性强且层级化的主题名,例如
building/floor1/room1/temperature。 - 避免不可打印字符,以保证跨系统兼容并减少意外问题。尽量仅使用ASCII字符。
多订阅匹配
在MQTT中,一个客户端可以有多个订阅,其中多个订阅匹配同一条发布消息的主题。
假设客户端订阅以下主题:
sensors/+/temperaturesensors/room1/#
若消息发布到主题 sensors/room1/temperature,两个订阅均匹配该主题。
此时TBMQ不会向每个匹配订阅各发一份。 而是将消息投递给 QoS最高的订阅,或当多个订阅QoS相同时投递给第一个匹配的订阅。
配置最大主题段数
在TBMQ配置中,可定义主题中允许使用的最大正斜杠(/)数量。
默认不限制,因环境变量 MQTT_TOPIC_MAX_SEGMENTS_COUNT 设为 0(禁用)。
主题名中段数过多会负面影响处理时间和性能。 每增加一个段都会提高broker内主题匹配与路由的复杂度,可能导致延迟上升和资源消耗增加。
例如,若将 MQTT_TOPIC_MAX_SEGMENTS_COUNT 设为 2,则当用户尝试在主题中使用超过两个正斜杠(/)时(如 sensors/floor1/room1/temperature 含3个正斜杠),broker将抛出错误。
共享订阅主题
还需提及 共享订阅 特性,用于在多个订阅者间分发消息,实现负载均衡和资源高效利用。
共享订阅主题具有特定格式,以区别于普通主题。
共享主题的通用结构为:
1
$share/{ShareName}/{TopicFilter}
其中:
- $share —— 表示该订阅为共享订阅的常量。
- {ShareName} —— 共享订阅的标识符,用于区分其他共享订阅。
- {TopicFilter} —— 表示用于订阅的主题过滤器,与普通订阅类似。
可包含通配符如
#和+以匹配多个主题。
共享订阅主题示例:
1
$share/group1/country/+/city/+/home/#