MQTT笔记
-
- 一、协议版本
- 二、核心概念深入讲解
-
- [1. 会话 Session](#1. 会话 Session)
- [2. Topic 主题规则](#2. Topic 主题规则)
- [3. Retain 保留消息](#3. Retain 保留消息)
- [4. Will 遗嘱消息(Last Will and Testament)](#4. Will 遗嘱消息(Last Will and Testament))
- [5. QoS 再细化](#5. QoS 再细化)
- [三、MQTT 控制报文(一共14种报文)](#三、MQTT 控制报文(一共14种报文))
-
- [心跳 KeepAlive](#心跳 KeepAlive)
- 四、Broker(消息代理)常用开源实现
- [五、MQTT 安全机制](#五、MQTT 安全机制)
- [六、MQTT over WebSocket](#六、MQTT over WebSocket)
- [七、MQTT 优缺点](#七、MQTT 优缺点)
- 八、适用/不适用场景
- [九、简单对比 MQTT vs Kafka vs WebSocket](#九、简单对比 MQTT vs Kafka vs WebSocket)
- [十、MQTT 消息结构(PUBLISH报文)](#十、MQTT 消息结构(PUBLISH报文))
- [十一、MQTT 时序图](#十一、MQTT 时序图)
-
- [QoS2 目的:**保证消息有且仅收到 1 次,不丢、不重复**,一共 4 步:](#QoS2 目的:保证消息有且仅收到 1 次,不丢、不重复,一共 4 步:)
- [心跳 PINGREQ / PINGRESP(KeepAlive 保活)](#心跳 PINGREQ / PINGRESP(KeepAlive 保活))
-
- [1. 两个报文](#1. 两个报文)
- [2. 作用](#2. 作用)
- [3. 重点区分](#3. 重点区分)
一、协议版本
目前主流两个版本:
- MQTT 3.1.1:最广泛,大量物联网设备、开源 broker(Mosquitto)默认支持,稳定够用。
- MQTT 5.0 :增强版,新增大量能力,现在逐步普及:
- 支持共享订阅(多个客户端分摊同一个主题消息,负载均衡)
- 消息与订阅携带原因码,方便排查失败原因
- 主题别名,减少报文体积
- 支持用户属性(自定义KV附加在消息里)
- 更好的错误反馈、流量控制、会话管理
选型建议:新项目优先考虑MQTT5;老旧嵌入式设备很多只能跑3.1.1。
二、核心概念深入讲解
1. 会话 Session
客户端连接 Broker 时可以指定 Clean Session(清除会话)
- CleanSession = true(MQTT3.1.1) / Clean Start = true(MQTT5)
连接成功后,断开连接就清空会话:订阅关系、未接收消息全部丢弃。临时客户端常用(手机APP临时查看数据)。 - CleanSession = false / Clean Start = false
Broker保存会话:客户端掉线后,订阅关系保留;QoS1/QoS2未送达消息会缓存。设备重连后,自动补发离线期间消息。适合传感器这类持续在线设备。
缓存消息有上限,Broker一般会设置最大缓存数量,超出会丢弃。
2. Topic 主题规则
- 层级分隔符:
/,例如device/001/temp - 通配符 (只能用在订阅,发布消息不能带通配符)
+:单层通配符。sensor/+/temp匹配sensor/room1/temp、sensor/room2/temp;不能跨层级#:多层通配符,必须放在主题末尾。sensor/room1/#匹配sensor/room1/temp、sensor/room1/hum
示例:
主题:
factory/workshop1/machine01/temp
factory/+/machine01/temp✔ 匹配
factory/#✔ 匹配
factory/#/temp❌ 错误,#只能在最后
3. Retain 保留消息
发布消息时设置 retain=true:
Broker保存这个主题最新一条消息 。
新客户端订阅该主题瞬间,Broker立刻把这条保留消息推送给新订阅者。
场景:上报设备当前状态。比如温度传感器,新APP订阅后马上拿到当前温度,不用等传感器下一次上报。
清除保留消息:向该主题发送一条 payload 为空、retain=true 的消息。
4. Will 遗嘱消息(Last Will and Testament)
客户端连接Broker的时候,预先告诉Broker:
如果我非正常断开(断网、断电、程序崩溃,没有发送正常DISCONNECT包),请帮我向指定主题发送遗嘱消息。
正常调用断开指令DISCONNECT,遗嘱消息不会发送。
场景:设备离线告警。设备掉线,其他订阅端立刻收到
device/001/status= offline。
5. QoS 再细化
QoS 是发布者和Broker之间 的保障,不是端到端!
例如:发布QoS1,订阅QoS0 → Broker收到消息后,发给订阅者就是QoS0。
- QoS 0:最多一次
PUBLISH报文直接发出,无应答。丢包就丢失。开销最小。适合高频非关键数据(温度实时流,丢一条无所谓)。 - QoS 1:至少一次
流程:PUBLISH → 收到PUBACK才算成功。没收到ACK就重发。
缺点:消息可能重复到达,业务层需要做去重。适合状态上报,允许重复。 - QoS 2:恰好一次
四次握手:PUBLISH → PUBREC → PUBREL → PUBCOMP。
保证消息只送达一次。开销最大。适合支付、开关指令这类不能丢、不能重复的场景。
三、MQTT 控制报文(一共14种报文)
MQTT通信全部由固定格式报文组成,常见:
- CONNECT:客户端发起连接
- CONNACK:Broker响应连接结果
- SUBSCRIBE:客户端订阅主题
- SUBACK:订阅应答
- PUBLISH:收发消息主体报文
- PUBACK / PUBREC / PUBREL / PUBCOMP:QoS应答报文
- UNSUBSCRIBE:取消订阅
- UNSUBACK:取消订阅应答
- PINGREQ:心跳请求(客户端保活)
- PINGRESP:心跳响应
- DISCONNECT:客户端正常断开
心跳 KeepAlive
CONNECT的时候设置KeepAlive时间(秒)。
含义:客户端必须在这个时间间隔内至少发一次PINGREQ,证明在线。
如果Broker超过1.5倍KeepAlive时间没收到客户端任何数据 → 判断客户端掉线,触发遗嘱消息。
嵌入式设备常用:KeepAlive=60s。
四、Broker(消息代理)常用开源实现
- Eclipse Mosquitto:轻量、简单,MQTT3.1.1/5支持,最常用,适合测试、中小型项目。
- EMQX:高性能,百万级连接,MQTT5完善,支持集群、共享订阅、规则引擎,工业/云平台常用。
- VerneMQ:高并发集群Broker。
五、MQTT 安全机制
- 用户名密码认证:CONNECT包携带username/password,最简单。
- TLS/SSL加密:MQTT over TLS(端口8883),传输内容加密,防止抓包窃听;MQTT默认1883明文。
- 证书认证(x509):客户端证书,比账号密码更安全,设备场景首选。
- 权限控制 ACL:Broker配置,控制客户端只能订阅/发布指定主题(例如设备只能发布自己id的主题,不能读其他设备)。
六、MQTT over WebSocket
端口一般 8083。
把MQTT包封装在WebSocket里,浏览器前端JS直接连接MQTT broker,不用后端中转。网页控制台实时看传感器数据常用。
七、MQTT 优缺点
✅ 优点
- 报文极小,网络开销低,适合低带宽、4G/窄带物联网NB-IoT
- Pub/Sub解耦,设备不用关心对方IP地址
- 长连接,消息实时推送
- 丰富特性:遗嘱、保留消息、QoS,适配物联网设备不稳定网络
- 跨平台,几乎所有单片机、嵌入式、编程语言都有SDK
❌ 缺点
- 依赖Broker,Broker是单点(可以集群解决)
- 不适合超大文件传输(设计初衷是短消息,payload最大理论上限256MB,但一般业务只传几十~几百字节)
- QoS不能跨Broker保证,分布式场景要业务层兜底
- 消息没有内置持久化(Broker可以配置持久化,不是协议强制)
八、适用/不适用场景
✅ 适合:
- 物联网传感器、智能硬件上报数据
- 设备远程下发控制指令
- 实时状态推送、设备上下线告警
- NB-IoT、4G模组低功耗设备
❌ 不适合:
- 大文件上传下载(视频流一般不用原生MQTT)
- 复杂事务消息(kafka更适合大数据流)
- 一次性短请求(HTTP更简单)
九、简单对比 MQTT vs Kafka vs WebSocket
- MQTT:物联网,海量低算力设备,小消息,Pub/Sub,支持QoS/遗嘱。
- Kafka:大数据日志流,高吞吐,消息持久化,适合后端数据分析,不适合嵌入式设备。
- 原生WebSocket:浏览器双向通信,没有主题、QoS、遗嘱这些能力,只是单纯双向通道。MQTT over WebSocket是在WebSocket之上跑MQTT协议。
十、MQTT 消息结构(PUBLISH报文)
报文分为两部分:固定头 + 可变头 + 载荷payload
- 固定头:控制报文类型、QoS、retain等标记
- 可变头:主题名,QoS1/2带报文ID;MQTT5可带用户属性
- payload:消息内容,二进制字节流,MQTT不关心里面是JSON、文本、二进制,业务自己解析。
习惯:物联网消息大多用JSON,方便调试。
十一、MQTT 时序图

QoS2 目的:保证消息有且仅收到 1 次,不丢、不重复,一共 4 步:
- PUBLISH:发布端 → Broker:发送消息
- PUBREC:Broker → 发布端:已收到消息(收到这一步,Broker 就不会再接收这条消息的重复 PUBLISH)
- PUBREL(Release,释放消息) :发布端 → Broker:我确认收到 PUBREC 了,现在允许 Broker 把这条消息转发出去
- PUBCOMP(Complete,发布完成):Broker → 发布端:消息转发流程全部结束,这条报文 ID 可以释放
简单一句话理解这两个报文:
PUBREL = "我确认你收到消息了,可以把消息发出去了"
PUBCOMP = "全部搞定,这条消息事务结束"
这 4 个报文(PUBLISH-PUBREC-PUBREL-PUBCOMP)就是 QoS2 的四次握手。
心跳 PINGREQ / PINGRESP(KeepAlive 保活)
1. 两个报文
- PINGREQ :Ping Request,心跳请求(客户端发给 Broker)
- PINGRESP :Ping Response,心跳响应(Broker 回复客户端)
2. 作用
MQTT 是长连接 ,但是网络中间设备(路由器 / 防火墙)会自动删掉长时间没有数据的空闲 TCP 连接。
所以客户端必须定时发心跳包,告诉 Broker:我还在线!
工作规则
- 客户端 CONNECT 连接 Broker 的时候,会填写
KeepAlive(保活时间,单位秒,比如 60s) - 规则:客户端必须在 KeepAlive 时间内,至少发一次 PINGREQ
- Broker 判断掉线:超过 1.5 × KeepAlive 的时间,没有收到客户端任何数据(PINGREQ 或者消息)
→ Broker 判定客户端异常掉线(断网 / 断电 / 程序崩溃) ,触发遗嘱消息 Will
举例子:KeepAlive=60 秒
客户端每 50s 发送一次 PINGREQ(心跳请求)
Broker 收到,回复 PINGRESP(心跳响应)
如果断网,Broker 等 90s(1.5*60)还没收到任何包 → 判断离线,推送遗嘱消息。
3. 重点区分
✅ 正常下线:客户端主动发送DISCONNECT,Broker 直接知道离线,不触发遗嘱
❌ 异常掉线:没发 DISCONNECT,Broker 靠心跳超时判断离线,触发遗嘱消息