MQTT 主题的高级特性

什么是主题

MQTT 协议 通过网络传输应用消息,应用消息通过 MQTT 传输时,它们有关联的服务质量(QoS)和主题(Topic)。主题本质上是一个字符串,MQTT 协议规定主题是 UTF-8 编码的字符串,这意味着,主题过滤器和主题名的比较可以通过比较编码后的 UTF-8 字节或解码后的 Unicode 字符。

主题名和主题过滤器

  • 主题名 附加在应用消息上的一个标签,服务端已知且与订阅匹配。服务端发送应用消息的一个副本给每一个匹配的客户端订阅。
  • 主题过滤器 订阅中包含的一个表达式,用于表示相关的一个或多个主题。主题过滤器可以使用通配符。

如果订阅的主题过滤器与消息的主题名匹配,应用消息会被发送给每一个匹配的客户端订阅。主题资源可以是管理员在服务端预先定义好的,也可以是服务端收到第一个订阅或使用那个主题名的应用消息时动态添加的。服务端可以使用一个安全组件有选择地授权客户端使用某个主题资源。

主题和主题过滤器命名的规则

  • 所有的主题名和主题过滤器必须至少包含一个字符。
  • 主题名和主题过滤器是大小写敏感的。ACCOUNTSAccounts 是不同的主题名。
  • 主题名和主题过滤器可以包含空格字符。Accounts payable 是合法的主题名
  • 主题名或主题过滤器以前置或后置斜杠 / 区分。/financefinance 是不同的。
  • 只包含斜杠 / 的主题名或主题过滤器是合法的。
  • 主题名和主题过滤器不能包含 null 字符(Unicode U+0000)。
  • 主题名和主题过滤器是 UTF-8 编码字符串,除了不能超过 UTF-8 编码字符串的长度限制之外,主题名或主题过滤器的层级数量没有其它限制。

主题层级

主题层级分隔符

斜杠(“/” U+002F)用于分割主题的每个层级,为主题名提供一个分层结构。分隔符用于将结构化引入主题名。如果存在分隔符,它将主题名分割为多个主题层级,是消息主题层级设计中很重要的符号。 比方说:aaa/bbbaaa/bbb/cccaaa/bbb/ccc/ddd 这样的消息主题格式,是一个层层递进的关系,可通过多层通配符同时匹配两者,或者单层通配符只匹配一个。 这在现实场景中,可以应用到:公司的部门层级推送、国家城市层级推送等包含层级关系的场景。

MQTT 订阅报文包含一个主题过滤器(Topic Filter)和一个最大的服务质量(QoS)等级。订阅的主题过滤器可以包含特殊的通配符,允许客户端一次订阅多个主题。当客户端订阅指定的主题过滤器包含两种通配符时,主题层级分隔符就很有用了。主题层级分隔符可以出现在主题过滤器或主题名字的任何位置。相邻的主题层次分隔符表示一个零长度的主题层级。

主题过滤器中可以使用通配符,但是主题名不能使用通配符。单层通配符和多层通配符只能用于订阅 (subscribe) 消息而不能用于发布 (publish) 消息,层级分隔符两种情况下均可使用。

多层通配符

井字符号(“#” U+0023)是用于匹配主题中任意层级的通配符。多层通配符表示它的父级和任意数量的子层级。

例如,如果客户端订阅主题 sport/tennis/player1/#,它会收到使用下列主题名发布的消息:

  • sport/tennis/player1
  • sport/tennis/player1/ranking
  • sport/tennis/player1/score/wimbledon

因为多层通配符包括它自己的父级,所以 sport/# 也匹配单独的 sport 主题名,sport/tennis/player1/# 也可以匹配 sport/tennis/player1

单独的多层通配符 # 是有效的,它会收到所有的应用消息。

多层通配符必须单独指定,或者跟在主题层级分隔符后面。多层通配符必须是主题过滤器的最后一个字符。因此,sport/tennis#sport/tennis/#/ranking 都是无效的多层通配符。

单层通配符

加号 (“+” U+002B) 是只能用于单个主题层级匹配的通配符。例如,sport/tennis/+ 匹配 sport/tennis/player1sport/tennis/player2 ,但是不匹配 sport/tennis/player1/ranking。同时,由于单层通配符只能匹配一个层级,sport/+ 不匹配 sport 但是却匹配 sport/

在主题过滤器的任意层级都可以使用单层通配符,包括第一个和最后一个层级,可以在主题过滤器中的多个层级中使用它,也可以和多层通配符一起使用,++/tennis/#sport/+/player1 都有有效的。在使用单层通配符时,单层通配符占据过滤器的整个层级,sport+ 是无效的。

以 \$ 开头的主题

服务端不能将 $ 字符开头的主题名匹配通配符 (#+) 开头的主题过滤器, 订阅 # 的客户端不会收到任何发布到以 $ 开头主题的消息,订阅 +/monitor/Clients 的客户端也不会收到任何发布到 $SYS/monitor/Clients 的消息。服务端应该阻止客户端使用这种主题名与其他客户端交换消息,客户端注意不能使用 $ 字符开头的主题。

服务端实现可以将 $ 开头的主题名用作其他目的。,例如 $SYS/ 被广泛用作包含服务器特定信息或控制接口的主题的前缀。订阅 $SYS/# 的客户端会收到发布到以 $SYS/ 开头主题的消息,订阅 $SYS/monitor/+ 的客户端会收到发布到 $SYS/monitor/Clients 主题的消息,如果客户端想同时接受以 $SYS/ 开头主题的消息和不以 $ 开头主题的消息,它需要同时订阅 #$SYS/#

举个例子

比如我们用传感器监视家里的卧室、客厅以及厨房的温度、湿度和空气质量,可以设计一下几个主题:

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

当我们想获取卧室的所有数据时,可以订阅 myhome/bedroom/+ 主题,当我们想获取三个房间的温度数据的时候,可以订阅 myhome/+/temperature 主题,当我们想获取所有的数据的时候,可以订阅 myhome/# 或者 #

关注我们获取最新动态

推荐阅读

EMQ X 与 RabbitMQ 消息服务器 MQTT 性能对比(上)

本文深入分析了 EMQ X 以及 RabbitMQ 在核心架构上的侧重,并据此分析了它们为 MQTT 集群模式表现带来的不同影响。

EMQ X 与 RabbitMQ 消息服务器 MQTT 性能对比(下)

本文详细解读了造成上篇压力测试结果存在差异的三个原因:节点间通讯的方式、消息流架构的方式、队列的使用。

MQTT 赋能工业 PLC 数据采集与应用

集成了 MQTT 协议的 PLC 将使工业数据采集场景变得更加简单高效,结合高性能的 MQTT 消息中间件,工业生产数据更得以轻松上云。

2021-08-26