HTTP 已经统治互联网几十年,为什么到了物联网领域,我们却经常看到 MQTT?

ESP32、STM32、树莓派、智能家居、工业设备、传感器、网关为什么喜欢 MQTT?

MQTT 到底比 HTTP 好在哪里?

HTTP 能不能做物联网?

MQTT 为什么要设计 Publisher、Subscriber、Broker、Topic、QoS?

本文不从“MQTT 是一种轻量级协议”这种定义开始,而是从一个最根本的问题开始:

如果我们有 10 万个物联网设备,到底应该怎么让它们和服务器通信?


一、先说结论:物联网不是“不用 HTTP”,而是很多场景下 MQTT 更合适

首先纠正一个非常容易产生的误解:

物联网并不是不能使用 HTTP。

事实上,HTTP 在物联网中依然大量存在。

例如:

设备
  ↓ HTTP POST
服务器

完全可以。

ESP32 也可以:

HTTPClient http;

http.begin("https://example.com/api/device/data");

http.addHeader("Content-Type", "application/json");

int code = http.POST(
    "{\"temperature\":25.6}"
);

服务器同样可以接收:

POST /api/device/data HTTP/1.1
Content-Type: application/json

{
    "temperature": 25.6
}

所以问题并不是:

HTTP 能不能做 IoT?

答案是:

当然可以。

真正的问题是:

当设备数量变多、设备需要持续在线、数据需要实时上报、服务器需要主动下发命令、网络不稳定、设备资源有限的时候,HTTP 还是不是最合适的通信模型?

这时候 MQTT 的优势就开始出现了。


二、先从一个最简单的物联网场景开始

假设我们现在有一个温度传感器。

每 5 秒读取一次温度:

25.1℃
25.2℃
25.3℃
25.4℃
25.2℃
...

我们的目标是:

ESP32
   ↓
服务器
   ↓
数据库
   ↓
Web 管理后台

看起来非常简单。

我们甚至可以直接设计一个 HTTP API:

POST /api/device/temperature

请求:

{
    "deviceId": "ESP32-001",
    "temperature": 25.3,
    "timestamp": 1778500000000
}

服务器:

@PostMapping("/api/device/temperature")
public void report(@RequestBody TemperatureReport request) {

    System.out.println(
        "设备:" + request.getDeviceId()
        + " 温度:" + request.getTemperature()
    );
}

这完全没有问题。

那么为什么还需要 MQTT?

答案就藏在一个问题里面:

服务器怎么主动告诉 ESP32?


三、HTTP 最大的问题:它天然是 Request / Response 模型

HTTP 的核心通信模式是:

Client
   |
   | Request
   v
Server
   |
   | Response
   v
Client

IETF 的 HTTP 标准 RFC 9110 对 HTTP 的定义就是:

HTTP 是一种无状态的 request/response 协议。

HTTP 的基本模型就是:

客户端发送 Request
        ↓
服务器处理
        ↓
服务器返回 Response

RFC 9110 明确规定了 HTTP 的请求与响应语义:客户端发送 request,服务器处理后返回 response。

在这里插入图片描述


四、问题来了:服务器想主动控制设备怎么办?

假设现在有一个智能灯。

设备:

ESP32

服务器:

Java
Spring Boot

我们希望:

用户点击后台按钮
        ↓
服务器
        ↓
关闭灯
        ↓
ESP32

但是 HTTP 的天然模型是:

客户端 → 请求 → 服务器
服务器 → 响应 → 客户端

服务器并不能简单地:

Server
   ↓
HTTP POST
   ↓
ESP32

因为普通 HTTP 场景下,设备通常是 HTTP Server 的客户端,而不是一个等待服务器请求的 HTTP 服务端。

当然,我们可以让 ESP32 开放 HTTP Server:

ESP32 : 8080

然后:

Java Server
     ↓
HTTP POST
     ↓
ESP32

但现实中的 IoT 设备通常处于:

家庭路由器
    ↓
NAT
    ↓
互联网

设备往往没有一个公网 IP。

于是服务器很难直接找到设备。


五、有人可能会说:那就让设备一直轮询 HTTP

这是最经典的解决方案。

设备:

每 1 秒:

GET /api/device/command

服务器:

{
    "command": null
}

过 1 秒:

GET /api/device/command

服务器:

{
    "command": null
}

又过 1 秒:

GET /api/device/command

服务器:

{
    "command": null
}

直到某一次:

{
    "command": "LIGHT_OFF"
}

设备终于收到:

关闭灯

看起来解决了。

但是问题也来了。


六、HTTP 轮询到底浪费在哪里?

假设:

10000 台设备

每台设备:

每 1 秒请求一次

那么:

10000 × 60 × 60

一个小时就是:

36,000,000

次 HTTP 请求。

一天:

864,000,000

次请求。

关键是:

绝大部分请求其实没有数据。

例如:

设备 001 → 有命令吗?没有。
设备 002 → 有命令吗?没有。
设备 003 → 有命令吗?没有。
设备 004 → 有命令吗?没有。
...

这是一种非常典型的:

无效轮询。


七、HTTP 的设计目标和 IoT 的需求,本来就不完全一样

HTTP 是为了 Web 世界发展起来的。

它非常擅长:

浏览网页
REST API
文件传输
Web 服务
资源获取
前后端通信

例如:

GET /api/products

非常合理。

客户端说:

我要商品。

服务器:

给你商品。

但是 IoT 很多时候不是这种模式。

IoT 更像:

设备:
我刚刚测到了 25.6℃。

然后:

服务器:
收到。

同时服务器可能突然说:

服务器:
把继电器打开。

设备:

收到。

甚至还有:

设备 A
设备 B
设备 C
设备 D

全部都需要接收:

topic = building/1/floor/2/light

这样的消息。

这已经不是单纯的:

Request → Response

问题了。


八、MQTT 的核心思想:不要让设备一直问“有没有消息”

MQTT 换了一种思路。

不是:

设备:
服务器,有消息吗?

服务器:
没有。

设备:
服务器,有消息吗?

服务器:
没有。

设备:
服务器,有消息吗?

服务器:
没有。

而是:

设备:
我订阅这个主题。

服务器:
好的。

...

服务器有消息:

服务器
  ↓
Broker
  ↓
设备

这就是 MQTT 最核心的:

Publish / Subscribe

也就是:

发布 / 订阅模型。

OASIS 的 MQTT 5.0 标准明确将 MQTT 定义为:

Client Server publish/subscribe messaging transport protocol

并明确指出,发布/订阅模式可以实现一对多消息分发和应用之间的解耦。


九、MQTT 到底有几个角色?

MQTT 最重要的三个概念:

Publisher
Subscriber
Broker

中文:

发布者
订阅者
消息代理

例如:

温度传感器
      ↓
Publisher
      ↓
    MQTT
      ↓
   Broker
      ↓
Subscriber
      ↓
Java服务器

或者:

Java服务器
    ↓
Publisher
    ↓
 MQTT Broker
    ↓
Subscriber
    ↓
ESP32

十、什么是 Broker?

Broker 可以理解成:

MQTT 世界里的消息中转站。

例如:

ESP32
  ↓
发布消息
  ↓
┌──────────────┐
│ MQTT Broker  │
└──────────────┘
  ↓
订阅者

常见的 Broker:

EMQX
Mosquitto
HiveMQ
VerneMQ

Broker 负责:

连接管理
消息接收
Topic 路由
订阅管理
QoS 处理
会话管理
权限控制

因此 MQTT 的通信模型从:

Device → Server

变成:

Device → Broker → Subscriber

十一、这时候一个非常重要的问题来了:为什么不直接设备连服务器?

因为 MQTT 最重要的一个设计思想就是:

解耦。

假设有:

10000 个设备

如果全部直接连接业务服务器:

ESP32-001 ─┐
ESP32-002 ─┤
ESP32-003 ─┤
ESP32-004 ─┤
...        ├── Java Server
ESP32-9999 ┤
ESP32-10000┘

那么业务服务器需要负责:

设备连接
认证
心跳
消息
离线
重连
路由

业务系统会越来越复杂。

而 MQTT:

                    ┌── Device
                    │
                    ├── Device
Device ── Broker ───┼── Device
                    │
                    ├── Java
                    │
                    └── Web

Broker 专门负责:

消息通信。

业务服务器专门负责:

业务逻辑。

这就是解耦。


十二、Topic:MQTT 最重要的设计之一

MQTT 不直接把消息发送给:

deviceId

而是发送到:

Topic

例如:

home/livingroom/temperature

设备发布:

Topic:
home/livingroom/temperature

Payload:
25.6

另一个客户端订阅:

home/livingroom/temperature

就可以收到:

25.6

十三、Topic 到底是什么?

可以把 Topic 理解成:

消息频道。

例如:

home/livingroom/temperature

可以拆成:

home
 └── livingroom
      └── temperature

再比如:

device/001/status
device/001/temperature
device/001/humidity
device/001/command

我们甚至可以设计成:

iot/
 ├── device/
 │    ├── 001/
 │    │    ├── status
 │    │    ├── telemetry
 │    │    └── command
 │    │
 │    └── 002/
 │         ├── status
 │         ├── telemetry
 │         └── command

这样整个物联网系统就有了一个非常清晰的消息命名空间。


十四、MQTT 的通配符非常适合 IoT

MQTT 支持 Topic Filter。

例如:

device/+/temperature

其中:

+

表示单层通配符。

因此:

device/001/temperature
device/002/temperature
device/003/temperature

都可以匹配。

还有:

#

多层通配符。

例如:

device/#

可以匹配:

device/001/status
device/001/temperature
device/002/status
device/002/temperature

MQTT 5.0 标准明确规定了 Topic Filter 和通配符订阅机制。


十五、一个非常经典的 MQTT 场景

假设:

1000 个温度传感器

全部发布:

building/1/temperature/{deviceId}

例如:

building/1/temperature/001
building/1/temperature/002
building/1/temperature/003

现在:

Java服务器

订阅:

building/1/temperature/#

那么所有温度数据都可以进入 Java 服务。

与此同时:

数据分析服务

也可以订阅:

building/1/temperature/#

而:

监控系统

也可以订阅:

building/1/temperature/#

于是:

              ┌── Java
              │
Sensor ─ Broker ─ Analytics
              │
              └── Monitoring

发布者完全不需要知道:

Java 在哪里
Analytics 在哪里
Monitoring 在哪里

这就是:

发布者和消费者解耦。


十六、HTTP 和 MQTT 最核心的区别

现在可以正式比较两者。

对比项HTTPMQTT
通信模型Request / ResponsePublish / Subscribe
中间代理可有可无Broker 是核心
消息方向典型为客户端请求双向消息
一对多需要额外设计天然支持
Topic没有核心机制
QoS不提供 MQTT 那种消息级 QoSQoS 0/1/2
Retain无原生对应机制支持
Will无原生对应机制支持
IoT 设备通信可以非常适合
Web API非常适合通常不如 HTTP
浏览器原生支持通常通过 WebSocket
典型用途REST API/WebIoT/M2M/实时消息

HTTP 的标准模型是无状态的 Request/Response;MQTT 则以 Publish/Subscribe 为核心,并提供 QoS、Retain、Session 等针对消息通信设计的机制。


十七、为什么 MQTT 特别适合弱网环境?

物联网和互联网应用有一个非常明显的区别:

服务器通常:

CPU 很强
内存很多
网络稳定
电源稳定

但是设备可能:

ESP32
STM32
传感器
4G 模块
NB-IoT
Wi-Fi
电池供电
低功耗

设备可能:

掉线
断网
网络抖动
信号弱
带宽低

因此 IoT 协议必须考虑:

设备可能随时断开。

MQTT 从设计上就考虑了这种场景。

OASIS 标准明确指出,MQTT 设计目标包括资源受限环境和网络带宽受限的 M2M/IoT 场景。


十八、MQTT 为什么叫 Lightweight?

MQTT 的一个重要定位就是:

轻量级。

注意:

“轻量级”不是说 MQTT 完全没有协议头。

而是:

相比很多面向通用 Web 的通信协议,MQTT 的协议模型和控制报文更加针对消息传输场景。

MQTT 的固定头部非常紧凑。

例如 MQTT PUBLISH 报文的固定头中包含:

DUP
QoS
RETAIN
Remaining Length

OASIS MQTT 5.0 标准详细规定了 MQTT Control Packet 的结构以及 PUBLISH、SUBSCRIBE 等报文。


十九、QoS:MQTT 最重要的能力之一

如果你真正学习 MQTT,一定绕不开:

QoS

QoS:

Quality of Service

MQTT 定义了三个等级:

QoS 0
QoS 1
QoS 2

分别对应:

QoS 0
最多一次

QoS 1
至少一次

QoS 2
恰好一次

OASIS MQTT 5.0 标准明确规定了这三个 QoS 等级。


二十、QoS 0:At Most Once

QoS 0:

最多一次

发送:

Publisher
   |
   | PUBLISH
   ↓
Broker

没有:

PUBACK

也不会进行 MQTT 层面的重试。

因此:

可能收到
也可能丢失

适合:

实时温度
实时湿度
实时空气质量
实时位置

例如:

25.1℃
25.2℃
25.3℃

如果:

25.2℃

丢了一条。

问题不大。

因为:

25.3℃

马上又来了。

MQTT 标准甚至以环境传感器数据作为 QoS 0 的典型适用场景。


二十一、QoS 1:At Least Once

QoS 1:

至少一次

流程:

Publisher
    |
    | PUBLISH
    ↓
Broker
    |
    | PUBACK
    ↓
Publisher

如果没有收到:

PUBACK

发送方可能重新发送。

因此:

消息至少送到一次。

但是:

可能重复。

例如:

服务器收到:

订单支付成功

因为 ACK 丢失。

设备重新发送:

订单支付成功

服务器可能收到两次。

所以 QoS 1 的业务代码必须考虑:

幂等性。

例如:

if (alreadyProcessed(messageId)) {
    return;
}

process(message);

markProcessed(messageId);

二十二、QoS 2:Exactly Once

QoS 2:

恰好一次

这是最高级别的 MQTT QoS。

它会进行更加完整的握手:

PUBLISH
   ↓
PUBREC
   ↓
PUBREL
   ↓
PUBCOMP

也就是:

Publisher
    |
    | PUBLISH
    ↓
Broker
    |
    | PUBREC
    ↓
Publisher
    |
    | PUBREL
    ↓
Broker
    |
    | PUBCOMP
    ↓
Publisher

因此 QoS 2 的协议开销更大。

OASIS 标准明确说明 QoS 2 用于既不能丢失也不能接受重复的消息,但其开销高于 QoS 0/1。


二十三、千万不要认为 QoS 2 就等于“业务绝对不会重复”

这是学习 MQTT 时非常重要的一个细节。

MQTT 的:

Exactly Once

是:

MQTT 消息传递语义层面的 Exactly Once。

并不自动意味着:

数据库业务
支付业务
订单业务

就一定不会重复。

例如:

MQTT
 ↓
Java
 ↓
MySQL

即使 MQTT 消息只交付一次。

你的 Java 程序仍然可能:

消费成功
 ↓
数据库提交成功
 ↓
程序崩溃
 ↓
业务状态没有正确记录

因此生产系统仍然需要:

幂等
事务
消息 ID
唯一约束
状态机

二十四、MQTT Retain:为什么新上线的设备也能马上知道状态?

这是 MQTT 非常有意思的一个能力。

假设:

Topic:

home/livingroom/light/status

当前灯是:

ON

设备发布:

ON

并设置:

RETAIN = true

Broker 会保存这个 Topic 的最后一条 retained message。

此时:

一个新的客户端

刚刚订阅:

home/livingroom/light/status

Broker 就可以把之前保存的:

ON

立即发给它。


二十五、Retain 到底解决什么问题?

没有 Retain:

设备:
我现在 ON。

↓

客户端当时没在线

↓

客户端后来上线

↓

不知道当前状态

有 Retain:

设备:
ON
 ↓
Broker 保存
 ↓
客户端后来上线
 ↓
Subscribe
 ↓
Broker 立即发送 ON

这特别适合:

设备在线状态
开关状态
温度当前值
设备配置
运行状态

MQTT 5.0 标准明确规定了 RETAIN 标志:Broker 保存指定 Topic 的 retained message,并在后续匹配订阅时提供该消息。


二十六、Retain 和数据库有什么区别?

Retain:

保存 Topic 的最新消息

数据库:

保存完整业务历史

例如:

MQTT Retain:

temperature = 25.6

数据库:

10:00 → 25.1
10:01 → 25.3
10:02 → 25.6
10:03 → 25.4

所以:

Retain 不是数据库。

它更像:

这个 Topic 的“最后已知状态”。


二十七、MQTT Last Will:设备突然掉线怎么办?

这是 MQTT 另一个非常适合 IoT 的能力:

Last Will and Testament

简称:

Will Message

中文一般叫:

遗嘱消息。

假设:

ESP32

正常在线。

它连接 MQTT Broker 时告诉 Broker:

如果我异常掉线,
请帮我发布:

device/001/status = offline

如果 ESP32 正常执行:

DISCONNECT

Broker 不应该因为正常断开而发布遗嘱。

但是如果:

Wi-Fi 断开
设备死机
突然断电
网络断开

Broker 判断连接异常终止后,就可以发布:

offline

二十八、Will Message 对 IoT 有多重要?

比如:

device/001/status

可以设计:

online
offline

设备启动:

online

异常掉线:

offline

于是管理后台就可以实时显示:

设备 001    在线
设备 002    在线
设备 003    离线
设备 004    在线

而不需要不断 HTTP 查询:

设备 001 在线吗?
设备 002 在线吗?
设备 003 在线吗?

这正是 MQTT 非常适合 IoT 的一个重要原因。


二十九、Keep Alive:MQTT 怎么知道设备还活着?

MQTT 还有一个:

Keep Alive

机制。

例如:

Keep Alive = 60 秒

意味着客户端与 Broker 在规定时间内需要保持通信活动。

MQTT 提供:

PINGREQ
PINGRESP

用于保持连接以及检测连接状态。

协议中定义了:

Client
  |
  | PINGREQ
  ↓
Broker
  |
  | PINGRESP
  ↓
Client

如果连接长期没有有效通信,客户端或服务器可以判断连接已经失效。


三十、MQTT 为什么适合“长连接”?

IoT 设备经常需要:

一直在线
一直监听
随时接收命令

因此 MQTT 通常建立一个持续的 TCP 连接:

ESP32
   |
   | TCP
   |
MQTT Broker

然后:

温度来了
↓
PUBLISH

命令来了
↓
PUBLISH

状态变化
↓
PUBLISH

而不是每次数据都:

建立 HTTP 请求
发送
等待响应
结束

需要注意的是:

HTTP/1.1 本身也支持持久连接。

IETF RFC 9112 明确规定 HTTP/1.1 默认允许 persistent connections,一个连接上可以承载多个请求和响应。

所以不能简单说:

HTTP 没有长连接。

这是错误的。

真正的区别是:

HTTP 的核心语义依然是 Request/Response;MQTT 的核心语义是持续连接上的消息发布/订阅。


三十一、所以 MQTT 比 HTTP 快吗?

不能简单回答:

MQTT 一定比 HTTP 快。

这是一个非常常见的误区。

准确来说:

MQTT 在大量小消息、持续连接、实时消息分发、设备通信等场景下,通常具有更合适的协议模型和更低的通信开销。

而不是:

MQTT > HTTP

所有场景都成立。

例如:

下载 100 MB 文件

你显然不会因为 MQTT 轻量就选择 MQTT。

HTTP:

非常合适

MQTT:

并不适合

三十二、HTTP 和 MQTT 的本质不是“谁更快”

更准确的问题应该是:

这个通信场景是什么?

如果是:

Web API
文件下载
图片上传
REST
网页
资源访问

HTTP 非常合适。

如果是:

传感器
设备状态
实时消息
设备控制
一对多
持续在线
弱网

MQTT 往往更加合适。


三十三、一个完整的 IoT MQTT 架构

假设我们开发一个智能家居系统:

                     Internet
                         |
                  MQTT Broker
                         |
        +----------------+----------------+
        |                |                |
        ↓                ↓                ↓
      ESP32            ESP32            ESP32
      客厅灯            卧室灯            温度计

后面再接:

              MQTT Broker
                    |
          +---------+---------+
          |                   |
          ↓                   ↓
     Java Backend       Data Service
          |
          ↓
       MySQL
          |
          ↓
       Web Admin

完整结构:

                    ┌──────────────┐
                    │   Web Admin  │
                    └──────┬───────┘
                           ↓
                    ┌──────────────┐
                    │ Java Backend │
                    └──────┬───────┘
                           ↓
                    ┌──────────────┐
                    │ MQTT Broker  │
                    └──────┬───────┘
                           ↓
             ┌─────────────┼─────────────┐
             ↓             ↓             ↓
          ESP32-001     ESP32-002     ESP32-003

三十四、Java 后端为什么非常适合接 MQTT?

假设你本身是 Java 开发者。

你完全可以:

Spring Boot
     +
MQTT Client
     +
EMQX / Mosquitto

例如:

Spring Boot
     |
     | MQTT Client
     ↓
MQTT Broker
     |
     +── ESP32
     +── STM32
     +── Gateway

这样 Java 不需要自己实现:

MQTT Server

而是作为:

MQTT Client / Subscriber / Publisher

连接 Broker。


三十五、Java 订阅 MQTT 的基本思想

例如:

mqttClient.subscribe(
    "device/+/telemetry",
    1
);

收到消息:

public void messageArrived(
        String topic,
        MqttMessage message) {

    String payload =
        new String(
            message.getPayload(),
            StandardCharsets.UTF_8
        );

    System.out.println(
        topic + " => " + payload
    );
}

如果设备发送:

device/001/telemetry

Java 就可以收到:

{
    "temperature": 25.6,
    "humidity": 60
}

三十六、设备向 MQTT 发布数据

ESP32 可以使用 MQTT 客户端库。

伪代码:

mqttClient.publish(
    "device/001/telemetry",
    "{\"temperature\":25.6}"
);

整个链路:

ESP32
 ↓
PUBLISH
 ↓
MQTT Broker
 ↓
Java Subscriber
 ↓
业务处理
 ↓
MySQL

三十七、服务器向设备发送命令

服务器发布:

Topic:

device/001/command

Payload:

{
    "command": "LIGHT_ON"
}

ESP32 订阅:

device/001/command

于是:

Java
 ↓
MQTT PUBLISH
 ↓
Broker
 ↓
ESP32
 ↓
打开灯

整个过程中:

Java 根本不需要知道 ESP32 的 IP 地址。

这就是 MQTT 非常关键的价值。


三十八、这也是 MQTT 和 HTTP 最核心的区别之一

HTTP:

Server 想控制 Device

往往需要:

找到 Device
 ↓
建立连接
 ↓
发送 Request

MQTT:

Server
 ↓
Publish
 ↓
device/001/command
 ↓
Broker
 ↓
Device

服务器只需要知道:

Topic。

不需要知道设备在哪里。


三十九、这就是“位置”和“身份”的解耦

这是 MQTT 非常漂亮的设计。

设备:

device/001

无论它现在:

Wi-Fi A
4G
Wi-Fi B
家庭网络
公司网络

只要它连接到 Broker:

Broker

并订阅:

device/001/command

就可以收到命令。

因此:

Device Identity

与:

Network Location

被解耦了。

这对于 IoT 非常重要。


四十、MQTT 的安全性怎么样?

MQTT 本身并不意味着:

自动安全

通常需要:

MQTT
+
TLS
+
Authentication
+
Authorization

例如:

MQTT over TLS

常见端口:

1883

通常用于非 TLS MQTT。

而:

8883

常用于 MQTT over TLS。

MQTT 5.0 标准明确说明 TCP 1883 和 TLS 1883/8883 的注册使用,其中 8883 为 MQTT over TLS 的常见端口。


四十一、为什么 MQTT 必须做 Topic 权限控制?

假设:

device/001

只应该访问:

device/001/#

但是如果没有权限控制:

device/001

可能订阅:

device/002/command

甚至:

device/#

那就会产生非常严重的安全问题。

因此生产级 MQTT 必须设计:

Username
Password
Client ID
TLS
ACL
Topic Permission

例如:

device/001

允许:

device/001/telemetry
device/001/status
device/001/command

禁止:

device/002/#
system/#
admin/#

四十二、MQTT Topic 权限实际上非常适合多租户 IoT

假设:

tenant001
tenant002
tenant003

可以设计:

tenant/{tenantId}/device/{deviceId}/telemetry

例如:

tenant/10001/device/001/telemetry

Java 后端可以根据:

tenantId

进行权限控制。

这和 SaaS 多租户设计其实非常类似。


四十三、MQTT 与数据库应该怎么配合?

一个比较合理的架构:

ESP32
 ↓
MQTT
 ↓
Broker
 ↓
Java Consumer
 ↓
┌───────────────┐
│ Business Logic│
└───────┬───────┘
        ↓
     MySQL

但是不要把所有实时数据都无脑写 MySQL。

例如:

10000 台设备
每秒上报一次

就是:

10000 messages / second

一年数据量非常大。

这时候应该考虑:

MQTT
 ↓
Message Processing
 ↓
Kafka / Pulsar
 ↓
Time Series DB

或者:

MQTT
 ↓
Stream Processing
 ↓
InfluxDB
TimescaleDB
ClickHouse

根据具体业务选择。


四十四、MQTT 并不是数据库

这一点必须再次强调。

MQTT:

消息传输协议

MySQL:

关系型数据库

Redis:

缓存 / 数据结构存储

Kafka:

分布式事件流平台

它们解决的问题完全不同。

所以:

MQTT

不是:

Kafka 的 IoT 版本

也不是:

Redis 的消息版

它首先是:

IoT/M2M 场景下的轻量级消息传输协议。


四十五、MQTT 和 Kafka 有什么区别?

这个问题在后端开发中非常常见。

对比MQTTKafka
定位消息传输协议分布式事件流平台
主要对象IoT / Client后端服务 / 数据平台
Broker核心Broker 集群
Topic
QoSMQTT QoS 0/1/2不同可靠性机制
设备友好很强通常不适合直接跑在 MCU 上
持久化有相关机制核心能力之一
大规模日志流一般非常强
IoT 接入很适合通常需要网关
数据分析通常配合其他系统很强

实际系统甚至可以:

ESP32
 ↓
MQTT
 ↓
EMQX
 ↓
Kafka
 ↓
Data Platform

这才是非常常见的企业级架构思路。


四十六、MQTT 和 WebSocket 有什么区别?

WebSocket:

双向通信

MQTT:

发布 / 订阅消息协议

可以理解为:

WebSocket
解决:
浏览器与服务器之间建立双向通信通道

而:

MQTT
解决:
IoT 客户端之间如何进行消息发布和订阅

MQTT 甚至可以运行在 WebSocket 之上。

OASIS MQTT 5.0 标准明确说明 MQTT 可以运行在提供有序、无损、双向字节流的底层传输之上,并列出了 TCP/IP、TLS、WebSocket 等方式。


四十七、一个真实的智能家居系统应该怎么设计?

假设:

ESP32

控制:

客厅灯
卧室灯
风扇
窗帘
温度传感器
人体传感器

可以设计:

home/
├── livingroom/
│   ├── light/
│   │   ├── command
│   │   └── state
│   └── temperature
│
├── bedroom/
│   ├── light/
│   │   ├── command
│   │   └── state
│   └── temperature
│
└── gateway/
    └── status

四十八、设备状态 Topic

例如:

home/livingroom/light/state

Payload:

{
    "power": true,
    "brightness": 80
}

设置:

retain = true

这样新的客户端连接后,可以直接得到当前状态。


四十九、设备命令 Topic

例如:

home/livingroom/light/command

Payload:

{
    "action": "TURN_ON"
}

ESP32:

Subscribe:

home/livingroom/light/command

收到:

{
    "action": "TURN_ON"
}

然后:

GPIO HIGH

打开继电器。


五十、设备遥测 Topic

例如:

home/livingroom/sensor/telemetry

Payload:

{
    "temperature": 25.6,
    "humidity": 61.2
}

Java 后端:

Subscribe:

home/+/sensor/telemetry

即可接收所有房间的传感器数据。


五十一、设备在线状态 Topic

home/device/001/status

在线:

online

异常掉线:

offline

通过:

Will Message

实现。


五十二、最终形成一个非常漂亮的 IoT 通信模型

                    MQTT Broker
                         |
       +-----------------+-----------------+
       |                 |                 |
       ↓                 ↓                 ↓
    Telemetry         Command           Status
       |                 |                 |
       ↓                 ↓                 ↓
     Device           Device            Device

服务器:

                    Java Backend
                         |
                         |
                    MQTT Client
                         |
                         ↓
                   MQTT Broker

五十三、为什么 IoT 喜欢 MQTT?

现在我们可以真正回答最开始的问题。

因为 IoT 有很多特殊需求:

1. 设备数量巨大
2. 设备资源有限
3. 网络环境复杂
4. 设备可能随时掉线
5. 需要实时通信
6. 需要服务器主动下发
7. 一对多通信很常见
8. 需要设备状态管理
9. 需要离线处理
10. 需要低通信开销

而 MQTT 恰好针对其中很多问题提供了:

Publish / Subscribe
Broker
Topic
QoS
Retain
Will
Keep Alive
Session

所以:

不是 HTTP 不好。

而是:

MQTT 的通信模型更贴合很多 IoT 场景。


五十四、但是 HTTP 在 IoT 中依然非常重要

真正成熟的 IoT 系统一般不会:

全部 MQTT

更常见的是:

                IoT Platform
                     |
        +------------+------------+
        |                         |
       MQTT                      HTTP
        |                         |
     Device                   Management API
        |                         |
   Telemetry                 Web / App
   Command                   Admin
   Status                    Configuration

例如:

ESP32
 ↓ MQTT
设备数据

而:

Web
 ↓ HTTP
查询设备列表

又比如:

Web
 ↓ HTTP
修改设备名称

后端:

HTTP
 ↓
Java
 ↓
MQTT
 ↓
ESP32

于是:

HTTP

负责:

业务 API。

MQTT

负责:

设备消息。

这才是非常合理的架构。


五十五、一个典型的“HTTP + MQTT”架构

                 ┌───────────────┐
                 │   Web / App   │
                 └───────┬───────┘
                         │
                       HTTP
                         │
                         ↓
                ┌────────────────┐
                │  Java Backend  │
                └───────┬────────┘
                        │
             ┌──────────┴──────────┐
             │                     │
            HTTP                  MQTT
             │                     │
             ↓                     ↓
        Business API         MQTT Broker
                                   │
                     ┌─────────────┼─────────────┐
                     ↓             ↓             ↓
                   ESP32         ESP32         ESP32

这套架构其实非常适合:

Spring Boot
+
EMQX
+
MySQL
+
Redis
+
Vue
+
ESP32

五十六、如果我作为是一个 Java + IoT 开发者,我会怎么设计?

如果让我从零设计一个 IoT 平台,我不会选择:

全部 HTTP

也不会选择:

全部 MQTT

而会选择:

                 Frontend
                    |
                   HTTP
                    |
              Spring Boot
             /            \
          Redis          MySQL
             \
              MQTT Client
                  |
              MQTT Broker
                  |
       +----------+----------+
       |          |          |
     ESP32      ESP32      Gateway

其中:

HTTP

负责:

用户
设备管理
用户管理
设备配置
查询
统计
权限

而:

MQTT

负责:

遥测
状态
命令
实时数据
设备上下线
设备事件

五十七、MQTT 最核心的知识点总结

如果你刚刚开始学习 MQTT,可以先记住下面这张表:

概念作用
ClientMQTT 客户端
Broker消息代理服务器
Publisher发布消息
Subscriber订阅消息
Topic消息主题
PUBLISH发布消息
SUBSCRIBE订阅主题
QoS 0最多一次
QoS 1至少一次
QoS 2恰好一次
Retain保存 Topic 最新消息
Will异常断线消息
Keep Alive保持/检测连接
Session保存客户端会话状态
TLS加密通信
ACLTopic 权限控制

五十八、MQTT 的完整通信流程

一个典型 MQTT Client 生命周期:

                Client
                   |
                   | CONNECT
                   ↓
                Broker
                   |
                   | CONNACK
                   ↓
                Client
                   |
                   | SUBSCRIBE
                   ↓
                Broker
                   |
                   | SUBACK
                   ↓
                Client
                   |
                   | PUBLISH
                   ↓
                Broker
                   |
                   | PUBLISH
                   ↓
              Subscriber

如果是 QoS 1:

PUBLISH
   ↓
PUBACK

如果是 QoS 2:

PUBLISH
   ↓
PUBREC
   ↓
PUBREL
   ↓
PUBCOMP

这就是 MQTT 最基本的协议交互。


五十九、MQTT 不是“更高级的 HTTP”

这一点非常重要。

很多初学者会认为:

HTTP
 ↓
MQTT

好像 MQTT 是 HTTP 的升级版。

不是。

它们解决的问题不同。

HTTP:

Request / Response
Resource
URI
Method
Status Code

MQTT:

Publish / Subscribe
Topic
Broker
QoS
Session
Retain
Will

它们是:

不同通信模型的协议。


六十、什么时候应该用 HTTP?

如果你的需求是:

用户登录
查询设备列表
查询历史数据
修改设备名称
上传图片
下载文件
管理后台
REST API
开放平台 API

优先考虑:

HTTP / HTTPS

六十一、什么时候应该用 MQTT?

如果你的需求是:

传感器实时上报
设备在线状态
远程控制
实时消息
大量设备
设备主动上报
服务器主动下发
弱网
长连接
一对多消息

优先考虑:

MQTT

六十二、什么时候两个都需要?

绝大多数完整 IoT 平台。

例如:

用户
 ↓
HTTPS
 ↓
Java Backend
 ↓
MQTT
 ↓
Device

设备:

Device
 ↓
MQTT
 ↓
Java Backend

查询:

Web
 ↓
HTTPS
 ↓
Java Backend
 ↓
MySQL

这是非常经典的:

HTTP + MQTT 双协议架构。


六十三、最终答案:为什么物联网经常不用 HTTP,而使用 MQTT?

现在终于可以给出一个完整答案。

并不是:

物联网不用 HTTP。

而是:

物联网的通信特点与 HTTP 的 Request/Response 模型并不总是匹配,而 MQTT 的 Publish/Subscribe 模型更加适合大量设备、实时消息、弱网、长连接、设备上下行通信等场景。

HTTP 擅长:

请求资源
调用 API
上传文件
下载数据
Web 服务

MQTT 擅长:

设备消息
实时数据
状态同步
远程控制
一对多通信
设备上下行

所以实际系统往往是:

                User
                  |
                 HTTPS
                  |
            Java Backend
             /         \
            /           \
         MySQL          MQTT
                          |
                       Broker
                          |
          +---------------+---------------+
          |               |               |
        ESP32           ESP32           Gateway

这才是正确理解 MQTT 的方式。


六十四、从 HTTP 到 MQTT,本质上是通信思想的变化

HTTP 的思维:

我想要什么?
↓
我去请求服务器。

MQTT 的思维:

我关心什么?
↓
我订阅 Topic。

HTTP:

Client
  ↓
Request
  ↓
Server
  ↓
Response

MQTT:

Publisher
    ↓
  Topic
    ↓
 Broker
    ↓
Subscriber

这两个模型之间最大的区别,并不是:

代码写法不同

而是:

通信关系不同。


六十五、MQTT 真正伟大的地方:解耦

如果让我用一个词总结 MQTT:

解耦。

设备不需要知道:

谁在消费消息

消费者不需要知道:

设备在哪里

发布者不需要知道:

订阅者是谁

所有东西通过:

Broker
+
Topic

连接起来。

最终形成:

                 Topic
                   |
        +----------+----------+
        |          |          |
      Device      Java       AI
        |          |          |
        +----------+----------+
                   |
                 Broker

这也是 MQTT 能够成为 IoT 领域重要通信协议的核心原因之一。


六十六、从 MQTT 再往前一步:IoT 平台真正的核心是什么?

如果继续往后学习 IoT,你会发现:

MQTT 其实只是第一步。

真正完整的 IoT 平台还需要:

Device Management
设备管理

Device Authentication
设备认证

Device Provisioning
设备注册

Device Shadow
设备影子

OTA
固件升级

Rule Engine
规则引擎

Event Processing
事件处理

Data Storage
数据存储

Alarm
告警

Dashboard
数据可视化

AI
智能分析

最终形成:

                  IoT Platform
                       |
      +----------------+----------------+
      |                |                |
   Device            Data             AI
   Management       Platform         Engine
      |                |                |
      +----------------+----------------+
                       |
                    MQTT
                       |
               MQTT Broker
                       |
          +------------+------------+
          |            |            |
        ESP32        STM32       Gateway

所以:

MQTT 不是物联网平台。

MQTT 是物联网平台非常重要的一条通信基础设施。


六十七、如果你正在学习 IoT,建议这样学习 MQTT

建议不要一上来就背:

QoS
Retain
Will
Session

而是按照下面的路线学习。

第一阶段:理解通信模型

先理解:

HTTP
Request / Response

然后:

MQTT
Publish / Subscribe

真正理解两者为什么不同。


第二阶段:理解 MQTT 核心组件

掌握:

Client
Broker
Publisher
Subscriber
Topic

第三阶段:掌握消息可靠性

重点学习:

QoS 0
QoS 1
QoS 2

并理解:

为什么 QoS 1 会重复?
为什么业务需要幂等?
为什么 QoS 2 开销更高?

第四阶段:掌握 IoT 状态机制

学习:

Retain
Will
Keep Alive
Session

第五阶段:掌握安全

学习:

TLS
Authentication
Authorization
ACL
Topic Permission

第六阶段:和 Java 结合

学习:

Spring Boot
+
MQTT Client
+
EMQX

实现:

设备上报
设备订阅
服务端下发
设备上下线
数据入库

第七阶段:连接真实硬件

例如:

ESP32
+
温度传感器
+
MQTT
+
EMQX
+
Spring Boot
+
MySQL
+
Vue

做出一个真正可以运行的 IoT 项目。


六十八、一个真正值得做的 MQTT 实战项目

如果你准备把 MQTT 学透,我非常推荐做这样一个项目:

“基于 ESP32 + MQTT + Spring Boot 的物联网设备管理平台”

架构:

                  Vue
                   |
                  HTTP
                   |
             Spring Boot
              /        \
             /          \
          MySQL        MQTT Client
                         |
                     EMQX Broker
                         |
             +-----------+-----------+
             |           |           |
           ESP32       ESP32       ESP32
             |           |           |
          Sensor       Sensor      Relay

功能:

设备注册
设备认证
设备在线
设备离线
温度上报
湿度上报
远程开关
设备日志
历史数据
实时数据
MQTT QoS
Retain
Will
OTA

这个项目做完以后,MQTT 基本就不是停留在“知道概念”的阶段了。

而是真正进入:

能设计 IoT 系统。


六十九、最后总结

如果整篇文章只记住下面这张图,就已经足够了:

                 HTTP

             Client
                |
             Request
                |
                ↓
             Server
                |
             Response
                |
                ↓
             Client

HTTP 是:

请求 / 响应。

而 MQTT:

                 MQTT

 Publisher
     |
  Publish
     |
     ↓
  Topic
     |
     ↓
  Broker
     |
     +------------+
     |            |
     ↓            ↓
Subscriber    Subscriber

MQTT 是:

发布 / 订阅。

再往上:

HTTP
 ↓
业务 API

MQTT
 ↓
设备消息

Broker
 ↓
设备通信

QoS
 ↓
消息可靠性

Retain
 ↓
最新状态

Will
 ↓
异常掉线

Keep Alive
 ↓
连接状态

TLS + ACL
 ↓
安全

所以,物联网为什么经常使用 MQTT?

不是因为:

MQTT 比 HTTP 高级。

也不是因为:

HTTP 不能做物联网。

真正原因是:

物联网面对的是大量设备、持续连接、实时消息、上下行通信、弱网络环境以及一对多消息分发,而 MQTT 的 Publish/Subscribe + Broker + Topic + QoS 等机制,天然更贴合这些通信需求。

HTTP 解决的是:

客户端如何请求服务器资源。

MQTT 解决的是:

大量设备和服务之间如何高效地交换消息。

当你真正理解这一点之后,MQTT 就不再是一堆:

QoS
Topic
Retain
Will
Broker

这些零散概念。

你会发现:

MQTT 的每一个设计,几乎都在回答 IoT 世界里的一个真实问题。


七十、官方标准与参考资料

本文主要参考以下官方标准与权威资料。

1. OASIS MQTT 5.0 官方标准

MQTT 5.0 是 OASIS 标准,完整定义了:

MQTT Client / Server
Publish / Subscribe
Topic
QoS
Retain
Will
Session
Keep Alive
Flow Control

官方标准:

https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html


2. OASIS MQTT 3.1.1 官方标准

MQTT 3.1.1 同样是 OASIS 标准,也是大量 MQTT 实际项目长期使用的重要版本。

官方标准:

https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html


3. IETF RFC 9110:HTTP Semantics

RFC 9110 定义了现代 HTTP 的核心语义,并明确说明 HTTP 是一种:

stateless
request/response

协议。

官方:

https://www.rfc-editor.org/rfc/rfc9110.html


4. IETF RFC 9112:HTTP/1.1

RFC 9112 定义 HTTP/1.1 消息语法和连接管理,并明确说明 HTTP/1.1 默认支持 persistent connections。

官方:

https://www.rfc-editor.org/rfc/rfc9112.html

更多推荐