MQTT 5.0协议新特性
2021-01-11 12:14:51 来源:华启智能
作为 MQTT 3.1.1 的后续版本,为什么版本号直接变成了 5.0?因为 3.1.1 在 CONNECT 的时候指定的 Protocol Version 为 4,所以后续版本只有使用 5 了。
MQTT 5.0 在 MQTT 3.1.1 的基础上做了很多改变,并不是向下兼容的。在协议上,就增加了Property
字段,也正是因为这个字段,使得MQTT 5.0可以支持众多的新特性。下面将从以下几个新特性进行介绍,这些新特性能够解决在3.1.1版本中较难处理的问题。
1. 用户属性(User Properties)
5.0 中可以在 PUBLISH、CONNECT 和带有 Return Code的数据包中夹带一个和多个用户属性数据:
- 在 PUBLISH 包中携带的用户属性由发送方的应用定义,随消息被 Broker 转发到消息的订阅方;
- CONNECT 和 ACKs 消息里面也可以带发送者自定义的用户属性数据。
在实际的项目中,除了关心收到的消息内容,往往也想知道这个消息来自于谁。例如:ClientA 收到 ClientB 发布的消息后,ClientA 想给 ClientB 发送一个回复,这时 ClientA 必须知道 ClientB 订阅的主题才能将消息传递给 ClientB。在 MQTT 3.1.1 中,我们通常是在消息数据中包含发布方的信息,比如它订阅的主题等。5.0 以后就可以把这些信息放在 User Properties 里面了。
2. 共享订阅(Shared Subscriptions)
在 3.1.1 和之前的版本,订阅同一主题的订阅者都会同样收到来自这个主题的所有消息。例如你需要处理一个传感器的数据,假设这个传感器上传的数据量非常大且频率很高,你没有办法通过启动多个 Client 来分担处理的工作,因为多个Client都会同样收到所有消息。
针对上述的问题,也许可以启动一个 Client 来接收传感器的数据,并将这些数据分配给后面多个 Worker 来处理。这个用于接收数据的 Client 就是系统的瓶颈和单点故障之一。也可以通过主题分片,如让传感器依次发布到 /topic1…/topicN 来变通地解决这个问题,但仅仅是解决了部分问题,同时也提高了系统的复杂度。
而在 5.0 里面,MQTT 可以实现 Producer/Consumer 模式了。多个 Client(Consumer)可以一起订阅一个共享主题(Producer),来自这个主题的消息会依次均衡地发布给这些 Client,实现订阅者的负载均衡,最终解决了这个问题。
这个功能在传统的队列系统中,比如 RabbitMQ里面很常见。EMQTT 在 3.1.1 上已经支持这个功能了,详情可以查询官方文档
3. 消息过期(Publication Expiry Interval)
假设一个基于 MQTT 的共享单车平台,用户通过平台下发一条开锁指令给一辆单车,但是不巧的是,单车的网络信号(比如 GSM)这时恰好断了,用户摇了摇头走开去找其他车了。过了两个小时以后,单车的网络恢复了,它收到了两个小时以前的开锁指令,该怎么做?
为了处理这种情况,在 3.1.1 和之前的版本,我们往往都是在消息数据里带一个消息过期时间,在接收端来判断消息是否过期。但是这要求设备端的时间和 Server 端保持一致,对于一些电量不是很充足的设备,一但断电,之后再启动时间就会变得不准确,会导致异常的出现。
5.0 中终于包含了消息过期的功能,在发布的时候可以指定这个消息在多久之后过期,Broker 不会将已过期的离线消息发送到 Client。
4. 重复主题
在 MQTT 3.1.1 和之前的版本里,PUBLISH 数据包每次都需要带上发布的主题名,即使你每次发布的都是同一个主题。
在 5.0 里面,如果你将一条 PUBLISH 的主题名设为长度为 0 的字符串,那么 Broker 会使用你上一次发布的主题。这样降低了多次发布到同一主题(往往都是这样)的额外开销,对网络资源和处理资源都有限的系统非常有用。
5. Broker 能力查询
在 5.0 里面,CONNACK 包含了一些预定义的头部数据,用于标识 Broker 支持哪些 MQTT 协议功能。Client 在连接之后就可以知道 Broker 是否支持自己所要用到的功能,这对于一些通用的 MQTT 设备生产商或者 Client 库的开发者很有用。
Pre-defined Header | 数据类型 | 描述 |
---|---|---|
Retain Available | Boolean | 是否支持 Retained 消息 |
Maximum QoS | Number | Client 可以用于订阅和发布的最大 QoS |
Wildcard available | Boolean | 订阅时是否可以使用通配符主题 |
Subscription identifiers available | Boolean | 是否支持 Subscription Identifier(5.0 特性) |
Shared Subscriptions available | Boolean | 是否支持共享订阅 |
Maximum Message Size | Number | 可发送的最大消息长度 |
Server Keep Alive | Number | Broker 支持的最大 Keep Alive 值 |
6. 双向DISCONNECT
在 3.1.1 和之前的版本里,只有 Client 在主动断开时会向 Broker 发送 DISCONNECT 包。如果因为某种错误 Broker 要断开和 Client 的连接,它只能直接断开底层 TCP 连接,Client 则不会知道自己连接断开的原因,也无法解决错误,只是简单地重新连接、被断开、重新连接…
在 5.0 里面,Broker 在主动断开和 Client 的连接时也会发送 DISCONNECT 包。同时,从 Client 到 Broker,以及从 Broker 到 Client 的 DISCONNECT 包里面都会包含一个 Reason Code,来标识断开的原因。
Reason code | 发送方 | 描述 |
---|---|---|
0 | Client 或 Broker | 正常断开连接,不发送遗愿消息 |
4 | Client | 正常断开,但是要求 Broker 发送遗愿消息 |
129 | Client 或 Broker | MQTT 数据包格式错误 |
135 | Broker | 请求未授权 |
143 | Broker | 主题过滤器格式正确,但是 Broker 不接收 |
144 | Client 或 Broker | 主题名格式正确,但是 Client 或者 Broker 不接收 |
153 | Client 或者 Broker | 消息体格式不正确 |
154 | Broker | 不支持 Retained 消息 |
155 | Broker | QoS 等级不支持 |
158 | Broker | 不支持共享订阅 |
162 | Broker | 订阅时不支持通配符主题名 |
参考网址:
- 官方文档
- 转载自:https://blog.csdn.net/programguo/article/details/100125251