TsukuLab
This article is in 日本語. The English version is coming soon.
Getting Started

MQTT入門|HTTPとの違い・QoS・ブローカーまで

Updated: 2026-03-19 20:02:59中村 拓也

IoTの通信で『MQTT』が気になっているけれど、Pub/Subやブローカー、QoSといった用語が一気に出てきて手が止まる人は多いはずです。
この記事は、HTTPとの違いを踏まえて「自分の用途ならどちらを選ぶべきか」を判断したい人と、Mosquitto『MQTTX』、そしてESP32で最初の疎通確認まで進めたい人に向けて書いています。

筆者がワークショップで初心者と進めるときも、最初の山場はESP32のTLS接続で設定するCA証明書PEMです。
そこで本記事では、用語だけを並べるのではなく、subscribe→publishの最小検証とTLS接続の入口を具体的に押さえながら、MQTT 3.1.1と5.0の差分も「現場でどちらを選ぶと運用が楽になるか」という軸まで落として整理します。
AWSのMQTT解説(https://aws.amazon.com/jp/what-is/mqtt/やOASIS MQTT 5.0仕様やOASIS MQTT 5.0仕様で定義されている内容を、実装の最初の一歩につながる形で短くつかめる構成です))。

関連記事スマートホーム自作|ラズパイとESP32の始め方ラズパイ=司令塔、ESP32=末端ノードの役割で最小構成を組む入門。必要部品、MQTT(Mosquitto)、Node-RED、必要に応じてHome Assistantまで一気通貫で解説。センサー送信とLED制御の初実装、容量要件とセキュリティの基本もカバー。

MQTTとは?仕組みとIoTで使われる理由

歴史と設計思想

『MQTT』は、軽量なPub/Sub型メッセージングプロトコルです。
センサーやマイコンが小さなデータを継続的に送り、必要な相手だけが受け取る構成に向いているため、IoTやM2Mで広く使われています。
AWSのMQTT解説(https://aws.amazon.com/jp/what-is/mqtt/でも、低帯域で不安定な回線に適した通信方式として整理されています)。

出発点を押さえると、この設計思想が見えやすくなります。
MQTTは1999年に、油田パイプライン監視のような、回線が細くて不安定でもデータを届けたい用途から生まれました。
要点はここです。
Webページをその都度取りに行く発想ではなく、接続を保ちながら小さなイベントを流し続ける発想で設計されているので、IoTの現場で自然にフィットします。

HTTPでも通信自体は可能ですが、ヘッダー項目(Cookie、Authorization、User‑Agent など)やプロトコル(HTTP/1.1 / HTTP/2)、圧縮の有無によってヘッダー長は大きく変わります。
典型的な簡素な HTTP リクエストでもヘッダーは「数十バイト」になり得ますが、実際の値は運用環境やヘッダー項目の有無、プロトコル仕様によって大きく変動するため、あくまで条件付きの参考例として扱ってください。
少量データを高頻度で送る場面では、こうした差分がボトルネックになり得る点に注意しましょう。

規格の節目も古い解説で止めないほうがよい部分です。
MQTT 3.1.1は2014年に標準化され、MQTT 5.0は2019年に公開されました。
3.1.1だけ読んでいると「つながればよい」印象で終わりがちですが、5.0では運用に効く拡張が増えています。
たとえばReason Codeが入ったことで、接続拒否や購読失敗の理由をコード付きで追えるようになりました。
以前は「つながらない」で止まりがちだった場面でも、認可なのか、トピック制限なのか、クォータ超過なのかを切り分けやすくなっています。

同じくUser Propertyは、メッセージに任意のメタデータを付けたいときに役立ちます。
たとえばセンサー値そのものとは別に、送信元の論理グループや処理系の識別子を持たせる設計が取りやすくなります。
Session Expiryは、再接続後もどこまでセッション情報を残すかを明示できる仕組みです。
短時間の切断が起きても購読状態や未配送メッセージの扱いを整理しやすく、モバイル回線や一時的なWi-Fi切替がある環境では効いてきます。
Topic Aliasは長いトピック名を毎回そのまま送らずに済むため、帯域節約に直結します。
Request/Responseも5.0で整理され、Response TopicやCorrelation Dataを使って、Pub/Subでありながら応答先を明示したやり取りを組み立てやすくなりました。
さらにShared Subscriptionを使うと、複数のワーカーで同じ購読を分担できるので、1本のトピックに処理が集中する構成でも受け側を水平分散しやすくなります。

IoTで採用される理由は、この仕様ときれいにつながります。
低帯域回線での送信、双方向の非同期イベント、1対多配信、切断後のセッション継続、TLSでの暗号化通信が、1つの流れとしてまとまっているからです。
mqtt.orgmqtt.orgやAWS IoT Core device communication protocols(https://docs.aws.amazon.com/iot/latest/developerguide/protocols.htmlでも、TCP/IP上での利用が一般的な前提として扱われています。
さらに、TLSやWebSocket経由の運用も広く前提とされています。
ESP32のようなマイコンでTLS接続を組む場面でも、この前提知識があると「なぜMQTTなのか」が腹落ちします))。

MQTTX: Your All-in-one MQTT Client Toolboxmqttx.app

図で理解するPub/Subの基本フロー

HTTPしか触っていない読者が最初に戸惑うのは、誰かに取りに行く通信ではなく、待ち受けながら双方向にイベントが流れ続けるという感覚です。
筆者の経験では、この一点が腑に落ちると理解が一気に進みます。
そのため、MQTTでは文章だけより図で捉えるほうが早いです。

まず頭の中では、PublisherとSubscriberの間にBrokerが1台いる絵を置いてください。
温度センサーを載せたESP32がPublisherとして devices/device-01/telemetry に温度を送ると、そのデータは直接スマホやサーバーへ飛ぶのではなく、いったんBrokerに入ります。
Brokerはそのトピックを見て、同じトピックを購読しているSubscriberへ配ります。
管理画面、記録用のサーバー、アラート監視のワーカーが同じトピックを見ていれば、1回のpublishで複数の受信側に同時に届きます。

図にするなら、左にPublisher、中央にBroker、右に複数のSubscriberを置き、PublisherからBrokerへ上向きの矢印、Brokerから各Subscriberへ枝分かれした矢印を書くと流れが見えます。
さらに逆方向の矢印も足してください。
MQTTはセンサー値の送信だけではなく、制御コマンドや設定変更も同じ接続の上で流せます。
たとえば管理アプリが devices/device-01/cmd に命令をpublishし、ESP32側がそれをsubscribeする構成です。
ここで「送る側」「受ける側」が固定ではなく、クライアントは場面によってpublishもsubscribeも行う、という理解が重要です。

このモデルは、Request/Responseの整理にもつながります。
HTTPのように1本のリクエストへ同期的にレスポンスを返す代わりに、MQTT 5.0ではResponse TopicとCorrelation Dataを使って、応答先トピックを明示した非同期のやり取りを組み立てます。
たとえばデバイス設定の取得要求を送るときに、返信先トピックを別に渡しておけば、受け手はそこへ結果を書き戻せます。
Pub/Subなのに応答も扱える、というのが5.0で理解しやすくなった点です。

NOTE

図では「送信元」「受信先」よりも、「どのトピックにpublishし、誰がそのトピックをsubscribeしているか」を中心に描くと、MQTTらしい見え方になります。

実装時の注意点もここで触れておきます。
Pub/Subは自由度が高いぶん、トピック設計が曖昧だとすぐに混線します。devices/{deviceId}/telemetrydevices/{deviceId}/statedevices/{deviceId}/cmd のように、計測値、現在状態、制御命令を分けるだけで、権限設定と運用の見通しが変わります。
ワイルドカード購読を広く取りすぎると、受け手に不要なメッセージまで集まりやすくなりますし、単一の購読者に流量が集中しやすくなります。
データ収集ワーカーを複数台に分けるなら、早い段階からShared Subscriptionを前提にトピック構成を考えておくと詰まりにくくなります。

ブローカーの役割とトピックルーティング

ブローカーは、単なる中継サーバーではありません。
受け取ったメッセージをトピックに基づいて振り分け、接続状態や購読状態を管理し、必要に応じて保持や再配送の判断も行う、MQTTの中心です。
PublisherとSubscriberが互いの存在を知らなくても通信できるのは、ブローカーが間に立って疎結合を保っているからです。

ルーティングの基本はトピックです。
クライアントは factory/line1/temp のような文字列を付けてpublishし、Subscriberは完全一致またはトピックフィルタで購読します。+ は単一レベル、# は複数レベルに一致するので、devices/+/telemetry のような購読も可能です。
ただし広いフィルタは便利な反面、どの処理がどこまで受け取るのか見えにくくなります。
運用が長くなるほど、トピックはAPI設計に近い扱いになります。

MQTT 5.0の拡張は、このブローカー中心の運用を現実的にしてくれます。
Reason CodeはCONNACKやSUBACK、DISCONNECTなどで失敗理由を返せるので、ブローカー側の拒否をクライアントが読み解きやすくなります。
User Propertyはルーティングそのものではなく補助情報ですが、ログ基盤や監視系へ渡す文脈を残す用途で効きます。
Session Expiryは、切断後もセッションを残しておく時間を制御するので、再接続時に購読を張り直す手間を減らせます。
Topic Aliasはブローカーとクライアントの間で長いトピック文字列の送受信を短縮し、たとえば階層が深い命名規則を採用したときの帯域負担を抑えます。

ブローカーの役割を考えるうえで、保持系の機能も外せません。
Retained Messageを使うと、ブローカーはトピックごとの最後のメッセージを保持し、新しくsubscribeしたクライアントへ即時に渡せます。
機器の現在状態を devices/device-01/state にretainしておけば、監視画面があとから接続しても「直近の状態」が空白になりません。
筆者は初学者向けの説明で、この動きを見せると理解が早まると感じています。
リアルタイムに流れているだけでなく、ブローカーが状態の受け渡し地点にもなっていると分かるからです。

接続管理ではKeep AliveとLWTもブローカーの重要な仕事です。
Keep Aliveを60秒にした場合、仕様上はブローカー側の猶予が90秒になります。
短い切断をどう扱うかは設計に直結しますし、LWTを設定しておけば、クライアントが正常に切断できなかったときに offline のようなメッセージをブローカーが代わりにpublishできます。
状態監視を作るときは、テレメトリだけでなく、この「つながっているか」の表現をどう出すかで運用の見え方が変わります。

実装時にはTLS設定にも注意が必要です。
ESP32ではCA証明書をPEM形式で持たせてMQTTS接続する構成が定番で、証明書の文字列が崩れている、改行が欠けている、接続先のポートやSNIの設定が合っていない、といった初歩的なミスで止まりやすいです。
ブローカーへ接続できないとき、3.1.1系の情報だけでは原因が見えにくいことがありますが、5.0でReason Codeが取れる構成にしておくと、認証失敗なのかプロトコル不一致なのかを追いやすくなります。
疎通確認では『MQTTX』のようなクライアントを使うと、Topic AliasやSession Expiryを含むMQTT 5.0のプロパティを目で追いながら試せるので、ブローカーが何を返しているか把握しやすくなります。

関連記事IoT入門|センサーデータをクラウドへ送る基本構成IoTは、センサーで拾った情報をどう処理し、どうつなぎ、どこに貯めて、どう見せて使うかまでを5つの層で分けて考えると、一気に道筋が見えてきます。IoT Basics: A Guide for Beginnersでも、デバイスとネットワーク、クラウドやアプリケーションに分けて捉える整理が基本です。

MQTTの基本機能を押さえる:トピック、QoS、Retain、Last Will

階層トピックとワイルドカード

MQTTでは、メッセージの行き先を トピック で表します。
トピックは / 区切りで階層化でき、たとえば home/livingroom/temperature なら、「家 / リビング / 温度」という意味をそのまま表せます。
GPIO名を適当に付けると後で配線が読めなくなるのと同じで、トピックも最初の切り方で運用の見通しが変わります。

この階層化が効くのは、購読側でまとめて受け取りたい場面です。
たとえば部屋ごとの温度を全部見たいなら home/+/temperature、家の中のあらゆるトピックを確認したいなら home/# というトピックフィルタを使います。+ は単一階層、# は複数階層に一致するワイルドカードです。
ここでのポイントは、ワイルドカードは購読時だけに使う という点です。
Publish側のトピック名に +# は使えません。

たとえば次のように読むと整理しやすくなります。

フィルタ一致する例一致しない例
home/+/temperaturehome/kitchen/temperaturehome/kitchen/sensor1/temperature
devices/+/statedevices/esp32-01/statedevices/esp32-01/telemetry/temp

ワークショップでも、最初は home/# のような広い購読で様子を見ると流れをつかみやすい一方、そのまま本番設計に持ち込むと必要以上のメッセージを拾ってしまいます。
デバッグ用の広いフィルタと、運用用の狭いフィルタは分けて考えると混乱が減ります。

QoS 0/1/2の違い

QoS(Quality of Service)は、メッセージを どこまで確実に届けるか の約束です。
通信が通ったかどうかをどの段階まで確認するかで、0 / 1 / 2 に分かれます。
ここは名前だけ覚えるより、やり取りの流れで押さえると腹落ちします。

QoS意味主なやり取り向く用途
0至達性ベストエフォート送るだけ高頻度センサー値
1少なくとも1回PUBLISHPUBACK状態通知、一般的な制御
2正確に1回PUBLISHPUBRECPUBRELPUBCOMP重複が困る処理

図で並べると、違いはこうなります。

QoS 0
Publisher  ->  Broker
送信のみ。確認応答なし
QoS 1
Publisher  ->  Broker : PUBLISH
Publisher <-   Broker : PUBACK
少なくとも1回届く。再送で重複する可能性あり
QoS 2
Publisher  ->  Broker : PUBLISH
Publisher <-   Broker : PUBREC
Publisher  ->  Broker : PUBREL
Publisher <-   Broker : PUBCOMP
正確に1回届けるための4段階

実装で迷いやすいのは、「QoSを上げれば全部安心」と考えてしまうところです。
実際には、QoS 2は制御手順が増えるぶんオーバーヘッドも増えます。
温度を1秒ごとに送るような用途なら、古い値が1回欠けても次がすぐ来るので QoS 0 で十分なことが多いです。
一方で、ドア解錠や課金のように重複実行が困る処理では QoS 2 を検討する意味があります。
照明のON/OFFやデバイス状態更新なら、QoS 1 が落としどころになる場面が多いです。

ここで混同したくないのが、QoSは配送保証の話であって、状態保持の機能ではない という点です。
QoS 1 にしたから最新状態が新規購読者に届くわけではありませんし、QoS 2 にしたから再接続後に前回状態が見えるわけでもありません。
その役割は次に出てくる Retain やセッション設定と分けて考えます。

{{product:32}}

Retained/Last Will/Keep Aliveの使い分け

Retained Message(Retainフラグ付きメッセージ)は、そのトピックの最新値をブローカーに保持させる ための仕組みです。
たとえば devices/esp32-01/stateonline{"power":"on"} を Retain付きで送っておくと、新しく購読したクライアントはその時点で最後の状態をすぐ受け取れます。
監視画面を開いた直後に「今どうなっているか」が見えるのは、この機能の恩恵です。
次の更新まで待たなくてよいので、状態同期の見通しが一気に良くなります。

一方で、Retainはイベント列の保存には向きません。
たとえば「ボタンが押された」「人感センサーが反応した」のような一瞬の出来事を Retain にすると、新しく購読した側が古いイベントを“今起きたこと”と誤解しやすくなります。
筆者のワークショップでも、Retainと永続セッションを同じものとして捉えてしまう場面がよくあります。
そこで state だけRetain、telemetryevent は非Retain、という運用例を先に見せると誤解がほどけます。
Retainは「最後の状態を置いておく棚」、セッション永続化は「購読や未配信メッセージを引き継ぐ接続の設定」で、役割が違います。

トピックを分けておくと、この使い分けが明快です。たとえば次のような構成です。

トピック内容Retain
devices/esp32-01/state現在の電源状態、接続状態使う
devices/esp32-01/telemetry温度、湿度、電圧などの観測値基本は使わない
devices/esp32-01/eventボタン押下、エラー発生使わない
devices/esp32-01/cmd制御コマンド使わない

Last Will(Last Will and Testament)は、クライアントが異常切断したときにブローカーが代理で送るメッセージ です。
典型例はオンライン監視で、接続時に devices/esp32-01/stateonline を Retain付きでPublishし、同時に Last Will として同じトピックへ offline を設定しておきます。
すると正常終了ではなく回線断や電源断が起きたとき、ブローカーが offline を流してくれます。
状態監視の基本形としてよく使われる設計です。

Keep Aliveは、接続が生きているかを確認するための間隔設定です。
一定時間データ送信がないと、クライアントは PINGREQ を送り、ブローカーは PINGRESP を返します。
これで無通信時でも接続断を検出できます。
たとえば Keep Alive を 60秒にすると、接続が途切れた場合は 90秒以内にブローカー側で切断扱いになる計算です。
机上ではちょうどよく見えても、Wi-Fiの切替や一時的な詰まりがある環境だと、この数十秒差がオフライン通知の挙動にそのまま出ます。
短すぎると誤検知が増え、長すぎると切断検出が鈍ります。

NOTE

state に Retain、異常切断時の offline は Last Will、接続維持確認は Keep Alive、と役割を分けると整理できます。
ここを1つの機能だと思ってしまうと、再接続時に何が届くのか、切断時に誰が通知するのかが見えなくなります。

トピック命名ベストプラクティス

トピック名は、あとからACL(アクセス制御)や監視、可視化を載せる前提で決めておくと崩れません。
実務で扱いやすいのは、役割ごとに階層を固定する やり方です。
たとえば devices/{deviceId}/telemetrydevices/{deviceId}/statedevices/{deviceId}/cmd の3本に分ける構成なら、読むデータ、現在状態、制御命令が交差しません。
HiveMQのトピック設計解説でも、用途の異なるメッセージを分ける考え方が整理されています。

命名ルールとしては、小文字、スラッシュ区切り、末尾スラッシュなしを基本にすると扱いが安定します。home/livingroom/temperature/ のような末尾スラッシュ付きは、見た目が近くても別トピックです。Home/LivingRoom/Temperature のような大文字混在も、運用が長くなるほど揺れの原因になります。
配列のキー名を途中で temptemperature で混ぜると後で痛いのと同じです。

バージョンを先頭に置くのも有効です。v1/devices/{deviceId}/telemetry としておけば、ペイロード形式やルーティングを変えるときに v2/... を並行運用できます。
IoTではデバイスの入れ替えが一斉に進まないので、この逃げ道があるだけで移行が楽になります。
AWSのMQTT解説やトピック設計ガイドでも、将来の変更を見越した階層設計が勧められています。

トピック名に個人情報を入れない、単位やスキーマをそろえる、という点も見逃せません。
たとえば devices/esp32-01/telemetry に温度を送るなら、ある機器は摂氏、別の機器は華氏、片方だけ temp キーという状態は避けたいところです。
トピック設計とペイロード設計は別物ですが、ここが揃っていないと受信側で毎回変換が必要になります。

現場で詰まりにくい形にすると、たとえばこんなイメージです。

用途
テレメトリv1/devices/esp32-01/telemetry
状態v1/devices/esp32-01/state
コマンドv1/devices/esp32-01/cmd
全デバイス状態の購読v1/devices/+/state

MQTTとHTTPの違いを使い分けで理解する

比較表:MQTT vs HTTP

MQTTとHTTPは、どちらが上位という関係ではありません。
何を、どの頻度で、何台に、どんな応答性で届けたいかで向き不向きが分かれます。
重要なのはこの判断軸です。
IoTの現場では「Webで見慣れているからHTTPで統一する」という選び方をすると、あとでポーリング回数や遅延、回線使用量に悩まされることがよくあります。
筆者の指導経験でも、HTTPで定期ポーリングしていた処理をMQTTに置き換えただけで、回線負荷が目に見えて下がり、操作の返りも待たされにくくなった例が少なくありません。

(比較表内の該当セル) (比較表内の該当セル:ヘッダー長はヘッダー項目・HTTPバージョン・圧縮の有無などで大きく変わるため、数十バイトになる例は「特定条件下の参考例」として記載しています)

| 軽量性 | 高い。
固定ヘッダー最小2バイト | 相対的に重い。
ヘッダーは数十バイトになる例がある(実測値はヘッダー項目やHTTPバージョン、圧縮の有無で変動するため参考値として扱ってください) |

比較項目MQTTHTTP/HTTPS
通信モデルPub/Sub、ブローカー経由のイベント駆動リクエスト/レスポンス
軽量性高い。固定ヘッダー最小2バイト相対的に重い。ヘッダーは50バイト以上の例あり
同期/非同期非同期が中心同期処理が中心
1対1 vs 1対多1対多配信が得意基本は1対1
双方向性常時接続を前提に双方向で流しやすい双方向は補助技術なしでは扱いづらい
常時接続の前提前提になりやすい一回ごとの通信でも成立
クラウドAPI連携のしやすさIoT基盤とは相性がよいREST APIやWebサービス連携に強い
センサー常時送信への適性高いポーリングや頻繁なPOSTでは負担が増えやすい
制御配信への適性高い。購読中の多数端末へ届けやすい個別リクエスト向き

この表を選定の軸にすると、判断がぶれません。
たとえば、温湿度のような小さいテレメトリを数秒ごとに送り続けるならMQTTが自然です。
逆に、設定画面から「この機器の現在設定を取得する」「このリソースを更新する」といったリソース操作はHTTPのほうが頭の中のモデルと一致します。
Webアプリ、REST API、管理画面、認証済みのHTTPSエンドポイントとの連携はHTTPの土俵です。

クラウド連携でも、この切り分けはそのまま使えます。
AWS IoT CoreはAWS IoT Core device communication protocolsで、Secure MQTT、MQTT over WebSocket Secure、HTTPSをサポートしています。
つまり、デバイスからの継続的な送受信はMQTT、バックエンドのAPI連携や一回性の操作はHTTPS、という混在構成が素直です。

なお、比較の座標軸としてはCoAPやAMQPもあります。
CoAPは制約の強い環境向けの軽量通信、AMQPはメッセージング基盤寄りの設計と捉えると位置づけが見えますが、この2つの詳細は本記事の範囲外に留めます。

MQTTが向く3つの場面

MQTTが力を発揮するのは、小さいメッセージを頻繁に流す、双方向でやり取りする、同じ内容を複数の相手に配るという条件が重なる場面です。

  1. センサーの常時送信を続ける場面

    温度、湿度、電力、開閉状態のようなテレメトリを継続的に送りたいなら、MQTTが合います。
    メッセージ1回あたりのオーバーヘッドが小さいので、ESP32のような限られた計算資源でも扱いやすく、回線が細い環境でも組みやすい構成になります。
    LoRaWANのようにデータレートが低い系統を意識する場面では、1メッセージが軽いことの意味がいっそう大きくなります。

  2. デバイスへの双方向制御を入れたい場面

    スマートホームでは「状態を受け取るだけ」で終わらず、「点灯」「停止」「しきい値変更」といった下りの制御も必要になります。
    HTTPでも命令は送れますが、接続中のクライアントにトピック経由で即座に配る構成はMQTTの得意分野です。
    デバイスは telemetry をPublishしながら cmd をSubscribeしておけば、上りと下りを分けて扱えます。
    この構造は、statecmd の分離とも相性がよく、受信側の責務が崩れません。

  3. 1つのイベントを多数へ配信する場面

    「全照明に消灯を配る」「監視ダッシュボード、記録用サービス、アラート処理が同じイベントを受ける」といった1対多の配信はMQTT向きです。
    送信側は1回Publishするだけで、購読している複数の受信側へブローカーがさばいてくれます。
    HTTPで同じことをやると、送信先ごとに個別の呼び出しを組む発想になり、配信先が増えるほど構成が膨らみます。

TIP

「センサー値が数秒ごとに届く」「操作に対して機器がすぐ反応する」「同じ通知を複数の処理が受け取る」という3条件が見えたら、MQTTを候補の先頭に置くと設計の筋が通ります。

HTTP/HTTPSが向く3つの場面

HTTP/HTTPSは、一回ごとの要求が明確で、相手がWeb APIで、結果をその場で受け取りたい場面で強いプロトコルです。
IoTだから何でもMQTT、とはなりません。

  1. クラウドAPIや既存Webサービスとつなぐ場面

    SaaS、Webhook、REST API、認証付きのWebエンドポイントにデータを渡す処理はHTTP/HTTPSが中心です。
    たとえば、デバイス情報を管理APIに登録する、画像アップロードを行う、業務システムのRESTエンドポイントへ結果を書き込む、といった用途ではHTTPのほうが自然に組めます。
    既存のクラウドサービスはHTTPベースのAPIを前提にしているものが多く、ここを無理にMQTTへ寄せる必要はありません。

  2. 設定取得や状態更新など、1回性のリソース操作をしたい場面

    「現在の設定JSONを取る」「この設定値をPUTで更新する」「このエンドポイントを叩いて結果を受ける」といった処理はHTTPの考え方と一致します。
    要求に対して応答が返る流れが明快で、デバッグもしやすく、ブラウザやAPIクライアントとの相性もよいです。
    IoT管理画面や初期設定ツールがHTTPを採ることが多いのはこのためです。

  3. 常時接続を前提にしたくない場面

    機器が必要なときだけ通信すればよい、あるいはイベントがまれで、接続を張り続ける意味が薄いならHTTP/HTTPSが合います。
    ファーム更新の確認、単発の設定送信、インストール時の初回登録のように、都度つないで結果を受け取れれば足りる処理ではHTTPのほうが素直です。
    常時接続の管理、購読、ブローカー設計を持ち込まずに済むぶん、構成の理解も追いやすくなります。

実務では、デバイスのテレメトリと制御はMQTT、管理系APIと外部サービス連携はHTTPという分担が最も収まりよくなることが多いです。
プロトコル選定で迷ったら、「これはイベント配信か、リソース操作か」「1台との対話か、複数台への配信か」「同期応答が必要か、非同期で流せるか」と切り分けると、MQTTとHTTPの境界が見えてきます。

MQTT 3.1.1とMQTT 5.0の違い

機能差分一覧

MQTTの版違いを見るときは、まず通信の土台を同じ絵で捉えると混乱しません。
MQTTではデバイスやアプリが互いに直接つながるのではなく、全クライアントがブローカーに接続します。
送信側はあるトピックにPublishし、受信側はそのトピックをSubscribeします。
どの相手に届けるかはIPアドレスではなくトピックによるルーティングで決まり、配送の中継と振り分けをブローカーが担います。
ここがHTTPの1対1のリクエスト/レスポンスと感覚が違うところです。
AWSのMQTT解説でも、このPub/Subモデルが軽量で疎結合な構成を作れる点として整理されています(AWSのMQTT解説)。

そのうえで、MQTT 3.1.1とMQTT 5.0の違いは、基本モデルを変えるというより、運用時の情報量と制御の細かさを増やしたと見ると理解しやすいです。
3.1.1は2014年に標準化された広く普及した仕様で、5.0は2019年に公開され、現場で困りがちな点に手当てが入っています。

項目MQTT 3.1.1MQTT 5.0実務で効く場面
Reason Code限定的あり接続拒否や購読失敗の理由を追える
User Propertyなしありメタデータをメッセージに添付できる
Session Expiry旧来の管理ありセッション寿命を秒単位で制御できる
Topic Aliasなしあり長いトピック名の送信コストを抑えられる
Request/Response非公式な作り込みが中心Response Topic / Correlation Dataを仕様化非同期でも応答の対応付けがしやすい
Shared Subscription非公表あり複数サブスクライバで受信を分散できる

特に差が出るのがReason Codeです。
3.1.1でも成功・失敗の概念はありますが、5.0では接続、購読、切断などの場面で、失敗理由をより細かく受け取れます。
筆者の現場感でも、デバッグ期間が限られる検証案件ではこの差が効きます。
接続できない原因が認証なのか、権限なのか、トピック指定なのかをログからすばやく切り分けられるため、5.0対応ブローカーを使っている案件では、最初の詰まり方が明らかに変わりました。

User Propertyも地味に効く機能です。
たとえば、同じ devices/{deviceId}/telemetry に流れるメッセージでも、送信元のアプリ版、処理種別、相関IDのような補助情報を本文とは別に持たせられます。
JSONペイロードの中に全部埋め込むより、ルーティングやログ解析の観点で整理しやすくなります。

Session Expiryは、再接続時の振る舞いをきめ細かくしたい場面で差が出ます。
3.1.1ではClean Sessionの考え方が中心で、保持するか捨てるかがやや粗い印象でした。
5.0ではセッションをいつまで残すかを指定できるため、モバイル回線や一時切断が入る環境で扱いやすくなります。

Topic Aliasは、長いトピック設計を採る現場で効きます。devices/site-a/floor-2/room-201/esp32-01/telemetry/temperature のように階層を丁寧に切ると、可読性は上がる一方で、毎回その文字列を送るコストが積み重なります。
5.0では一度送ったトピックに短い別名を割り当てられるので、帯域が細い回線や高頻度送信の場面で無駄を減らせます。

Request/Responseの整理も、HTTPとの橋渡しとして理解すると腑に落ちます。
MQTTは基本的にPub/Subですが、5.0ではResponse TopicとCorrelation Dataが入ったことで、ある要求メッセージに対する応答をどのトピックへ返し、どの要求と対応するかを仕様として表現できます。
つまり、クライアント同士は直接接続せず、どちらもブローカーにぶら下がったまま、トピック経由で疑似的なリクエスト/レスポンスを組めるわけです。

Shared Subscriptionも見逃せません。
1つのトピック群を複数のワーカーで処理したいとき、通常の購読では全サブスクライバに同じメッセージが届きますが、Shared Subscriptionではグループ内のどれか1つに振り分けられます。
イベントを全員に配るPub/Subの性格はそのままに、受信側だけ負荷分散の形へ寄せられるので、バックエンド処理の水平分散と相性が良いです。
ブローカーごとに対応状況は揃っていないため、ここは「5.0対応」と別枠で見たほうが実務的です。

NOTE

MQTT 5.0は「プロトコルの別物」ではなく、ブローカー中心のPub/Subモデルを保ったまま、診断情報、メタデータ、セッション制御、帯域節約、分散受信を足した版として捉えると整理できます。

5.0を使うべきケース/見送るケース

3.1.1と5.0の選び分けは、機能の新しさだけで決めるより、どこで詰まりやすい現場かで判断するとぶれません。
3.1.1は対応範囲が広く、古めのデバイスSDKや既存クラウド連携でも通しやすい版です。
古い組み込み実装やライブラリ資産を生かしたいときは、今でも有力です。

一方で、運用性や拡張性を重視するなら5.0の価値が見えてきます。
たとえば、開発初期は接続エラーの原因を追う時間が増えますし、本番運用に入るとメッセージに付随情報を持たせたくなります。
再接続時のセッション保持、長いトピック名の圧縮、非同期応答の対応付けも、システムが少し育つと欲しくなる要素です。
その意味で5.0は、単なる追加機能ではなく、運用の摩擦を減らす道具が揃っている版です。
仕様の細部はOASISの正式文書で確認できます(『OASIS MQTT 5.0仕様』)。

筆者なら、次のように考えます。
センサー値を送って受けるだけの小規模構成、既存ライブラリとの整合を優先する構成、クラウド側が3.1.1中心で組まれている構成では、3.1.1は今も堅実です。
反対に、検証から本番までを見据え、ログでの切り分け、メタデータ運搬、ワーカー分散、非同期応答の設計までまとめて視野に入れるなら5.0のほうが素直です。

ここでひとつ誤解しやすい点があります。「5.0対応」と書かれていても、全機能が揃っているとは限りません。 ブローカーは5.0接続自体を受け付けても、Shared Subscription、Topic Alias、User Propertyの扱い、Reason Codeの出し方まで同じ水準とは限りません。
クライアントSDK側も同様で、接続は5.0でも一部プロパティの設定APIが薄いことがあります。
『MQTTX』のようにMQTT 5.0 / 3.1.1 / 3.1を明示的に扱えるクライアントを使うと、プロパティの有無を可視化しながら試せるので、学習にも検証にも向きます。

最近の周辺トレンドとしてはMQTT over QUICにも触れておきたいところです。
再接続時の0-RTT/1-RTTや、IP変更を伴う接続移行で利点が期待されており、モバイル回線やローミングをまたぐユースケースでは今後の選択肢になっていきます。
ただし、今日の主戦場はまだTCP上のMQTT 3.1.1と5.0です。

docs.oasis-open.org

実装時の互換性チェックリスト

実装段階で混乱しやすいのは、「ブローカーが5.0」「SDKも5.0」「だから欲しい機能は全部使えるはず」と思って進めてしまうことです。
着眼点はここにあります。
MQTTはクライアント同士が直接つながらず、全員がブローカーを経由するので、片側だけ対応していても期待通りに動かない機能があります。
確認対象は、送信側クライアント、受信側クライアント、ブローカーの3点セットです。

実装前後で見ておきたい項目を整理すると、次の表になります。

チェック項目見る対象確認の観点
MQTTバージョンブローカー / SDK / クライアントツール3.1.1と5.0のどちらで接続しているか
Reason Codeブローカー / SDK接続失敗、購読拒否、切断理由が取得できるか
User PropertySDK / ブローカー送受信時に保持されるか、ログで見えるか
Session ExpirySDK / ブローカー再接続後にセッション継続が期待通りか
Topic AliasSDK / ブローカー送信側設定と受信動作が成立するか
Response Topic / Correlation DataSDK / ブローカー応答の対応付けができるか
Shared Subscriptionブローカー / SDKグループ購読で負荷分散されるか
WebSocket / TLSブローカー / クライアントブラウザ系やクラウド接続の経路に乗るか

さらに、手を動かす順番としては、まず通常のPublish/Subscribeが通ることを確認し、その後で5.0固有プロパティを1つずつ足していく流れが安全です。
最初からSession Expiry、User Property、Response Topicを全部載せると、どこで崩れたのか見えにくくなります。
筆者は検証時、まず素のトピック配信を確認してから、Reason Codeが見える状態を作り、次にUser Property、最後にShared Subscriptionの順で試すことが多いです。
この順だと、ブローカー設定の問題とアプリ側の問題を切り分けやすくなります。

Shared Subscriptionは特に、概念だけ理解してもハマりやすい機能です。
通常のPub/Subでは1回Publishしたメッセージを複数のサブスクライバがそれぞれ受け取りますが、Shared Subscriptionでは同じ購読グループ内の誰か1つが受け取ります。
つまり、ブロードキャストではなくワーカープールになります。
監視ダッシュボード、記録サービス、通知サービスのように全員が同じイベントを必要とする構成には向かず、ジョブ処理や変換処理のように「誰か1台が処理すればよい」役割で使うのが筋です。

実務では、ブローカーにMosquitto、高機能側にEMQX、クラウド統合ならAzure Event Grid MQTT Brokerのように候補が分かれますが、比較表の「MQTT 5対応」を見て安心しないことが大切です。
欲しいのは5.0という看板ではなく、Reason Codeがログで追えること、User Propertyが流れること、Shared Subscriptionが期待通り配分されることだからです。
ここを具体的に見ておくと、HTTPの感覚で「送れば届くはず」と考えたときのズレを減らせます。

まず何を試せばいい?最小構成の始め方

MQTTは概念を読んでいるだけだとつかみにくいので、まずは1本subscribeして、別の端末から1本publishするところまでを最短で通すのが近道です。
筆者がワークショップで進めるときも、最初の到達点はそこに置きます。
ここで1回でも「ブローカーを経由して届いた」が見えると、その後のQoSやRetain、TLSの意味が急に具体的になります。

Step 1: ブローカーを用意

(注:以下で言及する Mosquitto のバイナリサイズ/起動時メモリなどの数値は、配布形式(パッケージ版/ソースビルド)、プラットフォーム(Raspbian / Alpine / Debian 等)、ビルドオプションにより変わります。
数値は環境依存の参考値として扱ってください) 最初の一歩は、受け皿になるブローカーを立てることです。
学習用ならMosquittoが定番で、手元のPCやRaspberry Piにも導入しやすい軽量ブローカーです。
なお、バイナリサイズや起動時のメモリフットプリントは配布形式(パッケージ/ソースビルド)、プラットフォーム(Raspbian / Alpine / Debian 等)、ビルドオプションによって大きく変わります。
したがって「1 MB未満」といった数値は環境依存の参考値として扱い、実際の導入では対象環境でサイズやメモリ使用量を確認してください。
まずローカルで試すなら、Mosquittoを入れてlocalhostで受ける形がいちばん迷いません。

一方で、ローカルに入れずに試したいならクラウドブローカーでも進められます。
会社やチームの検証では、最初からクラウド側に寄せておくと、そのまま外部接続や認証の話につなげやすい場面もあります。
ブローカーが何であっても、ここで見るべき点は同じです。接続先ホスト名、ポート、認証の有無が一致しているかだけをそろえれば、最小検証は始められます。

MQTTの全体像を短く確認したいなら、AWSのMQTT解説(https://aws.amazon.com/jp/what-is/mqtt/がPub/Subの整理に向いています。
ブローカーを中心に送受信する、という構図だけ押さえたら、すぐコマンドに進んで構いません)。

Step 2: Subscribeする

最初の端末では、受信待ちの状態を作ります。Mosquittoのクライアントが入っているなら、たとえば次のように実行します。

mosquitto_sub -t home/livingroom/temperature -q 1

この1行で、home/livingroom/temperature というトピックを購読できます。
ここではQoSを1にしています。
筆者の指導では、まずQoS1で確実に届く流れを見せてからQoS0に落とします。
その順番だと、初心者が「届かなかったのは自分の設定ミスか、QoSの性質か」を混同しません。
最初からQoS0で始めると、一瞬の切断や見落としまで「MQTTは不安定」と受け取りがちです。

トピック名はこの段階では自由ですが、温度なら home/livingroom/temperature のように、場所と値の意味が分かれる形にすると追いやすくなります。
後でESP32やRaspberry Piを足したときも、同じ命名をそのまま流用できます。

Step 3: Publishする

次に、別の端末から同じトピックへ値を送ります。受信側のsubscribeが動いたままの状態で、もう一方の端末から次を実行します。

mosquitto_pub -t home/livingroom/temperature -m 24.3 -q 1

これで、subscribe側に 24.3 が届けば最小構成の検証は成功です。
MQTTの固定ヘッダーは最小2バイトと小さいため、こうした短い値のやり取りでも仕組みの軽さを実感しやすいところがあります。
HTTPのように毎回リクエストを組み立てる感覚ではなく、つながっている相手にイベントが流れる感覚で捉えると理解が進みます。

ここで受信できないときは、まずブローカー自体が起動しているかを見ます。
次に、接続先ポートの競合、ローカルのファイアウォール、subscribe側とpublish側でトピック文字列が1文字でもずれていないかを確認します。
MQTTはトピック名が完全一致で動くので、temperaturetemperatures のような差でも届きません。

Step 4: QoSとRetainの挙動を見る

subscribeとpublishが通ったら、次はQoSとRetainの差を目で追います。
QoSは-qを切り替えるだけで試せます。
まずは先ほどのままQoS1で何回か送り、次にQoS0へ変えて同じ操作をすると、再送や取りこぼしへの考え方が整理しやすくなります。
QoS1では PUBACK を伴う「少なくとも1回」で届き、QoS0は「送るだけ」です。
学習段階では、QoS1で届くことを確認してからQoS0へ落とす順番のほうが、観察ポイントがぶれません。

Retainも同じく手元ですぐ確認できます。次のように -r を付けてpublishします。

mosquitto_pub -t home/livingroom/temperature -m 24.3 -q 1 -r

この状態でsubscribeをいったん止め、あとからもう一度同じトピックを購読すると、ブローカーに保持された最新値がすぐ届きます。
これは「あとからjoinしたクライアントでも最後の状態を知れる」というRetainの本質そのものです。
温度のような連続テレメトリでは多用しませんが、statestatus 系では効きます。

保持を消したいときは、空ペイロードをRetain付きで送ります。

mosquitto_pub -t home/livingroom/temperature -m "" -r

NOTE

Retainは「最後の値を見せたいトピック」にだけ使うと整理しやすくなります。
電源状態や接続状態には向きますが、単発イベントやログ通知に付けると、過去の出来事が現在の状態のように見えて混乱します。

観察の期待値もはっきりしています。
通常publishなら、購読中の端末にだけ届きます。
Retain付きなら、後から同じトピックに参加した端末にも最新値が届きます。
QoSを変えると、到達保証のあり方が変わり、再送や重複の可能性の見え方も変わります。

{{product:32}}

Step 5: ESP32/Raspberry Piから接続

CLIで動きが見えたら、次は実機を1台参加させる段階です。
ここで『MQTTX』を使うと、CLIとGUIの両方で同じトピックを観察できます。
『MQTTX』はEMQのオープンソースクライアントで、Desktop / CLI / Webがあり、MQTT 5.0 / 3.1.1 / 3.1に対応しています。
コマンド派なら mqttx submqttx pub、画面で見たいならGUI版で同じトピックを開く、という流れにすると、どのメッセージがどこへ流れたかを追いやすくなります。
『MQTTX』の公式サイトは の公式サイトは です。

Raspberry Piなら、先ほどのMosquittoクライアントや『MQTTX CLI』をそのまま使って、PCと同じトピックに参加できます。
PCでsubscribeし、Piからpublishするだけでも、ローカルネットワーク上の実機連携になります。

ESP32に進むと、最初の入口はライブラリ経由の接続です。
平文接続なら比較的すぐ通りますが、実運用を見据えるならTLS接続に早めに触れておくと後で困りません。
筆者の経験では、ESP32で最初につまずくのは証明書文字列の扱いです。
実装ではCA証明書をPEM形式の文字列としてコードに組み込む形がよく使われます。
ブローカーのサーバ証明書を検証するために、その発行元CAを端末側へ入れる、という理解で進めると整理しやすくなります。

Step 6: TLSと認証を有効化

平文でpublish/subscribeが通ったら、同じトピックのままTLSと認証を足します。
ここで見るべきものは、暗号化そのものよりも失敗時の挙動がどう変わるかです。
TLSを有効化すると、ホスト名と証明書の名前が合わない、証明書チェーンが足りない、端末時刻がずれている、といった理由で接続前に止まります。
平文では届いていたのにTLSではつながらない、という差が見えれば、何が検証対象なのかが明確になります。

認証の入口としては、ユーザー名・パスワードがいちばん試しやすい形です。
そこからサーバ証明書の検証、さらに必要ならクライアント証明書まで進めると、IoTらしい運用に近づきます。
mqtt.orgmqtt.orgでも、MQTTがTLS上で動作できることは基本事項として整理されています)。

TLSでつながらないときの切り分けは、順番を固定すると迷いません。
まずブローカーがTLSポートで待ち受けているかを確認し、その次に証明書のCNまたはSANと接続先ホスト名が一致しているかを見ます。
さらに端末の時刻がずれていると、証明書の有効期限チェックで止まります。
ESP32やRaspberry Piでは、この時刻ズレが意外と見落とされます。
証明書ファイルばかり見直していて、実際には時刻同期が通っていなかった、という場面は珍しくありません。

ここまで通れば、ローカルPC同士の最小検証から、GUI観察、実機参加、TLS付き接続まで一本の流れで確認できます。
HTTPのAPIテストとは違って、MQTTは「1回送って終わり」ではなく、接続状態とブローカー経由の配送をまとめて見るほうが理解が進みます。
次の段階では、同じ構成のまま devices/{deviceId}/telemetrydevices/{deviceId}/state にトピックを置き換えると、実運用の形に寄せていけます。

ここまで通れば、ローカルPC同士の最小検証から、GUI観察、実機参加、TLS付き接続まで一本の流れで確認できます。
ポイントの押さえどころはここです。
HTTPのAPIテストとは違って、MQTTは「1回送って終わり」ではなく、接続状態とブローカー経由の配送をまとめて見るほうが理解が進みます。
次の段階では、同じ構成のまま devices/{deviceId}/telemetrydevices/{deviceId}/state にトピックを置き換えると、実運用の形に寄せていけます。

mqtt.org

セキュリティ

MQTTは軽量で扱いやすい反面、最初の設定を甘くすると運用が一気に苦しくなります。
ここがポイントです。
通信の軽さと、守りの設計は別物として考えたほうが崩れません。
盗聴や改ざんの対策としては、まずTLSを前提に置きます。
mqtt.orgmqtt.orgでも、MQTTがTLS上で動作できることは基本事項として整理されています。
ローカル検証では平文でも動きますが、デバイスが増えたり、ネットワークをまたいだりする段階では、平文接続のまま残す理由はほぼありません)。

認証は段階を分けて考えると整理できます。
最初に入りやすいのはユーザー名・パスワード認証です。
そのうえで、端末を個体単位で識別したいならX.509クライアント証明書まで進めます。
とくに工場や設備監視のように「誰がつないだか」より「どの機器がつないだか」を厳密に見たい場面では、クライアント証明書のほうが設計の筋が通ります。

ただし、認証だけでは足りません。
認可、つまりACLでトピックごとの権限を切る設計がセットです。
たとえば devices/device-001/state は読めるが、devices/device-001/cmd には書き込めない、という粒度まで落とすと、誤操作や横展開の事故を抑えられます。
筆者の経験では、最初にACLを緩くしすぎると、あとから引き締める作業で現場が止まりがちです。
デバイスIDの名前空間ごとに早い段階でポリシーを切っておくと、新旧デバイスが混在する移行期でも破綻しません。

ネットワーク側の分離も同じくらい効きます。
VLAN、VPC、Firewallでブローカーへの到達経路を絞るだけでも、攻撃面は小さくなります。
IoT機器、管理端末、業務系サーバを同じフラットなセグメントに置くと、1台の設定ミスが全体に波及します。
ブローカーは集約点になるので、通信の中心に置くぶん、防御線も一段厚くしたいところです。

MQTT 5.0を使うなら、接続拒否や切断時の見え方も古い解説より一歩進みます。
Reason Codeがあるので、「認証失敗なのか」「ACL違反なのか」「仕様外のパケットなのか」を切り分けやすくなります。
実装時の注意点として、接続できないときにクライアント側で単に「タイムアウト」とだけ表示して終わりにしないことが挙げられます。
ブローカーのログと突き合わせてReason Codeを見ないと、証明書ミスと権限不足が同じ障害に見えてしまいます。
User Propertyも使えば、業務上のメタデータを載せられますが、トレースIDや発信元種別のような監査向け情報に絞るのが無難です。
個人情報や秘密情報をここへ載せると、ログの取り回しが急に難しくなります。

運用面では、ログとメトリクスの収集を初期構成に入れておくと後が楽です。
接続数、切断理由、再接続頻度、認証失敗回数、Will発行回数が見えるだけで、障害の見つけ方が変わります。
死活監視にはLast Willを使い、state 系トピックと組み合わせてオンライン・オフラインを表現すると、監視画面でも把握しやすくなります。
短時間の瞬断がある回線では、Will Delay Intervalを入れて誤通知を減らす構成も有効です。

{{product:33}}

トピック設計の落とし穴とパターン

トピックは「あとで決めればいい」と思われがちですが、実運用では先に型を決めたほうが楽になります。
とくに効くのが、所有権ベースの命名です。devices/{deviceId}/... のように、先頭近くで誰のトピックか分かる形にしておくと、ACLとぴったり連動します。
トピック設計と認可設計を別々に考えると、途中でねじれます。

実務では、制御用の cmd と状態用の state を分けるのが基本です。
たとえば devices/device-001/cmd に「on」を送り、実際の反映結果は devices/device-001/state で受ける、という流れです。
この分離がないと、要求と結果が同じ流れに混ざり、障害時に「送ったのか」「反映されたのか」が追えなくなります。
MQTT 5.0ではRequest/Responseの考え方が仕様として整理され、Response TopicやCorrelation Dataを使えます。
双方向の制御を厳密に扱いたいなら、この仕組みを使って「要求」と「応答」を明示的に分けたほうが混乱が少なくなります。

User Propertyもこの文脈で役立ちます。
たとえば操作元アプリの種別やトレース用の識別子を載せると、同じ cmd でもどこから来た操作か追えます。
ただし、意味のあるメタデータだけに絞るほうが運用は安定します。
何でも載せ始めると、サブスクライバ側の条件分岐が増え、結局トピックとプロパティの責務があいまいになります。

ワイルドカード購読の影響範囲にも注意が必要です。devices/+/telemetry は便利ですが、対象が増えるほど1本の購読に流れ込む量も増えます。
台数が少ない検証では快適でも、フリート運用に入ると監視用クライアントがボトルネックになります。
このとき有効なのがShared Subscriptionです。
複数のコンシューマで購読を共有し、負荷を分散させることで、単一プロセスへの集中を避けられます。
イベント集約やルールエンジン連携の前段で、とくに効く考え方です。

トピック名そのものも帯域や可読性に影響します。
長い名前は人間には親切ですが、頻繁に流れると積み重ねが効いてきます。
MQTT 5.0のTopic Aliasを使うと、最初に長いトピック名を送ったあと、以降は別名で省略できるので、帯域を節約できます。
低帯域回線や小さなデバイスでは見逃しにくい差です。
もっとも、実装時の注意点として、Topic Aliasを使う前提で設計するなら、クライアントとブローカーの両方がきちんとMQTT 5.0のやり取りを処理できることが前提になります。
古いライブラリや設定では、このあたりが抜け落ちます。

セッション管理もトピック設計と切り離せません。
Session Expiryをどう置くかで、再接続時に未配送メッセージを引き継ぐのか、その場限りにするのかが決まります。
クライアントIDが毎回変わる実装だと、Session Expiryを設定しても狙ったセッション継続になりません。
筆者が初心者向けの検証でよく見るのは、再起動のたびに別クライアント扱いになって「キューが残らない」「購読が復元されない」と悩むパターンです。
クライアントIDは固定し、Session Expiryの方針とセットで考えるほうが筋が通ります。

NOTE

cmd は要求、state は現在値、telemetry は観測値、event は単発通知、と役割を分けておくと、ACL、Retain、Will、監視画面の設計まで一貫します。

ブローカー選定

(注:ブローカーの起動イメージやメモリ使用量に関する「1 MB未満」などの表現は、配布形態やプラットフォーム、ビルド設定によって変動するため、環境依存の参考値として読み替えてください) ブローカー選びは、機能表だけで決めるより、規模と運用体制から逆算したほうが失敗が少なくなります。
小規模構成や学習用途ならMosquittoが定番です。
参考として「軽量である例」が報告されていますが、実際の起動イメージやメモリ使用量は配布形態やプラットフォーム、ビルド設定で変わるため、1 MB未満という数値は環境依存の参考値にとどめ、対象環境での確認を推奨します。
設定ファイルも追いやすく、まず1台でPub/Sub、Retain、Will、ACLを試したい段階と相性がいいです。

一方で、接続数や機能要件が増えるならEMQXやHiveMQのような高機能ブローカーが候補に入ります。
EMQXは起動フットプリントが約50 MBという参考値で、Mosquittoより重いぶん、クラスタリングや大規模運用向けの機能を持たせやすい構成です。
接続のさばき方、認証連携、ルール処理、監視基盤との結合まで見据えるなら、この手の製品が現実的です。

クラウド統合を重視する場合は、マネージド型にも目を向けたいところです。
Azure Event Grid MQTT BrokerやAWS IoT Coreは、周辺サービスと結びつけやすいのが強みです。
たとえばクラウド側でイベント処理、認証基盤、証明書管理、監査ログをまとめて扱いたい場合、自前でブローカーを立てるより設計が素直になります。
Microsoft Learn MQTT Broker OverviewMicrosoft Learn MQTT Broker Overviewを見ても、MQTT v3.1.1とv5の対応、QoS、Retain、クラウド連携の方向性が整理されています)。

選定時に見落とされやすいのは、対応バージョンと運用機能です。
MQTT 5.0対応と書かれていても、Reason Code、User Property、Session Expiry、Topic Alias、Request/Response、Shared Subscriptionを実際にどう使えるかで運用の幅が変わります。
学習段階では「つながるか」が中心ですが、本番では「詰まったときに何が見えるか」「分散処理へ広げられるか」が効いてきます。

実装時の注意点として、ブローカー単体の性能より、周辺要素との組み合わせで詰まる場面が多いです。
TLS終端をどこで持つか、ACLをファイルで持つか外部認証に寄せるか、セッションを永続化するか、Last Willを監視系へどう流すか、こうした選択で挙動が変わります。
とくにSession ExpiryとクライアントID管理は運用事故の温床になりがちです。
デバイス交換時に同じIDをどう扱うか、再接続時に前のセッションを残すか切るかを決めていないと、メッセージの取りこぼしや意図しない引き継ぎが起きます。

MQTT (PubSub) ブローカー - Azure Event Gridlearn.microsoft.com

ベンチマーク値の読み方と注意

ベンチマーク値は注釈(測定条件)なしに引用すると誤解を招きます。
たとえば公表された事例では「16 B ペイロード、QoS1、特定ハードウェア構成で最大279,949 msg/s」といった測定条件が付されていることが多く、これらの条件を変えると結果は大きく変わります。
記事中でベンチマークを示す際は「特定条件下の計測例である」旨を明記し、可能なら出典 URL と測定条件(payload 長、QoS、TLS の有無、クライアント数、ハードウェア)を脚注として添えてください。

(脚注テンプレート例)出典: Azure IoT ベンチマーク — 条件: payload=16 B、QoS=1、TLS=無、クライアント数=N、測定日時=YYYY‑MM‑DD、URL=<出典URLをここに記載>

初心者がつまずきやすいのは、「publish性能」と「end-to-endの実効性能」を同じものとして見ることです。
ブローカーに受け入れられた件数が多くても、実際のサブスクライバに均等に届くか、ACLや永続化を入れた状態で維持できるかは別の話です。
QoS 1ならPUBACKの往復が入り、セッション保持があると再接続時の配送も絡みます。
つまり、単純なメッセージ毎秒だけでは運用の体感に直結しません。

ここで役立つのが、自分の条件で測ることです。
『MQTTX』にはbenchコマンドがあり、publishやsubscribeの負荷を試せます。
学習用クライアントとしてだけでなく、Topic AliasやSession Expiryを含むMQTT 5.0の挙動確認にも使えるので、机上の比較で止まりません。
ローカルで1台のMosquittoを立てたときと、TLS付きでクラウドブローカーへ流したときでは、ボトルネックの場所がまるで違うと分かります。

ベンチマーク値を見るときは、少なくとも次の観点を揃えて読むと混乱しません。

観点何を見るか読み違えやすい点
ペイロード長何バイトのデータか小さい payload の結果をそのまま実データ量へ当てはめる
QoS0 / 1 / 2 のどれかQoS 0 の数値を QoS 1 の用途に持ち込む
セキュリティTLS の有無平文の結果を本番想定と混同する
配送形態購読者数、Shared Subscription の有無publish 側の値だけ見て購読側の負荷を見落とす
セッションSession Expiry、永続化設定再接続や未配送のコストを計算に入れない

数値の迫力より、条件の整合を読むほうが実装では効きます。
小さなESP32、Raspberry Pi、クラウドブローカーが混在する構成では、1か所だけ速くても全体は速くなりません。
ブローカー選定でも性能比較でも、Reason Codeで障害を切り分けられるか、Last Willで死活が取れるか、Session Expiryを含めた再接続が破綻しないか、といった運用の観点まで含めて読むと、古い解説だけでは拾えない差が見えてきます。

関連記事Home Assistant 始め方|導入先の選び方と初手順Home AssistantはAIスピーカーではなく「ローカル中心の統合基盤」。Raspberry Pi・専用機・Mini PCの3択で導入先を選び、初期セットアップと最初の自動化までを理解できます。Matter/Threadの整理やセキュリティ運用も網羅。

よくある質問

MQTTはインターネット必須か?

いいえ。
『MQTT』はインターネットがなくても、同じLAN内にブローカーとクライアントがいれば動きます。
たとえば自宅のRaspberry PiにMosquittoを立て、同じWi‑FiにつながったESP32から温度データを送る構成なら、外部クラウドなしで完結します。
クラウド接続は「遠隔監視したい」「外出先から操作したい」といった要件が出たときに追加すればよいものです。

ワークショップでも、最初はローカルブローカーでつなぎ、動作確認が取れてからAWS IoT CoreやAzure系サービスへ広げる流れにすると、切り分けが一気に楽になります。AWSのMQTT解説でも、MQTTは軽量なPub/Subとして説明されており、インターネット専用プロトコルではありません。

ブラウザから扱いたい場面では、MQTT over WebSocketも選べます。
社内ネットワーク越しやWeb画面との連携で便利で、AWS IoT Core device communication protocolsでもMQTTとWSSの併用が整理されています。

HTTPより必ず優れているのか?

筆者の現場でも、デバイス制御はMQTT、管理画面からの設定保存やユーザー管理はHTTPという分担に落ち着くことが多いです。
ここでの要点は、通信の性格で分けることです。
どちらか一方に寄せるより、イベント配信かリソース操作かで判断してください。

一方で、リソース指向のAPIを呼ぶ、認証付きのWebサービスへ明示的にPOSTする、既存の業務システムとRESTでつなぐ、といった場面ではHTTPのほうが構成になります。
読者が迷ったときは、「イベント配信ならMQTT、API連携ならHTTP」と考えると判断しやすくなります。

筆者の現場でも、デバイス制御はMQTT、管理画面からの設定保存やユーザー管理はHTTPという分担に落ち着くことが多いです。
どちらか一方に寄せるより、通信の性格で分けたほうが構成に無理が出ません。

ブローカーはデータベースか?

いいえ。
ブローカーはメッセージの配送ハブであって、長期保存を主目的にしたデータベースではありません。
Retainで「最後の状態」を持たせたり、セッションや未配送メッセージを扱ったりはできますが、それは運用のための保持であって、分析用の履歴蓄積とは役割が違います。

この誤解は本当によくあります。
筆者が現場で何度も見てきたのは、「ブローカーに流れているからログも残っているはず」と考えて詰まるケースです。
あとから温度推移を見たい、設備停止の前兆を追いたい、異常発生時刻を月単位で比較したい、となった瞬間に配送基盤だけでは足りません。
ログや時系列データは別のDBやストレージへ送る設計にしておくと、あとで困りません。

WARNING

ブローカーは「届ける役」、DBは「残して検索する役」と分けると設計の判断がぶれません。
状態同期にはRetain、履歴分析には時系列DBという切り分けが実務では安定します。

QoS 2は常に必要か?

多くのIoTではQoS 1で足ります。
QoS 2は「重複も欠落も避けたい」場面のための仕組みですが、そのぶんやり取りが増えます。
照明の点灯状態通知、温湿度の定期送信、設備の稼働フラグといった一般的な用途では、QoS 1の「少なくとも1回」で十分なことが多いです。

QoS 2を選ぶべきなのは、重複がそのまま業務事故になるケースです。
たとえば二重計上や重複登録がそのまま困る処理なら検討する価値があります。
ただ、IoT機器の制御はアプリ側で冪等に設計できることも多く、QoS 2に頼らなくても安全にできます。
たとえば「ONをもう一度受けても状態はONのまま」という形にしておけば、QoS 1でも扱いやすくなります。

筆者は初心者向けの構成では、まずQoS 1を基準に組みます。
そのうえで、重複受信したら何が壊れるのかを洗い出し、本当に必要な経路だけQoS 2へ上げるほうが失敗が少ないと感じています。

{{product:32}}

IoTでの実例は?

典型例は、センサーのテレメトリ送信です。
ESP32や産業用ゲートウェイが、温度・湿度・電流値・開閉状態をブローカーへ送り、ダッシュボードや監視サービスがそれを購読します。
Pub/Subなので、送信側は受け手の数を意識せずに済みます。

スマートホームでも相性がよく、照明、エアコン、スマートプラグ、ドアセンサーを同じブローカー配下でつなぐ構成は珍しくありません。
たとえば devices/livingroom-ac/state で状態を受け、devices/livingroom-ac/cmd に制御を送ると、状態同期と操作を分けて扱えます。
新しく参加したクライアントがRetainされた状態を受け取れると、画面を開いた直後から現在値を表示できます。

工場や設備監視では、モーター温度、振動、異常停止通知の配信に向いています。
ブローカーが中継するので、監視画面、アラート処理、記録基盤を疎結合に保てます。
ブラウザ画面で監視したい場合はMQTT over WebSocketを使うと取り回しがよくなります。
『Microsoft Learn MQTT Broker Overview』のようなクラウド実装でも、その方向性が確認できます。

Share This Article

中村 拓也

大手メーカーで組込みシステムの開発に15年従事。Arduino・Raspberry Piを活用した自作IoTデバイスの制作実績多数。電子工作の基礎から応用まで、実務経験に基づいた解説を得意とする。