2、MQTT协议基础:发布/订阅模型、主题与通配符、服务质量详解

好,咱们今天来聊聊MQTT。这玩意儿在物联网里,可以说是“标配”级别的协议了。我最早接触它,是在一个智能路灯的项目里。当时设备多,网络又不稳定,用HTTP轮询?那简直是灾难。后来换成了MQTT,整个世界都清净了。

说白了,MQTT就是一个轻量级的消息协议。它专门为“小设备”和“烂网络”设计的。你想想看,一个传感器可能只有几KB的内存,网络还动不动断一下,这时候MQTT的优势就体现出来了。

2.1 发布/订阅模型:告别“点对点”

传统的HTTP通信,是“客户端-服务器”模式。客户端请求,服务器响应。这就像你打电话,必须知道对方号码,还得等对方接。

MQTT不一样。它用的是发布/订阅模型。这里有个中间人,叫Broker(代理服务器)。

  • 发布者(Publisher):只管把消息扔给Broker。它不需要知道谁会收到。
  • 订阅者(Subscriber):告诉Broker,我对哪些消息感兴趣。然后等着收就行了。
  • 代理(Broker):核心角色。负责接收发布者的消息,再转发给所有感兴趣的订阅者。

这个模型的好处是什么?解耦。发布者和订阅者互不认识,也不需要同时在线。我在项目中就遇到过这种情况:一个温度传感器在户外,网络时好时坏。它只管上报数据,哪怕Broker当时没收到,等网络恢复了,数据还能补上来。订阅者(比如后台服务器)也不用一直盯着传感器,它只需要订阅“温度”这个主题,数据自然就来了。

核心思想: 发布者不关心谁在收,订阅者不关心谁在发。一切由Broker调度。

2.2 主题(Topic)与通配符:消息的“地址”

Broker怎么知道把消息发给谁?靠的就是主题(Topic)

主题就是一个字符串,用来对消息进行分类。它用“/”分层,很像文件路径。比如:

sensor/temperature/room1
sensor/humidity/room2
device/light/status

发布者发消息时,必须指定一个主题。订阅者订阅时,也是指定一个主题。只有主题匹配上了,消息才能送达。

这里有个关键点:通配符。它让订阅变得非常灵活。

  • 单层通配符 +:匹配一层。比如订阅 sensor/+/room1,就能收到 sensor/temperature/room1sensor/humidity/room1,但收不到 sensor/temperature/room1/extra
  • 多层通配符 #:匹配剩余所有层。比如订阅 sensor/#,就能收到所有以 sensor/ 开头的消息。

我的习惯: 在设计主题时,尽量用有意义的层级。比如 项目/设备类型/设备ID/数据点。这样后期用通配符做批量管理会非常方便。

我曾经在一个项目中,因为主题设计得不好,导致订阅逻辑变得极其复杂。后来重构了一次,把主题按“地理位置-设备类型-功能”分层,整个系统清晰多了。

注意: 通配符只能用在订阅端,不能用在发布端。发布者必须指定一个具体的、不含通配符的主题。

2.3 服务质量(QoS 0/1/2):消息能“必达”吗?

物联网网络不稳定,消息丢了怎么办?MQTT提供了三个级别的服务质量(Quality of Service,QoS),让你在“效率”和“可靠性”之间做选择。

QoS级别 含义 可靠性 性能开销 典型场景
QoS 0 最多发一次(At most once) 最低,可能丢 最低 传感器定期上报,丢一两次无所谓
QoS 1 至少发一次(At least once) 中等,不会丢,但可能重复 中等 控制指令,必须到达,但允许重复执行
QoS 2 恰好发一次(Exactly once) 最高,不丢不重 最高 计费、支付等关键业务

QoS 0:说白了就是“发完就不管了”。Broker收到消息后,不会给发布者任何确认。性能最好,但消息可能丢失。我一般用它来上报环境温度、湿度这类数据,丢个一两次不影响大局。

QoS 1:发布者发完消息后,会等Broker回复一个PUBACK包。如果没收到,发布者会重发。这就保证了消息至少被Broker收到一次。但问题来了:Broker可能收到了消息,但PUBACK包在回传时丢了。这时候发布者会重发,导致Broker收到两条相同的消息。所以,订阅者可能会收到重复消息。

QoS 2:这是最严格的。它通过一个四次握手协议(PUBLISH -> PUBREC -> PUBREL -> PUBCOMP),确保消息恰好被Broker接收一次。开销最大,但最可靠。我记得在一个智能门锁的项目里,开锁指令必须用QoS 2。万一重复执行了,门开了又关,那用户体验就太差了。

避坑指南: 我曾经在一个项目中,所有消息都用了QoS 2,结果设备多了之后,Broker负载飙升,消息处理变慢。后来分析发现,大部分传感器数据根本不需要这么高的可靠性。所以,按需选择QoS,别一刀切。

嗯,这里要注意一点:QoS是发布者到Broker以及Broker到订阅者这两个环节独立协商的。发布者可以用QoS 1发消息,但订阅者可以用QoS 0来接收。最终订阅者实际收到的服务质量,是两者中较低的那个。

好了,MQTT的基础就这些。发布/订阅模型让你解耦,主题和通配符让你灵活订阅,QoS让你在可靠性和性能之间找到平衡。下一节,我们聊聊怎么在实际代码里用起来。