mazyu36の日記

某SIer所属のクラウドエンジニアのブログ

AWSにおけるMQTTブローカーを比べてみる(Amazon MQ, AWS IoT Core)

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
  • ワイルドカード:サブスクライブするときにワイルドカードでトピック名を指定可能です。
    • +:単一レベルのワイルドカード(例:foo/+/hogeとすると間の一階層のみ任意となります)。
    • #:複数レベルのワイルドカード(例:foo/#とするとfoo/で始まるトピック全てが対象になります。)

またMQTTのトピックに関するベストプラクティスとして、AWSがホワイトペーパーを公開しています。AWS IoT Coreに関するドキュメントですが、一般的なMQTTトピックに関しても記載があり、参考になると思います。

以下ホワイトペーパーから一般的に使えそうなプラクティスのみ引用します。

MQTT トピックレベルでは、小文字、数字、ダッシュのみが使用されていることを確認する

  • 記載の通りで、大文字小文字は区別されるため大文字はなるべく避けましょうという話になります。

MQTT トピックレベルの構造が、一般的なものから具体的なものへのパターンに従っている ことを確認する

  • トピック名をプラットフォーム名/建物名/フロア名/デバイス名のように、広い範囲から狭い範囲になるように階層化しましょうという話です。
  • こうしておくとワイルドカードが使いやすくなると思います。例えば特定の建物のトピックを全てサブスクライブしたい、となったらプラットフォーム名/建物名/#とトピックを指定できます。

<参考>

QoSについて

MQTTにおけるQoS (Quality of Service) が定められています。数値が大きいほど、メッセージ到達の保証レベルが高いです。

  • QoS 0:At most once

    • メッセージが最大一回届く(届かない場合もある)
    • 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)

詳細なシーケンスは以下の記事が参考になります。

qiita.com

個人的な所感としては以下かなと思いました。

  • 基本は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を使用することを前提に記載します。

docs.aws.amazon.com

docs.aws.amazon.com

ぶっちゃけどっちがいいの

ざっと触ってみた感触は以下です。特に理由がなければAWS IoT Coreがいいと思います。

  • 以下のいずれかに該当するならAmazon MQ
    • ActiveMQを使いたい。
    • QoS2を使いたい(2023/6時点でAWS IoT Coreは非対応)。
    • パスワード認証でサッとやりたい(AWS IoT Coreでもできなくはないが、Amazon MQの方が楽)
  • 上記以外は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相当)で権限の制御が可能です。

詳細は以下の記事をご参照ください。

mazyu36.hatenablog.com


一方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:largeタイプのブローカーの場合、1ブローカーあたり2000
  • AWS IoT Core:アカウントあたり500,000

上記の通りAmazon MQはクォータが低めの印象です。またリージョンあたりのブローカー数が最大50なので、ブローカーを増やしたとしても最大50*2000=100,000 であるため、AWS IoT Coreにおよびません。

接続するクライアント数は特に考慮しておいた方がいい点かと思います。

<参考>

Amazon MQ のクォータ - Amazon MQ

AWS IoT Core エンドポイントとクォータ - AWS 全般のリファレンス

おわりに

違い比べてみた限りプロダクションレベルで使うなら、AWS IoT Coreの方が良いかなという印象です。

実際に触ってみた系の話はまた別の機会にします。