AWS上でMQTTを使う機会があったのですが、MQTT自体を全く知らなかったので、基礎知識整理しつつ関連サービスを触ってみて感じた違いを整理してみます。
(内容としては初心者向けです。間違っているところあれば教えてください。)
今回試してみたサービスはAmazon MQとAWS IoT Coreです。
※対象のサービス探す時に以下の図が非常に参考になりました。ありがたい。
(引用元:https://pages.awscloud.com/rs/112-TZM-766/images/DevAx_connect_season1_Day2_MessagingService_配布.pdf)
目次
1. MQTTの基礎知識
個人的に知っておいた方が良いと思われる基礎知識を簡単に整理します。
MQTTとは
一言で言うと「停帯域や不安定なネットワークでも使える軽量なメッセージングプロトコル」だそうです(by ChatGPT)。その特徴からIoTの分野で使われていることが特に多い印象です。
アーキテクチャーはいわゆるPub/Subモデルとなっており、Topicを介して通信をします。
(引用元:MQTT - The Standard for IoT Messaging)
- Publisher:MQTTブローカーのトピックにメッセージをパブリッシュする。
- Subscriber:MQTTブローカーのトピックをサブスクライブしてメッセージを取得する。
- MQTTブローカー:通信を仲介するコンポーネントで、トピックの管理やメッセージの受け渡しを行う。
MQTTのトピックについて
AWS脳なのでAmazon SNSのトピックと同じようなものと思っていました。概念的には同じですが、「MQTTのトピック」としては以下を押さえておく必要があります。
- トピックは動的に作成される:Amazon SNSのように事前にトピックを作っておくなどは不要です。パブリッシュするトピック、サブスクライブするトピックを指定するだけで良いです。
- 階層構造:トピック名は
/
で構造化できます(例:foo/bar/hoge
) - ワイルドカード:サブスクライブするときにワイルドカードでトピック名を指定可能です。
またMQTTのトピックに関するベストプラクティスとして、AWSがホワイトペーパーを公開しています。AWS IoT Coreに関するドキュメントですが、一般的なMQTTトピックに関しても記載があり、参考になると思います。
以下ホワイトペーパーから一般的に使えそうなプラクティスのみ引用します。
MQTT トピックレベルでは、小文字、数字、ダッシュのみが使用されていることを確認する
- 記載の通りで、大文字小文字は区別されるため大文字はなるべく避けましょうという話になります。
MQTT トピックレベルの構造が、一般的なものから具体的なものへのパターンに従っている ことを確認する
- トピック名を
プラットフォーム名/建物名/フロア名/デバイス名
のように、広い範囲から狭い範囲になるように階層化しましょうという話です。 - こうしておくとワイルドカードが使いやすくなると思います。例えば特定の建物のトピックを全てサブスクライブしたい、となったら
プラットフォーム名/建物名/#
とトピックを指定できます。
<参考>
AWSのMQTTトピックに関するホワイトペーパー https://d1.awsstatic.com/whitepapers/ja_JP/Designing_MQTT_Topics_for_AWS_IoT_Core.pdf?did=wp_card&trk=wp_card
上記ホワイトペーパーに関するAWS公式の解説ブログ aws.amazon.com
QoSについて
MQTTにおけるQoS (Quality of Service) が定められています。数値が大きいほど、メッセージ到達の保証レベルが高いです。
-
- メッセージが最大一回届く(届かない場合もある)
- Publisherはメッセージを1回投げるだけなので到達する保証は無いと言うイメージ。
QoS 1:At least once
- メッセージが最低一回届く(重複する場合もある)
- 到達確認を保証する仕組みはあるので、最低一回は届くというイメージ。
QoS 2:Exactly once
- メッセージが正確に一回だけ届く
- 重複の検知も可能のため、正確に一回届くというイメージ。
注意点としては以下です。
- (当然ですが)性能的にはQoS0 > QoS1 > QoS2 になります(到達保証や重複検知の仕組みが入るとその分性能は落ちる)。そのため要件を踏まえて適切な選択が必要です。
- PublisherとSubscriberが指定したQoSのうち、低い方に合わせる形になります。
- QoS 2にしたい場合はPublisher・SubscriberともにQoS2を指定する必要があります。
- PublisherはQoS2を指定しているけど、SubscriberはQoS0を指定した場合、トータルではQoS0にダウングレードされる形となります。
実装イメージ(python)
# QoS 2を指定してパブリッシュ client.publish(topic=topic, payload=payload, qos=2) # QoS 2を指定してサブスクライブ client.subscribe(topic=topic, qos=2)
詳細なシーケンスは以下の記事が参考になります。
個人的な所感としては以下かなと思いました。
- 基本はQoS0を使用する
- ロストしたら困る場合はQoS1を使用して、サブスクライブ側で冪等性を確保する
- QoS2は極力使わない。
retain
メッセージをpublishする際にretain
を付与すると、後から対象のトピックをsubscribeするSubscriberで受信することができます。
1トピックに対してretain=true
は1メッセージという制約があります。
実装イメージ(python)
client.publish(topic=topic, payload=payload, qos=0, retain=True) # retainフラグ
最新の状態を通知するためなどに使えそうですね。
Last Will and Testament (willメッセージ)
willメッセージはPublisherが切断処理を行わずに、意図せず接続が切れた場合に指定したメッセージを通知する機能です。
太字のところがポイントで、正常に切断処理を行うと送信されないという点に注意が必要です(異常発生時に切断処理を行うような実装にしていると、Willメッセージが通知されなくなる)。
実装イメージ(python)
# Willメッセージの設定 client.will_set(topic=topic, payload=payload, qos=2)
2. MQTTブローカーとして使えるAWSのサービス
選択肢
Amazon MQとAWS IoT Coreの2つが選択肢になるかと思います。
一言で言うと以下のようなサービスです。
- Amazon MQ: OSS(ActiveMQ)※1のフルマネージドサービス。OSSがビルトインされたブローカー(インスタンス)が払い出されるイメージ。
- AWS IoT Core: AWSネイティブなサーバーレスのサービス。ブローカーだけではなく様々なIoT向けの機能を提供している。
※1. Amazon MQはRabbitMQも使用可能ですが、デフォルトでMQTTをサポートしているのはActiveMQのみです。そのため以降ActiveMQを使用することを前提に記載します。
ぶっちゃけどっちがいいの
ざっと触ってみた感触は以下です。特に理由がなければAWS IoT Coreがいいと思います。
Amazon MQとAWS IoT Coreの違い
触ってみて感じた違いを表にまとめてみました。
No. | 項目 | Amazon MQ | AWS IoT Core |
---|---|---|---|
1 | サーバー管理 | 必要 | 不要 |
2 | QoSの対応レベル | 全て対応 | QoS0, QoS1のみ対応 |
3 | 認証方式 | パスワード認証 | Cognito / IAM / 証明書 / カスタム認証 |
4 | アクセス制御 | 限定的 | ポリシーによる柔軟な制御が可能 |
5 | 他AWSサービスとの連携 | 限定的 | ルールエンジン・アクションによる豊富な連携 |
6 | リソースの場所 | VPC内 | VPC外 |
7 | 同時接続のクォータ(2023/6) | 2,000 (インスタンスがlargeの場合) | 500,000 |
以降詳しく違いを見ていきます。
違い1. サーバー管理の要否
Amazon MQの場合、サーバー管理が必要となりインスタンスタイプや構成を選択する必要があります。
インスタンスタイプは以下から選択できます。
(引用元:https://www.cloudremix.net/awsdocs/20210317_AWS-BlackBelt_AmazonMQ%20210317a.pdf)
構成として単一インスタンスだけではなく、以下のようにActive/Standbyの構成にすることもできます。 なおActive/Activeとすることはできません。
(引用元: 高可用性対応の Amazon MQ アクティブ/スタンバイブローカー - Amazon MQ)
またActive/Standbyの構成としたときは単一のエンドポイントではなく、それぞれのBrokerへのエンドポイントが払い出される形になります。
そのため接続先をアプリ側でハンドリングする必要があります(片方のエンドポイントに接続できなかったら、もう片方のエンドポイントに接続する等)。
※ライブラリによってはフェイルオーバートランスポートを使える場合、多少楽にはなります(調べた感じJavaで対応しているものはあるが、Pythonでは無いかも?)
一方AWS IoT Coreではサーバー管理は不要、かつアカウントのリージョン単位で存在する単一のエンドポイント(デバイスデータエンドポイント)に接続するのみのため、非常にシンプルです。
違い2. QoSの対応レベル
AWS IoT Coreは執筆時点(2023/6)でQoS2をサポートしていません。
そのためQoS2を使いたい場合はAWS IoT Coreは選択肢から外れます。
The MQTT protocol defines a third level of QoS, level 2, but AWS IoT does not support it
(引用元:MQTT - AWS IoT Core)
違い3. 認証方式
Amazon MQはパスワード認証とLDAP認証のみになります(2023/6時点)。IoTの分野でよく使う(と思われる)クライアント証明書による認証はサポートしていません。
ただしパスワード認証でサクッとMQTTを試したい場合には便利かと思います。
一方AWS IoT Coreでは様々な手段をサポートしています。特にクライアント証明書による認証が使用できる点がメリットかと思います。
ただし、パスワード認証はネイティブではサポートされていません(カスタム認証で作り込めば可能)。
(引用元:https://pages.awscloud.com/rs/112-TZM-766/images/EV_iot-deepdive-aws2_Sep-2020.pdf)
違い4. アクセス制御
Amazon MQの場合はリソースのIAMロールやセキュリティグループなどを使ったアクセス制御が中心になります。
Amazon MQに対する操作のAPIとしてはブローカーの作成・削除などが中心であり、このあたりの制御は比較的容易です。 (参考:Amazon MQ の API 認証と認可 - Amazon MQ)
しかしMQTTブローカーに対する操作(Publish/Subscribe)を制御するのはなかなか難しいです。例えば特定のクライアントはPublishのみ許可し、Subscribeは禁止したいとしても一筋縄ではいきません(というかできないかも?)
- IAMでは制御不可。
- IP等による通信の制限も困難。Publish/Subscribeともにクライアント→ブローカーの通信かつポート番号も同じのため、片方のみ許可という制御ができない。
2023/7/3追記
Amazon MQ(ActiveMQ) でもユーザーを作成し、xmlによる設定(activemq.xml
相当)で権限の制御が可能です。
詳細は以下の記事をご参照ください。
一方AWS IoT Coreはここの制御が容易です。クライアントごとにクライアント証明書を発行し、その証明書に対してIAMベースのポリシーをアタッチすることで認可を行うことができます。
そのため特定のクライアントはPublishのみ許可等の制御が容易に行えます。
違い5. 他AWSサービスとの連携
ここはAWSネイティブなAWS IoT Coreが非常に強い部分かと思います。
ルールエンジン、アクションを使用して特定のメッセージがPublishされたときに、他のサービスに連携するなどが非常に容易に行えます。
Amazon MQで同じことをやろうとしてもなかなか難しいと思います。
(引用元:https://d1.awsstatic.com/webinars/jp/pdf/services/20201027_AWS-Blackbelt-AWS_IoT_Core.pdf)
違い6. リソースの場所(VPC内 or VPC外)
Amazon MQはVPC内、AWS IoT CoreはVPC外のサービスになります。
そのためプライベートサブネットにあるリソースからAWS IoT Coreに接続する場合は、VPC Endpointを通すなどを行う必要があります。
違い7. 同時接続のクォータ(2023/6)
最後の違いとして同時接続できるクライアントのクォータを取り上げます。
上記の通りAmazon MQはクォータが低めの印象です。またリージョンあたりのブローカー数が最大50なので、ブローカーを増やしたとしても最大50*2000=100,000 であるため、AWS IoT Coreにおよびません。
接続するクライアント数は特に考慮しておいた方がいい点かと思います。
<参考>
AWS IoT Core エンドポイントとクォータ - AWS 全般のリファレンス
おわりに
違い比べてみた限りプロダクションレベルで使うなら、AWS IoT Coreの方が良いかなという印象です。
実際に触ってみた系の話はまた別の機会にします。