Amazon SNSによるPub/Sub通知とファンアウト
Amazon SNSのトピック、購読、プッシュ配信、メッセージフィルター、配信失敗への備え、SQSとのファンアウトを学びます。
Amazon SNSによるPub/Sub通知とファンアウト
Amazon Simple Notification Service(Amazon SNS)は、トピックに発行されたメッセージを、そのトピックを購読する複数の宛先へ配信するマネージドサービスです。発行側をパブリッシャー、受信側をサブスクライバーと呼びます。両者が直接お互いの場所や実装を知らなくても、共通のトピックを介して非同期に連携できるため、サービス間の依存を減らせます。
SNSはメールやSMS、モバイルプッシュ通知のほか、Amazon SQS、AWS Lambda、HTTP/Sエンドポイント、Amazon Data Firehoseなど複数の配信先を扱います。エンドユーザーへの短い通知にも、AWS上のシステム間でイベントを配る用途にも使えます。
トピックを介して発行側と購読側を分離する
パブリッシャーはトピックにメッセージを発行し、SNSはその時点で有効なサブスクリプションへメッセージを配信します。サブスクリプションは「どの宛先に届けるか」と「その宛先に何を届けるか」を定義します。同じトピックに複数の購読を設定すれば、同じイベントをそれぞれ独立した処理へ通知できます。
たとえば、宅配便の追跡システムが荷物の状態変更をトピックに発行すると、配送状況画面の更新、利用者への通知、分析データの集計を別々のサブスクライバーに任せられます。発行側にそれぞれの処理先を直接呼び出させる必要はありません。通知を受け取る処理をあとから追加するときも、発行側の変更を小さくできます。
SNSは発行イベントの配布役です。トピックに発行したメッセージを、一般的なキューのようにコンシューマーが好きな時点で取り出すモデルではありません。通知が届いた後の処理を受信側で保留したい場合は、サブスクライバーにSQSキューを選びます。キューがメッセージを保持するため、ワーカーは自分の処理速度に合わせてポーリングできます。
プッシュ通知とキューイングを使い分ける
SNSとSQSはどちらもメッセージ連携に使いますが、メッセージの流れが異なります。
| 観点 | Amazon SNS | Amazon SQS |
|---|---|---|
| 基本モデル | トピックを購読する複数の宛先へのPub/Sub配信 | キューからコンシューマーがメッセージを取得 |
| 誰が配信を進めるか | SNSがサブスクライバーへプッシュする | コンシューマーがポーリングする |
| 同じメッセージの扱い | 複数の購読先へそれぞれ配信できる | 通常は同じキューの処理ワーカー間で仕事を分配する |
| 受信後の保留 | SNSだけでは一般的なキューのような任意の処理待ちを提供しない | キューに保持し、処理完了後に削除する |
| 主な選択条件 | イベントを複数の異なる宛先へ通知したい | 受信側が自分のタイミングで仕事を取り出したい |
一つのイベントから複数の非同期処理を始めるならSNSで通知し、各処理を個別に蓄積・再試行させるには購読先にSQSを置きます。反対に、一つの仕事を複数のワーカーのうちいずれか1つに処理させるだけなら、SQSだけで構成できます。
Amazon Kinesis Data Streamsは、継続的に流れるレコードを保持し、複数のコンシューマーがストリームを読み取って処理・分析する用途に適します。SNSはイベント通知、SQSは個々の作業要求の受け渡し、Kinesisは順序を持つデータストリームの取り込みと処理が中心です。
ファンアウト:SNSから複数のSQSキューへ配る
ファンアウトは、1つのメッセージを複数の購読先へ広げて配信するパターンです。SNSトピックの購読先に複数のSQSキューを指定すると、各キューに同じイベントが届きます。それぞれのキューは別の処理系に接続されるため、購読者ごとに処理の開始時刻、速度、再試行を独立させられます。
先ほどの荷物状態変更の例なら、配達予定を更新するキュー、検索インデックスを更新するキュー、利用状況を集計するキューを別々に用意できます。検索の更新が一時的に遅れても、通知処理や集計処理はそれぞれのキューから作業を続けられます。新しい用途が必要になれば、その用途用のキューと購読を追加できます。
| 構成要素 | 役割 |
|---|---|
| パブリッシャー | 業務イベントをSNSトピックへ発行する |
| SNSトピック | 1回の発行を購読設定に従って配信する |
| SQSキュー | 各処理系向けのコピーを保持し、処理側の都合で取得できるようにする |
| ワーカー | 自分のキューからメッセージを受け取り、処理後に削除する |
この構成では、SNSによる複数宛先への通知と、SQSによる受信側のバッファリングを組み合わせます。SNSの発行時点で後続作業をすべて完了させる必要はなく、各処理系はメッセージを受け取ってから独立して処理できます。
購読単位のフィルターポリシー
トピックに何もフィルターを設定しなければ、基本的に購読者はそのトピックへ発行された全メッセージを受け取ります。サブスクリプションにフィルターポリシーを設定すると、SNSがその購読先に配信するメッセージを選別します。フィルターはトピック全体ではなく、購読単位で適用されます。同じトピックを購読する別の宛先には、それぞれ異なる条件を指定できます。
フィルターの評価対象は次のいずれかです。
- メッセージ属性(既定): 発行時にメッセージとともに渡す属性値を評価する。属性を使う場合は、発行側が型を含む属性を正しく付与する必要がある。
- メッセージ本文:
FilterPolicyScopeをMessageBodyにしたうえで、本文を有効なJSONオブジェクトとして評価する。
たとえば荷物イベントに配送地域やイベント種別を属性として付ければ、地域別の購読先には担当エリアの通知だけ、分析用の購読先には到着イベントだけを配信できます。フィルターに一致しない宛先へは通知が配信されません。条件に合わないメッセージは、その購読先の処理対象にならない点に注意してください。
フィルターポリシーはJSONで記述します。文字列の大文字・小文字、属性名、値のデータ型、評価範囲(属性か本文か)が発行側の実データと一致している必要があります。設定変更後、反映まで時間がかかることがあります。フィルター条件とSNSのCloudWatchメトリクスを合わせて確認すると、メッセージが届かない理由を切り分けやすくなります。
SQSやHTTP/Sの購読では、RawMessageDeliveryを有効にしてSNSの通知エンベロープを外し、発行された本文をそのまま渡すこともできます。既定の形式ではSNS由来の情報を含む通知JSONがメッセージに付加されます。受信側がどちらの形式を想定しているか、購読の設定とアプリケーションのパーサーをそろえてください。
標準トピックとFIFOトピック
SNSには標準トピックとFIFOトピックがあります。順序が重要か、購読先が必要とする配送条件は何かを基準に選びます。
| 特性 | 標準トピック | FIFOトピック |
|---|---|---|
| 配信順 | 厳密な順序は保証されない | FIFO購読先へ発行順に配信する |
| 重複排除 | 重複を前提に受信側を設計する | 5分間の重複排除ID、または本文に基づく重複排除を利用できる |
| 主な宛先 | SQS、Lambda、HTTP/S、メール、SMS、モバイルプッシュなど | Amazon SQSの標準キューまたはFIFOキュー |
| 顧客管理エンドポイント | 対応するプロトコルに配信できる | メール、SMS、モバイルプッシュ、HTTP/Sなどには配信できない |
| 適する要件 | 高い配信並列性、順序に依存しない通知 | イベントの順序や重複排除が必要な非同期連携 |
FIFOトピックは、SNSからSQSへイベントを送る場合に使います。FIFOキューを購読先にすれば、キュー側でも順序を引き継いで処理できます。SQS標準キューを購読先に選ぶと、標準キューの性質により、受信側で順序や重複が保たれるとは限りません。FIFOトピックからLambdaを起動したい場合も、SNSからSQSキューへ配信し、そのキューをLambdaのイベントソースとして構成します。
FIFOではMessageGroupIdで順序を保つ範囲を分けます。同じグループ内では順序に沿って処理し、異なるグループは並行処理できます。MessageDeduplicationIdは重複排除のための識別子です。コンテンツベースの重複排除を使う場合、SNSはメッセージ本文から識別子を生成しますが、メッセージ属性はその計算に含まれません。
重複排除は、アプリケーション全体での副作用を無条件に「一度だけ」にするものではありません。SNS FIFOトピックとSQS FIFOキューの組み合わせで厳密な配信を目指す場合も、購読先のポリシー、キューコンシューマーの処理と削除、フィルターの有無、通信状態などの条件が関係します。特にフィルターポリシーを使うFIFOトピックでは、フィルターされる購読先にメッセージが配信されないため、全購読先での一度だけの処理を前提にできません。業務データの二重更新を防ぐには、処理側でも冪等性を設計します。
配信失敗とメッセージの保持
「SNSは一切再試行しない」「受信側がすぐ応答しなければ必ず失われる」とは限りません。再試行の動作は購読プロトコルやエラーの種類に応じて異なります。HTTP/S購読の再試行間隔は配信ポリシーで調整できます。AWSサービスが管理するエンドポイントにも、サービスごとの再試行動作があります。一方、無期限の保存を行うメッセージキューとしてSNSを扱うことはできません。
配信先が到達不能などの理由で配信に失敗し、再試行後も受信できないメッセージを保全するには、サブスクリプションに**デッドレターキュー(DLQ)**を設定します。SNSサブスクリプションのDLQにはSQSキューを指定します。DLQはSNSトピックと同じAWSアカウント、同じリージョンに配置し、SNSがSendMessageできるキューポリシーを設定します。失敗した配信の調査や、原因修正後の再処理に利用できます。
SNSのDLQと、SQSコンシューマーが処理できないメッセージを移すSQS自身のDLQは目的が異なります。
| DLQの種類 | 何に失敗したメッセージを受け取るか | 設定場所 |
|---|---|---|
| SNSサブスクリプションのDLQ | SNSから購読エンドポイントへの配信失敗 | SNSサブスクリプション |
| SQSのDLQ | SQSから受信した後のコンシューマー処理失敗 | SQSキューのRedrive Policy |
ファンアウト構成で両方の失敗を追えるようにするには、SNSから各キューへの配信失敗と、キューから各ワーカーへの処理失敗を分けて監視します。配信の再試行・保持期間・再投入手順を設計し、監視対象のCloudWatchメトリクスや通知先も決めます。
配信形式と代表的なAPI
HTTP/S購読では、SNSは通知の本文やトピックARNなどを含むJSONメッセージをエンドポイントへ送信します。HTTP/Sの購読登録時には、エンドポイントが購読確認を完了するまで配信が有効になりません。通知、購読確認、購読解除ではそれぞれ異なるJSON形式が使われます。エンドポイント側はSNSからの要求を検証し、成功した配信に対して正常なHTTP応答を返す必要があります。
主なSNS APIアクションは次のとおりです。
| APIアクション | 用途 |
|---|---|
CreateTopic |
トピックを作成する |
Subscribe |
トピックと配信先をサブスクリプションで結ぶ |
ConfirmSubscription |
HTTP/Sなどで受け取った購読確認を完了する |
Publish / PublishBatch |
トピックへメッセージを発行する |
SetSubscriptionAttributes |
フィルターポリシー、配信ポリシー、DLQなどの購読設定を変更する |
Unsubscribe |
サブスクリプションを解除する |
SetTopicAttributes |
トピック属性やトピックポリシーなどを設定する |
メッセージサイズは既定で最大256 KiBです。トピック属性MaximumMessageSizeを設定すると、対応する購読先では最大1 MiBまで拡張できます。大きなペイロードを複数の宛先へ運ぶ必要がある場合は、受信先プロトコルの対応範囲も確認します。SNS Extended Client Libraryを使ってAmazon S3に本文を置き、SNSには参照情報を発行する方法もあります。この方法ではS3の保存・リクエスト料金が別途かかります。
IAMポリシーとトピックポリシー
SNSへのアクセスは、利用者やロールに付与するIAMアイデンティティポリシーと、トピックに設定する**リソースベースポリシー(トピックポリシー)**を使って制御します。
- アイデンティティポリシーは、呼び出し元がどのSNSアクションを実行できるかを指定する。アプリケーションの実行ロールに対象トピックへの
Publishだけを許可する、といった設定ができる。 - トピックポリシーは、トピック側でアクセス主体と操作を指定する。別アカウントからの発行や、Amazon S3などのAWSサービスからの発行を許可するときに使う。
たとえば別アカウントの注文管理ロールからイベントを発行させる場合、トピックポリシーでそのロールに対象トピックへのsns:Publishを許可し、呼び出し側ロールのIAMポリシーでも対象リソースへの許可を設定します。AWSサービスからの発行を許すポリシーでは、許可するサービスプリンシパルに加えてaws:SourceArnやaws:SourceAccountなどの条件を使い、意図したリソースからの要求に限定します。
特定の購読先の操作や購読自体の作成も含め、必要なアクションだけを許可します。トピックのARN、リージョン、アカウント、アクションの指定を誤ると、発行できない、または意図しない主体が発行できる状態になります。
SNSとSES、SMS、MQTT
SNSはメール配信もできますが、メールマーケティングやトランザクションメールの管理が中心であればAmazon Simple Email Service(Amazon SES)を選びます。SNSのEメール購読は通知を届ける手段であり、宛先管理、配信キャンペーン、バウンスや苦情の処理などメール配信に特化した機能の代わりではありません。SNSのSMS配信は短いテキスト通知向けで、メッセージ長、文字エンコード、送信先の国やSMS設定によって扱いが異なります。
MQTTはIoTデバイスとメッセージブローカー間の通信で使われるプロトコルです。AWSでMQTTを使ったデバイス接続やルーティングを構成する場合はAWS IoT Coreが該当します。Amazon SNSの標準的な購読プロトコルにMQTTは含まれません。AWSサービスがSNSトピックに通知を発行する構成と、デバイスがMQTTブローカーへ接続する構成を混同しないようにします。
料金の考え方
SNSは無料の固定サービスではなく、利用量に応じて課金されます。API要求、メッセージのペイロードサイズ、配信プロトコル、FIFOトピック、SMSなどで課金単位が異なります。標準トピックではペイロードの64 KiB単位のチャンクが要求数に算入され、大きなペイロードでは1回の発行が複数の課金要求として数えられます。S3を用いる拡張ペイロードではS3料金、暗号化にAWS KMSを使う場合はKMS料金も考慮します。
料金はリージョンや配信先、利用量によって変わるため、固定額を前提にせずAmazon SNS料金ページで対象の課金条件を確認してください。大量の通知では購読先の数、配信失敗、ペイロードサイズ、SMSの宛先を含めて見積もります。
設計の判断ポイント
- 1つのイベントを複数の独立した宛先へ通知するならSNSを使う。
- 受信側にメッセージを保持し、処理タイミングや再試行を個別に制御させるなら、SNSの購読先にSQSを置く。
- 高スループットで順序に依存しない通知は標準トピック、FIFO順序が必要なSQS連携はFIFOトピックを検討する。
- 購読先ごとに属性またはJSON本文のフィルターポリシーを設け、不要なイベントを配信しない。
- SNSサブスクリプションのDLQで配信失敗を保全し、SQSのDLQでワーカー処理の失敗を隔離する。
- 発行ロール、AWSサービス、別アカウントの許可をIAMポリシーとトピックポリシーで最小限に絞る。
- SNSのリトライを考慮して受信処理を冪等にし、SNSを長期間保持するキューとして扱わない。
公式ドキュメント
重要ポイント
- ▸SNSはパブリッシャーとサブスクライバーをトピックで結び、1つの発行を複数の宛先へプッシュ配信する
- ▸購読ごとのフィルターポリシーはメッセージ属性またはJSON本文を評価し、必要な通知だけを宛先へ届ける
- ▸SNSからSQSへ配信すると、通知を各キューに保持でき、処理速度や稼働状況を購読者ごとに分離できる
- ▸標準トピックは高い並列性を重視し、FIFOトピックは順序と重複排除を必要とする場合に選ぶ
- ▸配信の再試行とサブスクリプションDLQを使って失敗に備え、SNS自体を長期間のメッセージ保管庫として扱わない
- ▸トピックのリソースポリシーとIAMポリシーを組み合わせて、発行元と操作を制限する
このトピックの学習を完了しますか?
完了状態はいつでも切り替えられます