概要
この記事は、IoTゲートウェイに入っているmosquittoのブリッジ機能を利用し、SORACOM Beam経由でIoT Coreのエンドポイントにデータを送信するためにmosquittoで設定した内容まわりについて記録することを目的としています。そのため、他の構成要素の基本的な部分については以下で簡単に説明するにとどめます。
mosquittoのブリッジ機能
mosquittoは主にブローカーやpub/subツールとして使われることが多いかと思います。ブリッジ機能も本質的にはそれと大差ない動きをします。データをブリッジ=あるデータを、本来目指したい場所(リモートブローカー)に橋渡しするような役目を果たします。
こちらの記事にブリッジ機能について図つきで細かく解説されており理解の助けになりました。ありがとうスティーブさん。
Mosquitto MQTT Bridge-Usage and Configuration
SORACOM BeamとAWS IoT
SORACOM Beamはデータの転送と暗号化をクラウドで行う機能です。MQTTS通信のために必要なX509証明書は本来証明元となるローカルデバイスで持つ必要がありますが、SORACOM Beam経由の場合はクラウド管理で証明書とデバイスを紐づけることができます。
SORACOMを経由せずにAWS IoTへデータをブリッジする場合について公式の以下の記事があります。
ローカルのMosquitto MQTT BrokerをブリッジにAWS IoTを使う | Amazon Web Services ブログ
SORACOM Beamで AWS IoTにMQTTS経由でデータ送信する方法については以下が参考になります。
Amazon Web Service (AWS) に送信する: AWS IoT と接続する | SORACOM Beam | ソラコムユーザーサイト - SORACOM Users
環境
$cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.6 LTS (Focal Fossa)"
$mosquitto -v
1714489200: mosquitto version 2.0.17 starting
前提
今回の目的
デバイスークラウド間の電波等の問題での接続断の際、つまりセッションが切断された際に、クラウドに届けられなかったデータをmosquittoのブローカー内でバッファリングし、デバイスに届けること。
mosquittoを利用することで、送信失敗したデバイスデータのキューイングまわりの機能を作りこむ手間なく、マシン内でデータを一定量保持することが可能となります。
mosquittoがインストールされていること
入っていなければ apt-get
で入れます。
なお、特に用いないのであれば、クライアント側となるmosquitto-clients
は不要です。
mosquittoの起動・停止ができること
以下のコマンドでmosquittoの状態が確認できます。
$systemctl status mosquitto
● mosquitto.service - Mosquitto MQTT Broker
Loaded: loaded (/lib/systemd/system/mosquitto.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2024-05-01 00:00:00 UTC; 1 day 12h ago
...
active
確認よし。
以下のコマンドで起動・停止・再起動・設定リロードできます。
$systemctl start mosquitto
$systemctl stop mosquitto
$systemctl restart mosquitto
$systemctl reload mosquitto
本日のメイン作業: ブリッジ設定ファイルを作る
mosquittoの conf.d
以下に、今回機能させたいブリッジの設定を記載します。
このディレクトリ配下に置けば、大元の設定ファイル mosquitto.conf
に include
されます。
$vi /etc/mosquitto/conf.d/bridge.conf
最終的には以下のようなファイルでIoT Core MQTT テストクライアントまでの疎通確認を行いました。
# =================================================================
# Bridge to SORACOM Beam
# =================================================================
# remote broker
connection awsiot
address mqtt://beam.soracom.io:1883
# topics to be bridged
topic test-topic out 1
# bridge connection settings
clientid bridgeToCloud
cleansession false
notifications false
# try_private must be set as false
try_private false
以下がmosquitto公式のドキュメントです。
mosquitto.conf man page | Eclipse Mosquitto
こちらの記事に全てではないですが項目の日本語説明があり参考にさせていただきました。
mosquittoの設定パラメータ一覧 #OSS - Qiita
以降、特に今回重要だった設定項目について説明を残します。
topic
今回は test-topic
に対してローカルから投げられるメッセージをリモートへ転送= out
するための設定をしました。
データのバッファリングが主目的だったので QoS
は 1
。
ちなみにIoT Coreは QoS 2
非対応(現在)。
try_private
ハマりポイントです。「 true
の場合、ブリッジは、通常のクライアントではなくブリッジであることをリモートブローカに示すように試みる。」そうですが、クラウド側がこれにどうやら対応していないらしく true
では動かず、 false
で動きました。
true
では以下のような動作をし、コネクションがすぐ切断されました。
Bridge bridge sending CONNECT
Client local.bridge closed its connection.
こちらについては、以下のサイトで別のHiveMQというAWSと別のクラウドサービスへのブリッジ設定で同様のエラーに苦しんでいるコミュニティがあり解決の糸口になりました。
Bridge Mosquitto to HiveMQ Cloud - HiveMQ Cloud - HiveMQ Community Forum
cleansession
ハマりポイントです。他の例で true
のことが多いのですが、今回の目的であるローカルデータのクラウドへの再送信を機能させるためには、こちらを false
にする必要がありました。
設定しなかった項目
bridge_protocol_version
ブリッジ機能に利用するMQTTプロトコルバージョンが指定できます。デフォルトでは mqttv311
が適用されます。
デフォルトのままで問題なかったです。
bridge_insecure
接続先サーバを認証するかどうかの設定です。デフォルト値ははっきり記載がないですが、明示的に insecure
を true
(=安全ではない状態)にすることでテストしやすくすることが目的のようです。
今回認証はSORACOM側で行うため設定しませんでした。
以下の記事が関連します。
IoT機器のTLS通信で立ちはだかる証明書の運用 - SORACOM公式ブログ
bridge_require_ocsp
オプション的に true
に設定することで、mosquittoがクライアントとして接続するTLS接続でOSCPを要求するとのことです。
今回TLS接続はSORACOMが担当するため設定しませんでした。
allow_anonymous
ユーザ名を指定せずに接続するクライアントの接続を許可するかどうか、とのこと。デフォルトは false
ですが、リスナーを定義しない場合は true
になり接続はローカルからのみ許可されるようです。
bridge_attempt_unsubscribe
「true
の場合、リモートブローカーにサブスクライブ解除要求を送信」します。上記の try_private
でハマったときに現れたエラーの解決に関係するかも?と考えたりしましたが関係なかったです。
実際のログ
mosquittoブローカーでセンサー( sensor_client
)からのデータを受け、これをブリッジにパブリッシュする、という一連の流れがログで確認できました。このデータをIoT CoreのMQTTテストクライアントで受信し、動作確認としています。
Received PUBLISH from sensor_client (...)
Sending PUBLISH to local.bridge (...)
Sending PUBACK to sensor_client (...)
Received PUBACK from local.bridge (...)
Received PUBLISH from local.bridge (...)
Sending PUBACK to local.bridge (...)
その他
デバッグ
Warning: Error resolving bridge address: Name or service not known.
address
に以下のような書き方をしたことが原因でした。
address mqtt://beam.soracom.io:1883
このように変更することで解決。
address beam.soracom.io:1883
設定して以下を実行
sudo mosquitto -c /etc/mosquitto/conf.d/bridge.conf -d
sudo: unable to resolve host XXXXX: Name or service not known
デバッグログが残っていなかったため思い出したら書きます、すみません。
ログについて
デフォルトのログ出力はUNIXタイムスタンプだったりカスタマイズが求められたので、こちらの記事を参考に設定しました。 ファイルに書き込んで残す場合は別途 loglotate
設定を忘れずにしましょう。
Amazon LinuxにMQTTブローカーMosquittoをインストールしてログ出力させる | DevelopersIO
キューイングデータ等の保持について
mosquitto内部で持つデータの保存等について設定が変更できます。
persistence
の値がtrue
でコネクション・サブスクライブ状況・メッセージデータが mosquitto.db
のディスクに書き込まれます(書き込み先は persistence_location
で変更可能)。デフォルトは false
で、同内容はメモリに記録されるようです。
ディスクへの書き込みタイミングは以下の通り
- Mosquittoがcloseした時
-
autosave_interval
に設定したタイミング-
autosave_on_changes
フラグtrue
で、retainされたメッセージ・受信メッセージ・キューのメッセージの変化に応じた自動保存になる。=秒数ではなく変化の度の保存に読み替えられます
-
-
SIGUSR1
シグナルをMosquittoに送信した時
注意点として、クライアントIDがランダム文字列などで毎回変わるような場合は、途切れたクライアントに対して永遠に再接続時に送信するデータを溜め込むことが起こりうるようです。このような場合は persistent_client_expiration
オプションを設定で切るまの時間を設定する対策をしましょう。
また、max_queued_bytes
と max_queued_messages
でそれぞれ保持するデータの容量とメッセージ数を設定できます。
デフォルトのメッセージ数は 1000
、bytesは 0
(上限なし)。
メインのmosquitto設定ファイルの内容
こんな感じになりました。
mosquitto.log
のlogrotate設定も必要です。
# logging
log_dest file /var/log/mosquitto/mosquitto.log
log_type all
log_timestamp true
log_timestamp_format %Y-%m-%dT%H:%M:%S
# data persistence
persistence true
persistence_location /var/lib/mosquitto/
include_dir /etc/mosquitto/conf.d
終わりに
MQTTは軽量なプロトコルということで単純なイメージを持ちますが、調べてみると実はできることが非常に多く驚かされ続けていました。今回のブリッジの利用目的は主にローカルデータの救出でしたが、双方向通信全体の効果的な仕組みを思いつくためにもっとドキュメントを読み込んでみたいと思います。