MQTT简介
在讨论IoT与实时通信时,首要问题之一便是: 什么是MQTT?
MQTT是一种为受限设备及低带宽、高延迟或不可靠网络设计的轻量级消息协议。 它采用发布/订阅消息模型,使设备能在资源受限的环境中高效通信, 如IoT(物联网)系统、移动应用和嵌入式系统。 MQTT以简洁为目标,保证最小开销,便于从微型传感器到大型工业系统等各种设备的实现。
MQTT协议格式
MQTT协议旨在最小化数据传输开销。消息由固定头、可选可变头和负载组成。 格式如下:
- 固定头(Fixed Header):
- 存在于每条MQTT消息中,由控制字节和标志组成。
- 表明消息类型(如CONNECT、PUBLISH、SUBSCRIBE)及具体控制信息。
- 可变头(Variable Header):
- 根据消息类型包含附加信息。
- 例如报文标识符或特定消息中的主题名。
- 负载(Payload):
- 承载实际应用数据或消息内容。
- 对发布消息而言为传输的数据;对订阅消息而言为主题过滤器。
固定头与可变头的简单格式使MQTT能保持消息体积小并优化网络使用。
与其他协议对比
相比广泛使用的消息与通信协议,MQTT以简洁及对低带宽环境的专注见长。简要对比如下:
- MQTT vs HTTP:
- HTTP 是常用于Web应用的请求/响应协议。需要更高带宽和更多开销,对资源受限设备不太适合。HTTP为无状态,即客户端每次请求都须包含全部必要信息,增加数据负载。
- MQTT 在持久连接上工作,在客户端与broker间维持轻量、有状态的会话,支持以最小开销进行持续数据交换,适合低功耗与带宽消耗优先的IoT应用。
- MQTT vs CoAP(受限应用协议):
- CoAP 是另一为受限设备设计的协议。与HTTP类似,基于UDP采用请求/响应模型,但为IoT减少了开销。
- MQTT 则使用TCP保证可靠投递,支持发布/订阅模型,更适合设备需收发消息而无需发送方与接收方直接通信的场景。
- MQTT vs AMQP(高级消息队列协议):
- AMQP 功能更丰富,支持复杂消息模式,常用于企业消息系统。
- MQTT 侧重简洁与最小开销,AMQP 在消息保证(如消息队列、路由)上提供更多控制,但复杂度和资源需求更高。
简言之,MQTT在简洁、低带宽与能效关键的场景中优势明显, 而HTTP、CoAP、AMQP等协议更适合需要更丰富特性、更复杂通信模式或更高网络带宽的应用。
MQTT协议的用途
MQTT的主要目标是在设备间提供灵活高效的数据传输,尤其适用于:
- 低带宽受限的环境。
- 功耗需尽可能降低。
- 网络可靠性不稳定。
通过小消息体积和轻量通信,MQTT使处理能力和内存受限的设备也能参与数据交换。 在IoT应用中尤其流行,使设备能以最小开销相互通信、与云平台或数据处理系统通信。
MQTT的典型用例包括:
- 智能家居自动化(照明、HVAC、安防系统)。
- 可穿戴设备(健身追踪、健康监测)。
- 车联网(车辆遥测、车队管理)。
- 工业监控与控制(工厂设备传感器)。
核心原则
MQTT基于以下核心原则工作:
- 发布/订阅模型:
- 发布者向特定主题发送消息,无需知道接收者(订阅者)是谁。
- 订阅者对特定主题表示兴趣,仅接收与其订阅匹配的消息。 该模型解耦了消息生产者与消费者,支持更可扩展、更灵活的通信模式。
- 基于broker的通信:
- MQTT broker作为中心中介,在发布者与订阅者之间路由消息。
- broker负责管理连接、分发消息,并根据请求的服务质量(QoS)级别确保可靠投递。
- 多个客户端可对同一主题发布和订阅,broker确保消息投递给所有相关订阅者。
MQTT架构
MQTT协议的核心是简洁而强大的架构,实现设备间可扩展、高效的通信。 架构基于三大组件:Client、Broker和Topic,各自在保障消息投递与通信顺畅中发挥不同作用。
- Client(客户端):
- 在MQTT中,client 可以是参与通信的任何设备或系统。它可发布数据或订阅以接收数据。客户端多为传感器、移动设备或嵌入式系统等受限设备。
- Publisher(发布者):向特定主题发送或“发布”消息的客户端。
- Subscriber(订阅者):监听或“订阅”感兴趣主题以接收已发布数据的客户端。
- 客户端无需相互了解,仅与 broker 交互。使MQTT可扩展且高效,尤其在设备数量显著增长时。
- Broker:
- broker 作为中心服务器,负责在客户端间路由消息。保证由某客户端发布的消息送达所有订阅相关主题的客户端。
- broker还管理客户端连接,根据指定QoS(服务质量)处理消息投递,并可为离线客户端持久化消息。
- broker解耦发布者与订阅者,使二者可独立运行,从而构建更可扩展的系统,客户端无需直接了解彼此。
- Topic(主题):
- topic 本质上是传输数据的通道。发布者向特定主题发送消息,broker将该消息投递给该主题的所有订阅者。
- 主题以层级结构组织,订阅者可监听特定主题或使用通配符(
+、#)一次订阅多个主题。 - 示例:主题可为
/home/livingroom/temperature,客户端在此发布温度数据,该主题的任意订阅者都会收到该数据。
MQTT消息流
在MQTT中,消息通过发布/订阅模式交换,将消息生产者(发布者)与消费者(订阅者)解耦。这使得跨众多设备实现灵活、可扩展的通信成为可能。该流程的关键在于broker,它负责在发布者与订阅者之间路由消息。
- 消息交换方式:
- 发布者向broker上的特定主题发送消息,broker充当中央消息处理器。
- 订阅者通过订阅特定主题来表达兴趣。当消息被发布到某个主题时,所有订阅该主题的客户端都会通过broker接收到该消息。
- 系统允许多个发布者和订阅者独立运行,简化通信管理并支持强大的多对多通信模式。
- 消息类型说明: MQTT定义了多种报文类型,也称为控制报文,用于管理客户端与broker之间的通信:
CONNECT
- 用途: 在客户端和broker之间建立连接。
- 报文格式:
- 固定头: 包含报文类型和标志。
- 可变头: 包含重要的连接信息,如协议名称、协议级别、清除会话标志等。
- 负载: 包含客户端特定数据,如
clientId、username、password,以及可选的遗嘱主题和消息。 - 描述:
- 由客户端发送以请求连接到broker。
- 包含认证信息(用户名、密码)和连接选项(保活时间、清除会话)。
- 可包含遗嘱消息(LWT),以便在客户端意外断开时通知其他客户端。
CONNACK
- 用途: 确认客户端的连接请求。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含
return code,指示连接是否成功。 - 描述:
- 由broker发送以响应CONNECT报文。
- 指示连接被接受还是被拒绝(例如由于认证失败)。
PUBLISH
- 用途: 将应用消息从发布者投递到broker(并最终投递给订阅者)。
- 报文格式:
- 固定头: 报文类型、DUP标志(用于重复消息)、QoS级别、Retain标志。
- 可变头: 包含主题名称,在QoS级别为1或2时还包含报文标识符。
- 负载: 包含要投递的实际消息内容。
- 描述:
- PUBLISH报文由发布者发送到broker,包含要发送给订阅客户端的消息。
- 包含QoS级别以定义消息的投递方式以及是否需要确认。
- 消息可标记为保留消息,以便后续订阅者在订阅时即可收到。
PUBACK
- 用途: 确认在使用QoS 1时收到PUBLISH报文。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含与原始PUBLISH报文对应的报文标识符。
- 描述:
- 由订阅者或broker发送以确认从发布者收到的QoS 1消息。
- 确保使用QoS 1时消息被准确投递一次。
PUBREC
- 用途: 确认在使用QoS 2时收到PUBLISH报文。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含PUBLISH报文的报文标识符。
- 描述:
- 确保QoS 2消息仅投递一次的第一步。
- 在收到QoS 2的PUBLISH消息后由订阅者或broker发送,以开始握手流程。
PUBREL
- 用途: 确认在QoS 2通信中收到PUBREC报文。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含PUBREC报文的报文标识符。
- 描述:
- 由发布者在收到PUBREC后发送,表示发布者已准备好完成消息投递。
- QoS 2通信握手流程的一部分。
PUBCOMP
- 用途: 确认QoS 2消息投递完成。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含报文标识符。
- 描述:
- 由订阅者发送以确认QoS 2消息已完全处理。
- 这标志着QoS 2投递的四步握手流程结束。
SUBSCRIBE
- 用途: 为客户端订阅一个或多个主题。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含报文标识符。
- 负载: 包含主题过滤器列表及其关联的QoS级别。
- 描述:
- 由客户端发送给broker以订阅特定主题。
- 每个主题可以关联不同的QoS级别,取决于客户端希望如何接收消息。
SUBACK
- 用途: 确认SUBSCRIBE报文。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含来自SUBSCRIBE报文的报文标识符。
- 负载: 包含返回码列表,指示每个主题的订阅是否成功。
- 描述:
- 由broker发送以确认或拒绝客户端对每个请求主题的订阅。
UNSUBSCRIBE
- 用途: 取消客户端对一个或多个主题的订阅。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含报文标识符。
- 负载: 包含要取消订阅的主题列表。
- 描述:
- 由客户端发送给broker以移除对特定主题的订阅。
UNSUBACK
- 用途: 确认UNSUBSCRIBE报文。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含来自UNSUBSCRIBE报文的报文标识符。
- 描述:
- 由broker发送以确认客户端已取消订阅指定主题。
PINGREQ
- 用途: 由客户端发送以检查broker是否仍然可用。
- 报文格式:
- 固定头: 报文类型和标志(此报文没有可变头或负载)。
- 描述:
- 在客户端没有数据要发送但需要维持与broker的连接时定期发送。
- 用于确保连接仍然存活,尤其是在预期有较长不活动期间时。
PINGRESP
- 用途: 确认PINGREQ报文。
- 报文格式:
- 固定头: 报文类型和标志(此报文没有可变头或负载)。
- 描述:
- 由broker在收到PINGREQ报文后发送,以确认其仍与客户端保持连接。
DISCONNECT
- 用途: 由客户端发送以正常断开与broker的连接,并可选择提供断开原因。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头(仅MQTT5.0):包含可选的
Reason Code(如正常断开、会话过期)以及可选的Session Expiry Interval或User Properties。 - 描述:
- 客户端发送此报文以表示有意断开连接,允许broker在需要时清除会话状态。
AUTH
- 用途: 用于MQTT会话中的认证,特别是在MQTT5.0中,在初始连接后继续或完成认证过程。
- 报文格式:
- 固定头: 报文类型和标志。
- 可变头: 包含
Auth Method和Auth Data,以及可选的Reason Code和User Properties。 - 负载:
Auth Data的内容,取决于所使用的认证方法(如SASL机制、OAuth令牌)。 - 描述:
- AUTH报文在MQTT5.0中引入,用于支持增强的认证流程。它允许需要客户端与broker之间多次交换的复杂认证方法。
- 在CONNECT报文之后,如果broker需要额外的认证步骤,它可能发送AUTH报文,客户端可以用另一个AUTH报文响应,直到认证过程完成。
- 与以前的MQTT版本相比,该机制支持更安全、可插拔的认证机制。
服务质量(QoS)级别
MQTT定义了三种服务质量(QoS)级别,用于控制客户端与broker之间的消息投递可靠性:
- QoS 0(最多一次): 消息最多投递一次,不需要确认。也被称为”发后即忘”。不保证投递。
- QoS 1(至少一次): 保证消息至少投递一次,但如果确认丢失,消息可能被投递多次。
- QoS 2(恰好一次): 保证消息恰好投递一次,通过四步握手流程确保投递无重复。
这些级别根据应用程序的可靠性需求提供了灵活性。
会话管理
MQTT中的会话管理定义了broker如何随时间维护客户端连接的状态。它影响消息投递、订阅和其他会话数据。
- 持久会话:
- broker存储会话信息(如订阅和未投递的消息),即使客户端断开连接也是如此。当客户端重新连接时,可以从断开处恢复,接收离线期间错过的消息。
- 清除会话:
- 使用清除会话时,客户端断开连接后所有会话数据(订阅、未投递消息)将被清除。客户端重新连接时将重新开始,没有之前会话的历史记录。
客户端重连与消息重投递:
- 当客户端断开后重新连接时,如果使用了持久会话,broker可以重新投递所有错过的消息。
- 如果使用QoS 1或2,broker确保消息被重新投递直到被客户端确认,保证消息可靠性。
这种会话灵活性使客户端即使在间歇性连接的情况下也能维持持续运行。
MQTT协议版本
MQTT3.1.1与MQTT5.0的区别:
- MQTT3.1.1: 该版本被广泛采用,提供发布/订阅模型、QoS级别和简单会话管理等核心功能。以轻量级和易于实现而著称。
- MQTT5.0: 在MQTT3.1.1的基础上引入了更多高级特性,以增强可扩展性、灵活性和控制能力。
MQTT5.0的新特性:
-
原因码: 为成功操作和错误提供详细反馈,改善客户端与broker之间的诊断和错误处理。
-
用户属性: 允许客户端和broker在MQTT报文中附加自定义键值对,为传输元数据或应用特定信息提供更大灵活性。
-
会话过期: 客户端可指定断开连接后broker应保留其会话数据(如订阅或未投递消息)多长时间,提供更好的会话持久化控制。
-
消息过期间隔: 消息可设置过期时间,允许broker丢弃超过该时间范围的未投递消息,防止过期消息被投递。
-
共享订阅: 允许多个客户端共享接收同一主题消息的负载,适用于高流量环境中的负载均衡。
-
主题别名: 允许客户端用别名替代常用主题名以减小消息体积,优化带宽受限网络中的性能。
-
增强认证(AUTH报文): 增加对更复杂的多步认证机制的支持,便于集成OAuth等高级安全协议。
-
流量控制: 引入客户端控制消息接收速率的能力,防止消息泛滥并更有效地管理流量。
-
请求-响应模式: 通过允许客户端发送请求并在不同主题上接收响应来促进异步通信,改善设备间的交互。
-
负载格式指示器和内容类型: 允许客户端指示负载的格式(如JSON、XML)并指定内容类型,增强消息数据的解释和解析。
-
订阅选项: 为客户端提供接收消息方式的额外控制,允许更自定义的订阅行为。 客户端可启用如下特性:Retain As Published(接收带有原始Retain标志的消息)、No Local(避免接收自己发布的消息)、Retain Handling(控制订阅时是否立即投递保留消息)以及Maximum QoS(限制接收消息的QoS级别)。
-
订阅标识符: 允许broker为每个订阅分配唯一标识符,该标识符可包含在PUBLISH报文中以帮助客户端追踪消息对应的订阅。
这些特性共同增强了MQTT5.0在复杂场景(尤其是IoT和企业系统)中的可扩展性、性能、安全性和灵活性。
最佳实践
- 性能优化:
- 减少延迟: 为最小化延迟,确保broker和客户端运行在优化的硬件和网络基础设施上。保持消息体积小并使用适当的QoS级别来平衡可靠性与性能。避免过度使用保留消息,仔细管理主题层级以防止消息泛滥。
- 管理QoS: 根据应用需求使用合适的服务质量(QoS)级别。在大多数场景中,QoS 0(发后即忘)提供最低延迟但不保证投递。QoS 1和QoS 2提供投递保证但引入额外开销,仅在必要时使用。
- 安全考虑:
- 使用TLS/SSL: 始终使用TLS/SSL保护客户端与broker之间的通信。这确保消息被加密,防止数据拦截和未授权访问。
- 认证: 实施强健的认证机制,如用户名/密码、证书或MQTT5.0中的SCRAM等增强认证方法。这防止未授权设备连接到broker。
- 访问控制: 在broker级别实施访问控制,限制客户端可发布或订阅的主题,降低未授权数据访问的风险。
- 可扩展性:
- 水平扩展broker: 为支持拥有大量客户端的大规模系统,通过集群化或使用负载均衡器水平扩展broker。将客户端连接分布到多个broker以高效处理高流量。共享订阅也有助于在客户端之间分配负载。
- 监控和指标: 使用监控工具跟踪broker的性能和健康状况,获取连接数、消息吞吐量和系统资源使用等重要指标。这有助于识别瓶颈和规划扩展。