MQTTの運用や設計について気になった点のメモ
IoT機器等で使用されるPub/Sub型プロトコル、MQTT。運用や設計についてのノウハウが気になるところです。
本記事は、MQTTの運用や設計に関して気になった点を調べた際のメモです。今後調べ直す機会があれば更新するかもしれません。
参考として、MQTTブローカーのMosquitto導入についてこちらの記事にまとめてあります。
本記事の目的
- MQTTの運用や設計に関する調査状況をメモしておく。
MQTTの構成と実装
MQTTを使用するシステムは、MQTTクライアント(Subscriber、Publisher)と、MQTTブローカーから構成されます。
フリーソフトやライブラリ、あるいはクラウドサービスとして、多くのMQTTの通信機能(ブローカー、クライアント)の実装があります(参考)。
IoT機器やそのゲートウェイ製品としても、MQTTによる通信を想定したものが多いです。
余談ですが、監視ソフトウェアのZabbixは、Zabbix Agent 2においてMQTTのSubscriberとして動作し取得したデータをZabbixサーバに送信する機能があります(機会があれば別途記事を掲載します)。
MQTT動作状況の確認
本記事では、私が気になった点として、仮に、とあるシステムがMQTTを使用して動作中であるとして、その動作状況を把握したいケースを考えてみます。
どんなMQTTクライアントがいるかの確認
どんなMQTTクライアント(Publisher、Subscriber)が動作しているのか、確認する方法について調べた範囲でメモしておきます。
- Subscriberとしては、受信したメッセージ自体には、どのPublisherから送信されたものかの情報は無い。
- 設計として、どのPublisherから送信されたものかを識別するための情報をメッセージに含めることは可能。
- ただし、全MQTTクライアントの接続状況を把握したい場合は、全MQTTクライアントが必ずPublishするよう設計が必要。
- 接続中のMQTTクライアントを管理する用のトピックを作成するといった手法も。
- 各MQTTクライアントが接続時にトピック
status/(クライアントID)
にPublishし、管理する側はstatus/#
(#はワイルドカード指定)をSubscribeしておく(参考)。
- 各MQTTクライアントが接続時にトピック
- 設計として、どのPublisherから送信されたものかを識別するための情報をメッセージに含めることは可能。
- MQTTブローカーとしては、MQTTクライアントからクライアントID(thingId的なもの)を含むパケットを受信している。
- MQTTブローカーの実装次第だが、基本的にはデバッグログや、少なくともネットワークトレースから通信しているクライアントIDを確認可能。
- Mosquittoのデバッグログの例はこちらの記事にあり。
- TLS通信の中身を見る場合は復号化も必要。
- クライアントIDから、それがどのデバイスかを識別できるかどうかは設計次第。
- 予めデバイスごとのクライアントIDを決めておき、その通りに各デバイスを設定しMQTT通信させる。
- デバイスごとのユニークな値(MACアドレス等)を予め把握しておき、各デバイスがその値をもとにクライアントIDを自動生成しMQTT通信させる。
- ただ、IoTは自律的に動作しスケールできる方が良い場面も多そうなので、このあたりは自動化しやすい方式を要考慮(何かあるだろう)。
- MQTTブローカーの実装次第だが、基本的にはデバッグログや、少なくともネットワークトレースから通信しているクライアントIDを確認可能。
以下のLWT機能は、MQTTクライアントを把握するための方法ではないですが補足として記載します。
- MQTTにはLWT(Last Will And Testament)、”遺言”的な意味の機能あり。
- MQTTブローカーは、意図しない原因でPublisherと通信できなくなった場合に、予めLWTに指定されたメッセージをSubscriberへ送信する。
- LWT機能を使用する場合、LWTメッセージはMQTTクライアントからのCONNECTメッセージ内で指定される。
- OASISの文書内の”3.1.3.2 Will Properties”などに記載あり(“LWT”とは書かれていない)。
- LWTの動作説明は、mqtt.orgのFAQから参照可能(HiveMQの説明ページへのリンク)。
アクティブなトピックの確認
次に、どんなトピックのやり取りがされているのか、リアルタイムで確認する方法について調べた範囲でメモしておきます。
- MQTTとしては、アクティブなトピックの一覧を取得する方法自体は無さそう。
- MQTTクライアントで全トピックをサブスクライブし続けることで、実質的にアクティブなトピックを可能(参考)。
- Mosquittoでの実行例
mosquitto_sub.exe -h (MQTTブローカー) -t "#" -d
- -t “#”で全トピックを指定しサブスクライブ。-dにてデバッグ表示。全トピック(#)にPUBLISHされたメッセージを受信する。
- 上記コマンド実行時のメッセージ受信例:
Client null received PUBLISH (d0, q0, r0, m0, 'test/Topic1', ... (77 bytes))
- Mosquittoでの実行例
- その他、ネットワークトレースの取得等。
管理用トピック($SYSなど)
MQTTの動作状況を把握に役立ちそうな、管理用トピック(トピック名が$から始まるもの)というものがあるようです。ただ、細かく標準化はされていないようで、各ブローカーの実装次第のように思われます。
以下、Mosquittoでの確認例です。
`"c:\Program Files\mosquitto\mosquitto_sub.exe" -h (MQTTブローカー) -t "$SYS/broker/clients/active"` 2
上記の例では、アクティブなクライアント数が2であることが確認できます。
MQTTのトピック設計(メモ)
いくつか参考URLを記載します。
- AWS IoT Core の MQTT トピックの設計
AWSによるベストプラクティスの解説ホワイトペーパー(PDFへのリンクあり)。 - 参考サイト1
- 参考サイト2
以下、トピック設計に関するメモです。
- トピック名は”/”で区切られた階層構造
- 例:france/office/3F/temp、japan/factory/6F/humid
- ある区域内のデータは1つのトピックにして、その中で細分化する等も
- ワイルドカードサブスクリプション(#)の活用
- 以下AWSドキュメントのベストプラクティスより引用+メモ
- MQTT トピックレベルでは、小文字、数字、ダッシュのみ
- MQTT 経由でデバイスとして接続するための MQTT クライアント ID として AWS IoT のモノの名前を使用する
- MQTT メッセージのペイロードに、特定のメッセージに関する追加のコンテキスト情報を含める
(場合によっては、クライアントIDをペイロードに含めても良いかも) - テレメトリとコマンド(温湿度情報はテレメトリ、機器の制御などはコマンド)
- 複数データのトピックをどのようにまとめるか
- 1トピックに複数のデータを(JSON等で)まとめて送るかどうか。
- 温度トピック、湿度トピックのように、各データでトピックを分ける方法が基本と思われる。
- 同時に取得されたデータをまとめてセットで送受信することが重要なデータはまとめても良いかも。
- 1トピックに複数のデータを(JSON等で)まとめて送るかどうか。
- MQTTのトピック名の変換機能
- そのような機能は見当たらない。以下、メモ程度。
- 例えば、複数のセンサー(Publisher)が、同一トピックにPublishする構成の場合に、ブローカー側でPublisherごとにトピック名を変換(自動振り分け)し、Subscriberが各センサーごとにトピックを分けてデータ受信したりすることができたら便利かも。
- 参考:トピック名の変換が可能なMQTTブリッジ(詳細は未確認、クライアントIDを埋め込むことはできなさそう)