MQTT 是什么、什么时候用、有什么坑?一个后端开发的实践总结

从一个项目踩坑开始,讲清楚 MQTT 协议的核心模型、适用场景、QoS 选择、会话管理、Topic 设计和 Broker 选型。

第一次碰到 MQTT

几年前做一个小型的物流追踪系统,后端从几十台车载终端收 GPS 数据。最开始的方案拍脑袋就定了——HTTP 长轮询。结果上线第一天,几十个终端同时上报,服务器 CPU 直接飙满,数据库连接被吃光,整个系统瘫了将近一小时。

那是我第一次认真研究 MQTT。后来发现这东西就是为这类场景设计的,早该用。做技术的回头看,很多所谓的”架构问题”,本质上是选错了通信协议。

MQTT 到底是什么

MQTT(Message Queuing Telemetry Transport)是一个轻量级发布/订阅消息协议,最早是 IBM 在 90 年代末为石油管道监控开发的。它的设计目标很明确:用最少的带宽和电量,在不可靠的网络下把消息送到。

核心模型就三个角色:

  • Broker(代理服务器)——消息的中转站。所有的消息都经过 Broker,它负责收、维护订阅关系、推。
  • Publisher(发布者)——发消息的一方。把消息发到一个”主题”(topic)上,无需关心谁在收。
  • Subscriber(订阅者)——收消息的一方。告诉 Broker 自己对哪些主题感兴趣,有消息来了 Broker 推给它。

这和传统的客户端-服务器模式完全是两回事。HTTP 是”客户端请求,服务器响应”——你必须主动去问,答案才来。MQTT 是”你说你要,有就给你”——你登录 Broker 的时候说”我要收 topic A”,以后 A 上有消息,Broker 主动推送给你,你躺着就行。

Topic 用斜杠分层的格式表示,比如 sensor/temperature/room1,支持通配符 +(单层)和 #(多层),非常灵活。

什么时候应该用 MQTT

不是所有场景都适合 MQTT,但它特别适合下面几类:

1. 设备多、带宽窄、网络不稳定

典型的物联网场景。一个温湿度传感器可能每隔几分钟才上报一次数据,用 HTTP 每次都要建立连接、协商 TLS、发完再断开。MQTT 用一条长连接搞定,报文头部最小只有 2 个字节。同样是发送一条数据,HTTP 可能用掉几 KB,MQTT 几十个字节就够。

物流追踪、智能抄表、农业大棚监控、共享单车……这些场景的核心诉求是:终端电池能用多久、信号不好时数据不能丢。MQTT 的 QoS 机制和 Keep Alive 就是为这个设计的。

2. 需要实时推送,不想轮询

IM 消息、App 通知、股票行情、实时仪表盘。HTTP 轮询效率太低了,WebSocket 虽然能推但实现成本偏高。MQTT 夹在中间正好——轻量、双向推、生态成熟。

3. 一对多分发

一条命令发给一千台设备,或者一个传感器的数据要同时推给三个后端服务和两个仪表盘。MQTT 的发布/订阅模型天然支持这个场景,Broker 帮你做分发,发布者和订阅者完全解耦。

什么时候不要用 MQTT

MQTT 不是万能药。下面的场景它就不太合适:

  • 请求-响应式强交互——比如用户登录、数据查询。HTTP 的 request-response 模型跟人脑的交互逻辑一致,MQTT 要做 RPC 虽然可以(用 request/response pattern),但绕了一圈不自然。
  • 大文件传输——MQTT 不会帮你切分和重传大文件,协议本身设计就是轻量消息。传图片视频,用 HTTP multipart 或者专门的传输协议。
  • 浏览器直连——虽然 MQTT over WebSocket 可以解决,但相比直接 WebSocket,多了一层协议转换的负担。前端在浏览器里直接用 WebSocket 往往更简单。

使用 MQTT 必须注意的地方

MQTT 看起来规简单——连上 Broker,订阅 topic,收消息。但实际项目里踩过的坑不少。

QoS 别乱选

MQTT 有三个 QoS 级别:

  • QoS 0(至多一次)——发了就不管。不确认、不重发。最快,但可能丢消息。适合传感器周期性上报——丢一个下次还有。
  • QoS 1(至少一次)——发一条等一个 PUBACK,超时重发。有可能重复收到同一条消息。适合上下线通知、报警。
  • QoS 2(恰好一次)——四次握手确保不丢不重。最慢,开销也最大。适合支付、订单等对幂等性要求极高的场景。

选 QoS 2 之前先问自己一句:你的应用真的需要吗?大部分物联网场景,接收端自己做好去重(比如用消息 ID),QoS 1 就足够。盲目用 QoS 2 只会让你的 Broker 负载变大,网络延迟升高。

Clean Session 和持久会话

客户端断线后重新连接,之前订阅的 topic 还在不在?不在线期间错过的重要消息还能不能收到?

  • Clean Session = true:每次连接都是全新的,断线后 Broker 清空所有订阅和未发送的消息。
  • Clean Session = false:Broker 保存客户端的会话状态,包括订阅关系和离线期间 QoS 1/2 的未确认消息。重连后恢复。

终端设备如果只做上报(不关心离线消息),Clean Session 设 true。后端服务建议设 false,防止重启后收不到离线期间的关键消息。

Will Message(遗嘱)是个容易被忽略的好东西

设备突然掉线(比如断电、断网),Broker 能不能通知别的服务?MQTT 的 Will Message 就在连接的时候设置好。设备连接时带上一个”如果我挂了,发这条信息到某个 topic”。Broker 检测到非正常断开时,自动发布遗嘱消息。

场景举例:共享单车断连了,后端收到遗嘱消息就知道这辆车可能出问题了。再比如,告警系统里一个代理挂了,其他代理收到遗嘱消息可以立即接手。

Topic 设计得提前想好

Topic 不是随便起的。一个好的 topic 结构会让你少很多麻烦:

  • 不要用中文,不要用空格
  • 按范围从大到小组织,比如 factory/line01/machine03/temperature
  • 通配符 +# 用得多了会影响性能,尤其是大规模订阅场景
  • 系统级 topic 加前缀 $SYS/ 避免跟业务 topic 撞名

认证和加密不能省

MQTT 默认不加密。你在公网上跑裸 MQTT,报文可以被随便抓包看到。上线前想清楚:

  • 生产环境一律上 TLS(mqtts://),用户名/密码是基础认证
  • 设备多的话建议上证书认证(X.509),每个设备唯一证书
  • Broker 侧做好 ACL(访问控制列表),不让设备订阅或发布非授权的 topic

Broker 的选型

几个主流 Broker 各有侧重:

  • Mosquitto——最轻量。适合单机部署、边缘网关、嵌入式环境。C 语言实现,内存占用很低。
  • EMQX——国产开源,目前物联网领域最活跃的 Broker 之一。原生集群、热升级、规则引擎,适合大规模生产部署。
  • NanoMQ——超轻量,针对边缘和嵌入式场景。性能和资源占用比 Mosquitto 还极致。
  • HiveMQ——企业级,Java 实现,强在集群和扩展,贵。

一个小例子

用 mqtt.js 在 Node.js 客户端订阅和发布:

const mqtt = require("mqtt");

// 连接 Broker
const client = mqtt.connect("mqtts://broker.example.com:8883", {
  username: "device01",
  password: "****",
  clientId: "device_01_" + Math.random().toString(16).slice(2, 8),
  clean: true,
});

client.on("connect", () => {
  console.log("connected");

  // 订阅温度 topic
  client.subscribe("sensor/temperature/#", { qos: 1 });

  // 发布一条消息
  client.publish("sensor/temperature/room1", JSON.stringify({ value: 25.3 }), {
    qos: 1,
  });
});

client.on("message", (topic, payload) => {
  console.log(`收到 [${topic}]: ${payload.toString()}`);
});

client.on("close", () => {
  console.log("disconnected");
});

总结

  1. MQTT 是为弱网络、低带宽、大批设备设计的协议,发布/订阅模型天然解耦。
  2. 选对场景用:物联网推送、实时仪表盘、一对多分发是它的强项。请求响应式交互请留给 HTTP。
  3. QoS 按需选:大部分情况下 QoS 1 够用,加上业务层去重,没必要无脑上 QoS 2。
  4. 安全不偷懒:TLS 加密、认证鉴权、ACL 是生产环境标配,缺一个都可能在安全上翻车。
  5. Topic 结构提前规划:上线之后改 topic 结构非常痛苦,先想好分层再动手。

MQTT 不是新技术,但它解决了一个很实在的问题:在带宽窄、设备多、网络差的条件下,怎么让消息可靠地流通。如果你正在做物联网或者实时推送类项目,花一天时间把 MQTT 的细节吃透,回报远比表面看起来的大。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注