Try EMQX Platform on Azure, Enjoy AI Integration and Simplified Billing →

MQTTでファイル転送:ワン・プロトコルで簡単に大容量ペイロードを送信

Andrew
Aug 28, 2023
MQTTでファイル転送:ワン・プロトコルで簡単に大容量ペイロードを送信

IoTにおけるファイル転送の課題

MQTTは、軽量なパブリッシュ/サブスクライブメッセージングのために設計されたプロトコルであり、多くのクライアントライブラリやサーバ実装で広くサポートされています。コードフットプリントが小さく、デバイスの機能が制限されているIoT(Internet of Things)のコンテキストなどの制約された環境にとって完璧なプロトコルです。MQTTのモデルとプリミティブはシンプルで理解しやすく、プロトコル自体は非常に強力で柔軟です。そのため、ほとんどのIoTアプリケーションのニーズを満たすことができます。

しかし、MQTTプロトコルだけでは不十分なデバイスとユースケースがいくつかのクラスには存在します。工場の品質保証パイプラインの一部である産業用カメラを想像してみてください。このカメラは、製品の高解像度画像を撮影し、さらなる処理のためにそれをサーバーに送信する必要があります。また、時折クラウドにロギングおよびテレメトリデータを送信する必要がある車両があります。スマートホームデバイスは、ビデオストリームを解析サービスにアップロードする必要がある場合もあります。これらのすべてのケースで、MQTT標準には大きなペイロードを転送するための確立された方法がなく、デバイスは通常、HTTPS(S3など)やFTPなど、その目的を念頭に置いて設計された他のプロトコルに依存することを強いられます。

これは理想的ではありません。デバイスが複数のプロトコルと通信チャネルを維持する必要があるため、システムの複雑さが増します。追加のプロトコルを実装し、個別の認証と認可のメカニズムをサポートし、それらを機能させるための補助のネットワークとクラウドインフラを維持するために、多くのエンジニアリング努力を費やす必要があります。それらのプロトコルは、MQTTと同じ制約を念頭に置いて設計されていないことも多いと言えます。例えば、S3のほとんどの実装では、クライアントが少なくとも5 MiBのチャンクでファイルを送信する必要があります。これは、制約されたデバイスがネットワーク経由でバッファリングおよび送信するには多くのデータです。

EMQXにおけるMQTTを介したファイル転送

MQTTには柔軟性が高いことを考えると、これらのユースケースを念頭に置き、シンプルなファイル転送メカニズムでそれを拡張することにしました。設計時にいくつかの目標がありました。

  • 多様なデバイスとプラットフォームで実装が容易になるよう、シンプルで使いやすい必要がある。

  • 最大数ギガバイトの大きなペイロードを転送できる必要がある。

  • ネットワークの問題が転送に影響を与えないよう、信頼性の低いネットワークで使用できる必要がある。

  • メモリ使用量が最小限である必要があるため、制約のあるデバイスで使用できる。

この取り組みの結果が、MQTT over File Transferプロトコルであり、これは現在EMQX Enterprise 5.1リリースで利用できます。このブログ記事では、プロトコルの詳細と、その実際の使用方法を説明します。

設計の詳細

ファイル転送プロトコルは、可能な限りシンプルに設計されており、MQTTプロトコルの自然な拡張です。MQTT 5.0仕様に基づいており、ベースプロトコルと同じプリミティブを使用します。このプロトコルをサポートするには、デバイスは特別なトピックと、フィードバックを提供するPUBACKパケット内の理由コードについてのみ知っている必要があります。一般に、デバイスは特別なトピックに発行されるコマンドのメッセージを送信し、ブローカーから応答としてPUBACKパケットを待つ必要があります。このPUBACKには、ブローカーがコマンドを正常に処理したかどうかを示す理由コードが含まれます。ただし、これは厳密な要件ではなく、一部のダムデバイスはフィードバックを無視してコマンドをブラインドで送信することを選択する場合があります。

ファイルはセグメントに転送され、各セグメントは個別のコマンドとして送信されます。ブローカーは、セグメントのサイズに対して境界を強制せず、デバイスは任意の便利なサイズを選択できます。セグメントのサイズは同じである必要はありません。デバイスは任意の順序でそれらを送信したり、同じセグメントを複数回送信することができます。ブローカーは、これらのすべてのケースを正しく処理し、サーバ側でファイルを再構成する必要があります。1

さらに、ブローカーはデバイスが1セッションで転送を完了することを要求しません。デバイスは、いつでも切断してから再接続し、中断した時点から転送を再開できます。または最初から再開することもできます。それが機能するために、ブローカーはデバイスに各転送に一意のファイルIDを割り当てることを要求します。デバイスは、各コマンドでこの識別子を送信する必要があり、異なる転送には再利用してはなりません。

すべてのセグメントが送信されたら、デバイスは転送が完了したことを示す特別なコマンドを送信する必要があります。その後、ブローカーはファイルを組み立て、ダウンロード用に利用できるようにします。さまざまな統合シナリオに対応するために、構成に応じて、EMQXはファイルをローカルファイルシステムに保存するか、クラウドストレージにアップロードするかを選択できるため、その複雑さをデバイスから隠すことができます。

Protocol flow outline

プロトコルフローの概要

ユースケース:産業用カメラの高解像度画像の転送

はじめにの例から、産業用カメラのユースケースを使用して、このファイル転送プロトコルを実装してみましょう。コンベアから出てくる製品の画像をカメラが撮影し、それをQACAM/20230707/PC123456.jpgというファイルに保存したとします。今、このファイルをさらなる処理のためにブローカーに送信する必要があります。カメラはブローカーに既に接続されており、テレメトリデータを送信しているとします。したがって、MQTT接続は既に確立されています。ここでは、ハッピーパスのみを考慮し、エラーケースは扱いません。後でそれについて戻ります。

カメラとEMQX間の対話を示すために、mqttx-cliを使用します。

開始の段階

まず、カメラは一意のファイルIDを選択する必要があります。ランダム数ジェネレータにアクセスできると仮定すると、カメラはUUIDを生成できます。この転送の場合、0d7cd07cc4cf4a0ab072259297f4e41bを選択したとします。

その後、テレメトリデータに使用しているのと同じMQTT接続を使用して、カメラは転送を開始するコマンドをパブリッシュします。

$ mqttx-cli pub -h broker.emqx.io \
    --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/init' \
    --qos 1 \
    -m '{
    "name": "QACAM_20230707_PC123456.jpg",
    "size": 1234567,
    "user_data": {"pipeline": "QA42"}
}'

ここで、カメラはファイルに関するメタデータ(ファイル名、サイズ、転送に関連付ける追加のユーザデータなど)を含むJSONペイロードを送信しています。必須のフィールドはファイル名のみです。それ以外はオプションです。EMQXは、このメタデータを保存し、転送が完了した後にそれに興味のある誰にでも利用可能にします。

カメラは、initファイル転送コマンドを表す特別なトピックにこのメタデータをパブリッシュしています。さらに、このファイル転送に関連するすべてのコマンドは、$file/0d7cd07cc4cf4a0ab072259297f4e41b/で始まるトピックにパブリッシュする必要があります。これは、これらのコマンドが同じファイル転送に関連していることをブローカーが認識する方法です。

EMQXはファイル名に任意のディレクトリ階層を許可せず、コマンドにスラッシュが含まれている場合はそれを拒否します。そのため、ファイルの名前はQACAM_20230707_PC123456.jpgになりました。

最終的にブローカーは、Reason Code 0(Successを意味する)を含むPUBACKパケットで応答します。カメラは今、セグメントの送信を開始できます。

セグメントの送信

1.2 MiBの大きなファイルを持っているカメラは、それを10セグメントの128 KiBに分割することにしました。その後、各セグメントを個別のコマンドとして送信します。

$ mqttx-cli pub -h broker.emqx.io --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/0' --qos 1 -m '<bytes 0-131072>'
$ mqttx-cli pub -h broker.emqx.io --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/131072' --qos 1 -m '<bytes 131072-262144>'
$ mqttx-cli pub -h broker.emqx.io --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/262144' --qos 1 -m '<bytes 262144-393216>'
...
$ mqttx-cli pub -h broker.emqx.io --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/1179648' --qos 1 -m '<bytes 1179648-1234567>'

各コマンドのトピック名には、セグメントのファイル内のオフセットが含まれ、メッセージペイロードはセグメントそのものです。最終的にブローカーは、対応するセグメントが正常に保存されたことを意味するReason Code 0を含むPUBACKパケットで応答する必要があります。

カメラは、ネットワークの輻輳や切断後の再接続などを考え、転送の最中にセグメントのサイズを変更することもできます。単に異なるサイズのセグメントを送信するだけで、EMQXはそれを正しく処理します。たとえクラスタ内の別のノードに再接続したとしてもです。

ここでは、再接続後、カメラは残りのセグメントを32 KiBのチャンクで送信することにしました。

$ mqttx-cli pub -h broker.emqx.io --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/262144' --qos 1 -m '<bytes 262144-294912>'
$ mqttx-cli pub -h broker.emqx.io --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/294912' --qos 1 -m '<bytes 294912-327680>'
...
$ mqttx-cli pub -h broker.emqx.io --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/1179648' --qos 1 -m '<bytes 1212416-1234567>'

以前と同様に、ブローカーはReason Code 0を含むPUBACKで応答します。

転送の完了

すべてのチャンクが送信されたら、カメラは転送が完了したことを示す最後のコマンドを送信します。

$ mqttx-cli pub -h broker.emqx.io \
    --topic '$file/0d7cd07cc4cf4a0ab072259297f4e41b/fin/1234567/1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' \
    --qos 1 \
    -m ''

このコマンドのトピック名には、ファイルサイズとファイルコンテンツのSHA-256ハッシュが含まれています。これは必須ではありませんが、ブローカーがファイルが正しく転送されたことを検証できるようにします。

ファイルサイズとこれまでに送信されたすべてのセグメントの知識を持つEMQXは、ファイルの組立てを開始できます。ファイルサイズ、セグメント数、クラスター全体への分散方法、ファイルの最終的な宛先(ローカルストレージ、S3バケットなど)によっては、組立てに長い時間がかかる可能性があります。ブローカーがファイルを組み立て、ファイルコンテンツのSHA-256ハッシュがカメラが送信したものと一致すると、ブローカーは再びReason Code 0を含むPUBACKパケットで応答します。

おめでとうございます!ファイルは転送され、さらなる処理のために利用可能になりました。EMQXの構成に応じて、ファイルはローカルに保存されるか、S3バケットにアップロードされます。

レガシークライアント

例のカメラが、MQTT 5.0をサポートしていないレガシークライアントの場合、ファイル転送プロトコルを使用できますが、PUBACKパケットにReason Codeがないため、フィードバックがないというコストがかかります。カメラは、各コマンドがブローカーによって受信および正常に処理されたと想定し、切断の場合はそれらを再試行するか、ユースケースの要件に応じて転送を完全に放棄する必要があります。

プロトコルの詳細をさらに探るには、クライアントとブローカーの要件と期待、エラー処理戦略を理解するためにEIP: MQTTを介したファイル転送を参照してください。

まとめ

EMQXエンタープライズ5.1でファイル転送機能の初期バージョンがリリースされました。現在も積極的に開発が進められており、さらなる改善を加えています。ぜひお試しいただき、フィードバックをお寄せください。

始めるにあたって、操作と設定を説明したドキュメントをご用意しました。さらに、様々なプログラミング言語とMQTTライブラリを使用したデモクライアントアプリもご用意しています。

EMQX Enterprise を無料トライアル
任意のデバイス、規模、場所でも接続可能です。
Get Started →

  1. ただし、デバイスが誤動作していると思われる場合、ブローカーはいくつかのアクションを実行する場合があります。 例えば、1つのファイルに対してデバイスが送信できるセグメントの総数を制限したり、奇妙な順番でそれらを送信した場合はデバイスの接続を切断したりすることが考えられます。