Suiko, 一个普通的软件工程师。 在 Github , Twitter 或者 Telegram 上可以找到我。

MQTT 基础与 MQTT5 新增特性

7 分钟阅读
博文封面图片

基础

概念

MQTT是一个客户端服务端架构的发布/订阅模式的消息传输协议。它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M)以及物联网环境(IoT)。

——MQTT 协议规范中文版

用于嵌入式设备的通讯协议需要满足以下条件:

  • 易于实现
  • 数据传输的服务质量可控
  • 占用带宽小
  • 传输数据内容不可预知
  • 设备连接状态可知

MQTT 协议很好的满足了以上条件,可以看出,MQTT 从诞生之初就是专为低带宽、高延迟或不可靠的网络而设计的。

基本原理

在 MQTT 协议的通讯中,主要分为 MQTT 服务端与 MQTT 客户端两种角色:

  • MQTT 服务端。MQTT 服务端的角色通常由一台服务器来担任,负责将 客户端 A 的信息传递给 客户端 B。
  • MQTT 客户端。MQTT 客户端可以”发布“信息,可以通过”订阅“收取信息。

MQTT 客户端通过向主题发布数据来让订阅了此主题的客户端能够获取信息,可以通过以下图片来理解:

需要注意的是,MQTT 客户端在通讯时,往往会同时担任发布者与订阅者的角色。如汽车是”汽车速度“主题的发布者,同时也会是”空调温度“主题的订阅者。

基本特性

  • 相互独立。MQTT 客户端无需知道有多少个其他的客户端,只需要对主题进行订阅/发布即可。
  • 空间分离。设备间的通讯只需要连接了同一个 MQTT 通讯网络即可,无论是局域网或者是互联网。
  • 时间可异步。如果某个订阅了主题的客户端掉线了,而此时有其他客户端向这个主题发布了数据,MQTT 服务端会在掉线的客户端上线后继续发布,防止信息丢失,从而达成时间可异步的效果。

版本

目前 MQTT 主流版本有 3.1 与 5.0,MQTT 3.1 在 2014 年 10 月发布,而 MQTT 5.0 在 2019 年 3 月发布,下文主要介绍 MQTT 5.0 引入的一些重要特性。

MQTT5

用户属性(User Properties)

用户属性由用户自定义的 UTF-8 键值对数组组成,允许用户向 MQTT 消息添加元数据,类似 HTTP 协议中的 Header 。

用户属性的出现,解决了 MQTT 3.1 的扩展性问题。举个使用例子,不同的客户端可能使用不同的消息数据格式,类比 HTTP Header,我们可以自定义一个用户属性:

{
  "content-type": "JSON"
}

此用户属性很简单,标注了 MQTT 消息内容格式,这样服务器接收到了消息后就不需要判断内容格式了,可以直接通过 content-type 来获取。

消息过期(Publication Expiry Interval)

上述提过 MQTT 的时间可异步的特性,这个特性在某些情况会成为一个麻烦事,举个例子,共享单车作为一个 MQTT 的客户端,用户下发了一条开锁指令,好巧不巧,共享单车的信号刚好在此时断了,两个小时后才恢复,此时因为时间可异步的特性,收到了两个小时前下发的开锁指令。一般来讲,在 5.0 之前的 MQTT 协议版本,会在消息数据中直接携带一个消息过期时间来让接收端判断消息是否过期。但是这个处理方式需要客户端的时间能和服务端保持一致。

在 5.0 中因为包含了消息过期功能,服务端不会将已过期的消息发送给客户端,客户端对上述情况的处理就不再需要保证时间的准确性了,因为压根都不会收到已过期的消息了。

共享订阅(Shared Subscriptions)

订阅同一主题的所有订阅者都会收到来自于此主题的所有消息。这会导致当此主题发布的信息数据量大且频次高时,没有办法启动多个客户端来分担处理工作,因为所有订阅者都会收到相同的消息。

当然我们可以让一个客户端接收消息,背后用多个 worker 来处理。但是这个客户端就会成为系统的瓶颈与单点故障的成因。

在 MQTT5 中可以使用多个客户端订阅一个共享主题来进行优化了。来自这个主题的消息会依次均衡地发布给这些客户端,实现订阅者的负载均衡。

参考资料

https://ithelp.ithome.com.tw/articles/10257223

https://www.jianshu.com/p/f4f50821eb98

https://www.cnblogs.com/schips/p/12288380.html

评论区