返回文章列表

MQTT vs HTTP:物聯網通訊協定怎麼選?

深入比較 MQTT 與 HTTP 在物聯網應用中的優劣勢,從頻寬、延遲、電力消耗到實作複雜度,幫助你選擇最適合的通訊協定。

12 分鐘
MQTTHTTP物聯網IoT通訊協定ESP32嵌入式系統

MQTT vs HTTP:物聯網通訊協定怎麼選?

物聯網裝置需要與雲端通訊,選擇適合的通訊協定直接影響系統效能、電池壽命和維護成本。本文深入比較 MQTT 與 HTTP 兩種主流協定,幫助你做出最佳選擇。

協定概述

HTTP(HyperText Transfer Protocol)

HTTP 是 Web 的基礎協定,採用請求-回應模式:

客戶端 ──請求──> 伺服器
客戶端 <──回應── 伺服器

特點

  • 無狀態協定
  • 請求-回應模式
  • 文字型標頭(HTTP/1.1)
  • 廣泛支援與成熟工具鏈

MQTT(Message Queuing Telemetry Transport)

MQTT 是專為物聯網設計的輕量級發布-訂閱協定:

發布者 ──發布訊息──> Broker ──推送──> 訂閱者

特點

  • 發布/訂閱模式
  • 極小封包開銷
  • 持久連線
  • QoS(服務品質)保證

效能比較

頻寬消耗

項目 MQTT HTTP
標頭大小 2-5 bytes 700+ bytes
連線建立 一次 每次請求
Keep-alive 極小 N/A

對於頻繁發送小量資料的場景,MQTT 的頻寬優勢非常明顯:

// MQTT 發送感測器資料(ESP32)
void send_mqtt_data(float temperature, float humidity) {
    char payload[64];
    snprintf(payload, sizeof(payload),
             "{\"temp\":%.1f,\"hum\":%.1f}", temperature, humidity);

    // 實際傳輸:2 bytes 固定標頭 + topic長度 + payload
    // 總計約 30-50 bytes
    mqtt_client_publish(client, "sensors/living-room", payload, 0, 0);
}

// HTTP 發送相同資料
void send_http_data(float temperature, float humidity) {
    char body[64];
    snprintf(body, sizeof(body),
             "{\"temp\":%.1f,\"hum\":%.1f}", temperature, humidity);

    // HTTP 請求包含:
    // - 請求行:POST /api/sensors HTTP/1.1
    // - Host, Content-Type, Content-Length 等標頭
    // - 空行 + body
    // 總計約 300-500 bytes
    http_client_post(client, "/api/sensors", body);
}

延遲比較

MQTT 的持久連線大幅降低延遲:

場景 MQTT HTTP
首次連線 ~100ms ~100ms
後續訊息 ~10ms ~100ms
伺服器推送 即時 需輪詢

電力消耗

對於電池供電裝置,MQTT 更省電:

HTTP 每次請求流程:
1. TCP 握手(3 次往返)
2. TLS 握手(2-4 次往返)
3. HTTP 請求/回應
4. 連線關閉

MQTT 持久連線:
1. 初始連線建立(同 HTTP)
2. 後續只需發送小封包
3. Keep-alive 維持連線

實測數據(ESP32 + WiFi):

操作 MQTT HTTP
發送一筆資料 15 mAs 80 mAs
每分鐘發送一次 900 mAs/hr 4800 mAs/hr

功能比較

訊息品質保證(QoS)

MQTT 提供三種 QoS 等級:

// QoS 0:最多一次(Fire and Forget)
// 不保證送達,最低開銷
mqtt_publish(client, topic, payload, QOS_0, false);

// QoS 1:至少一次
// 確保送達,可能重複
mqtt_publish(client, topic, payload, QOS_1, false);

// QoS 2:剛好一次
// 確保送達且不重複,開銷最大
mqtt_publish(client, topic, payload, QOS_2, false);

HTTP 需要應用層自行實作重試機制。

伺服器推送

MQTT 原生支援伺服器推送:

// 訂閱主題,當有新訊息時自動接收
void mqtt_message_handler(char *topic, char *payload) {
    if (strcmp(topic, "commands/device-001") == 0) {
        handle_command(payload);
    }
}

mqtt_subscribe(client, "commands/device-001", QOS_1, mqtt_message_handler);

HTTP 需要使用以下方式實現:

  • 輪詢(Polling):定時請求,浪費頻寬
  • 長輪詢(Long Polling):佔用連線
  • WebSocket:額外複雜度

離線訊息

MQTT 支援離線訊息緩存:

// 設定 Clean Session = false,Broker 會保留離線訊息
mqtt_connect_options opts = {
    .client_id = "device-001",
    .clean_session = false,  // 保留會話狀態
};

// 使用 Retained Message,新訂閱者會收到最後一則訊息
mqtt_publish(client, "status/device-001", "online", QOS_1, true);

實作範例

ESP32 MQTT 客戶端

#include "mqtt_client.h"

static esp_mqtt_client_handle_t mqtt_client;

// MQTT 事件處理
static void mqtt_event_handler(void *args, esp_event_base_t base,
                                int32_t event_id, void *event_data) {
    esp_mqtt_event_handle_t event = event_data;

    switch (event->event_id) {
        case MQTT_EVENT_CONNECTED:
            ESP_LOGI(TAG, "MQTT 已連線");
            // 訂閱命令主題
            esp_mqtt_client_subscribe(mqtt_client, "commands/#", 1);
            break;

        case MQTT_EVENT_DATA:
            ESP_LOGI(TAG, "收到訊息: %.*s", event->data_len, event->data);
            process_message(event->topic, event->data);
            break;

        case MQTT_EVENT_DISCONNECTED:
            ESP_LOGW(TAG, "MQTT 斷線,自動重連中...");
            break;
    }
}

void mqtt_init(void) {
    esp_mqtt_client_config_t config = {
        .broker.address.uri = "mqtts://broker.example.com",
        .credentials.client_id = "esp32-device-001",
        .session.keepalive = 60,
    };

    mqtt_client = esp_mqtt_client_init(&config);
    esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID,
                                    mqtt_event_handler, NULL);
    esp_mqtt_client_start(mqtt_client);
}

// 發送感測器資料
void publish_sensor_data(float temp, float humidity) {
    char payload[128];
    snprintf(payload, sizeof(payload),
             "{\"temperature\":%.2f,\"humidity\":%.2f,\"timestamp\":%lld}",
             temp, humidity, esp_timer_get_time() / 1000);

    esp_mqtt_client_publish(mqtt_client, "sensors/esp32-001",
                            payload, 0, 1, 0);
}

Node.js MQTT Broker 端

const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://broker.example.com');

// 訂閱所有感測器資料
client.on('connect', () => {
  client.subscribe('sensors/#', (err) => {
    if (!err) console.log('已訂閱 sensors 主題');
  });
});

// 處理收到的訊息
client.on('message', (topic, message) => {
  const data = JSON.parse(message.toString());
  console.log(`[${topic}] 溫度: ${data.temperature}°C`);

  // 儲存到資料庫
  saveToDatabase(topic, data);

  // 檢查是否需要告警
  if (data.temperature > 30) {
    client.publish('alerts/high-temp', JSON.stringify({
      device: topic.split('/')[1],
      temperature: data.temperature,
    }));
  }
});

選擇建議

選擇 MQTT 的情況

  1. 頻繁小量資料傳輸:感測器每秒或每分鐘上報
  2. 電池供電裝置:需要最小化無線傳輸
  3. 需要即時推送:遠端控制、告警通知
  4. 不穩定網路:QoS 保證訊息送達
  5. 大量裝置:萬級裝置同時連線

選擇 HTTP 的情況

  1. 偶發性資料上傳:一天幾次的回報
  2. 大量資料傳輸:韌體更新、日誌上傳
  3. 與 Web 服務整合:使用現有 REST API
  4. 簡單實作:不需要額外部署 Broker
  5. 防火牆限制:只開放 80/443 port

混合架構

許多系統會同時使用兩種協定:

┌─────────────────────────────────────────────────────┐
│                    雲端服務                          │
│  ┌─────────────┐         ┌─────────────┐           │
│  │ MQTT Broker │         │ REST API    │           │
│  │ (即時資料)   │         │ (查詢/設定)  │           │
│  └──────┬──────┘         └──────┬──────┘           │
└─────────┼───────────────────────┼───────────────────┘
          │                       │
     MQTT │                  HTTP │
          ▼                       ▼
┌─────────────────────────────────────────────────────┐
│                   物聯網裝置                         │
│  - 即時感測資料 → MQTT                              │
│  - 韌體更新 → HTTP                                  │
│  - 設定變更 → HTTP                                  │
└─────────────────────────────────────────────────────┘

結論

MQTT 和 HTTP 各有優勢,選擇時應考慮:

考量點 MQTT 更適合 HTTP 更適合
傳輸頻率 高頻 低頻
資料大小 小量 大量
即時性 需要 不需要
電力預算 受限 充足
基礎設施 可部署 Broker 使用現有服務

如果你正在規劃物聯網專案,歡迎聯繫我們討論最適合的通訊架構。