EventBridge / SQS / SNS
AWS のメッセージインフラを整理します。3つのツールの違い、SNS topic / SQS queue / EventBridge bus · rule、fan-out パターン、FIFO vs Standard、DLQ と冪等性(idempotency)、Visibility Timeout、そして Lambda / ECS とどう結びつくかまでを扱います。
第17章 Lambda 基礎 と 第18章 API Gateway + Lambda が同期呼び出しの領域だったとすれば、本章は非同期 / イベント駆動の方式です。呼び出し元が結果を待たず、コンポーネント同士がメッセージで疎結合になるパターンです。
AWS にこの領域のツールが3つあります — SNS / SQS / EventBridge です。似て見えますが強調点が異なります。本章でその違いを正確に分け、fan-out パターン、DLQ、冪等性のような運用ポイントまでを一度に整理します。ここで固めるキューと fan-out は、次の 第20章 Secrets Manager / Parameter Store の設定管理、第21章 Step Functions 入門 のワークフローと噛み合います。
3つの違い #
| SNS | SQS | EventBridge | |
|---|---|---|---|
| モデル | Pub/Sub (push) | Queue (pull) | Event Bus (push、ルーティングルール) |
| 受け取る側 | 0 ~ N 購読者が同時 | 1つのメッセージにつき 1つだけ | 0 ~ N (rule マッチに応じて) |
| 保存 | 即座に push、受け取らなければ消える | 最大 14日キューに保管 | rule マッチで即座に push |
| 適した場合 | 1イベント → 複数の受け取る側 | 作業キュー、バックプレッシャー | イベントベースのルーティング (多重ソース) |
| 統合 | Lambda、SQS、HTTP、Email、SMS | Lambda、ECS、EC2 (ポーリング) | Lambda、SQS、SNS、ECS、Step Functions、… 25+ |
代表的な構成を1行で見ます。
┌──────────────┐
│ │
生産者 ─→ SNS ─→ ├─→ SQS ─→ Lambda
└─→ Lambda Worker (長い処理)
(1イベント) (即座に push)
生産者 ─→ EventBridge ──┬─→ Lambda (ルール A マッチ)
(多様なソース) ├─→ Step Functions (ルール B)
└─→ SQS (ルール C)SNS — Pub/Sub #
Topic に publish するとすべての購読者に即座に伝わります。
モデル #
publish → Topic ──┬─→ 購読者 1 (Lambda)
├─→ 購読者 2 (SQS)
├─→ 購読者 3 (Email)
├─→ 購読者 4 (HTTP endpoint)
└─→ 購読者 5 (SMS)1イベントが発生したときに複数のコンポーネントが同時に知る必要がある場合です。
作る + Publish #
TOPIC_ARN=$(aws sns create-topic --name user-events \
--query TopicArn --output text)
# Lambda 購読
aws sns subscribe \
--topic-arn $TOPIC_ARN \
--protocol lambda \
--notification-endpoint arn:aws:lambda:ap-northeast-2:123456789012:function:on-user-event
# Email 購読 (確認メールのあと有効化)
aws sns subscribe \
--topic-arn $TOPIC_ARN \
--protocol email \
--notification-endpoint admin@example.com
# Publish
aws sns publish \
--topic-arn $TOPIC_ARN \
--message '{"userId":42,"action":"signup"}'Standard vs FIFO #
- Standard: ほぼ無限の処理量、順序保証なし、重複の可能性あり
- FIFO: グループ内の順序保証、正確に一度の配信。処理量制限 (3,000 msg/s with batching)
名前に .fifo 接尾辞が必須で、MessageGroupId が必須です。
メッセージフィルタリング #
同じ Topic に publish されても、購読者に一部だけ受け取らせることができます。
aws sns set-subscription-attributes \
--subscription-arn $SUB_ARN \
--attribute-name FilterPolicy \
--attribute-value '{"event": ["signup", "purchase"]}'publish 時に MessageAttributes の event が一致するときだけ伝わります。
適した場合 #
- 1イベント → 複数の処理 (メール、通知、分析、監査ログ)
- Email / SMS / Mobile Push 通知
- SQS fan-out の入り口
SQS — Queue #
Queue にメッセージを入れると、1つの consumer が polling で受け取り、処理する方式です。
モデル #
生産者 ─→ Queue ─→ 消費者 (Lambda / ECS Task)
↑
pull (polling)消費者が受け取りに行くモデルなのでバックプレッシャーが自然にかかります。消費者が遅ければ Queue にメッセージが積もり、その間は生産者は影響を受けません。
作る + Send / Receive #
QUEUE_URL=$(aws sqs create-queue --queue-name jobs \
--query QueueUrl --output text)
# Send
aws sqs send-message \
--queue-url $QUEUE_URL \
--message-body '{"job":"resize","key":"photo.jpg"}'
# Receive
aws sqs receive-message \
--queue-url $QUEUE_URL \
--max-number-of-messages 10 \
--wait-time-seconds 20 # long polling
# Delete (処理完了後)
aws sqs delete-message \
--queue-url $QUEUE_URL \
--receipt-handle <handle>Lambda と自動連携 #
Lambda に SQS をトリガーとして付けると、ポーリング / 削除は Lambda インフラが自動でします。
aws lambda create-event-source-mapping \
--function-name process-jobs \
--event-source-arn arn:aws:sqs:ap-northeast-2:123456789012:jobs \
--batch-size 10 \
--maximum-batching-window-in-seconds 5def handler(event, context):
for record in event["Records"]:
body = json.loads(record["body"])
process_job(body)
# 正常終了 → Lambda が自動でメッセージを削除
# 例外 → メッセージがキューに残り visibility timeout のあと再試行Visibility Timeout — 最も重要な設定 #
消費者がメッセージを受け取ると N 秒の間、他の消費者に見えなくなります。この時間の中で処理と削除が終わらなければなりません。そうでないと再びキューに浮かんで他の消費者が受け取ります → 重複処理のリスクです。
| 設定 | 推奨 |
|---|---|
| 平均処理時間 1秒 | Visibility Timeout 30秒 (余裕) |
| 平均処理時間 30秒 | 60 ~ 90秒 |
| 非常に長くなりうる処理 | change-message-visibility で処理中に延長 |
Standard vs FIFO #
SNS と同じです。
- Standard: ほぼ無限の処理量、順序保証なし、at-least-once (まれに重複)
- FIFO: グループ内の順序、正確に一度 (
MessageDeduplicationId)
Dead Letter Queue (DLQ) #
処理に失敗したメッセージを別のキューに移送します。運用必須です。
# DLQ を作る
DLQ_URL=$(aws sqs create-queue --queue-name jobs-dlq \
--query QueueUrl --output text)
DLQ_ARN=$(aws sqs get-queue-attributes \
--queue-url $DLQ_URL --attribute-names QueueArn \
--query 'Attributes.QueueArn' --output text)
# Main queue に redrive policy
aws sqs set-queue-attributes \
--queue-url $QUEUE_URL \
--attributes '{
"RedrivePolicy": "{\"deadLetterTargetArn\":\"'"$DLQ_ARN"'\",\"maxReceiveCount\":\"3\"}"
}'3回 retry のあと失敗すると DLQ に移送します。DLQ のメッセージは人が分析 / 修正して再びキューに送ります。
適した場合 #
- 作業キュー (画像処理、メール送信、外部 API 呼び出し)
- トラフィックスパイクの吸収
- コンポーネントの分離 (生産者が消費者の速度の影響を受けない)
EventBridge — Event Bus #
EventBridge は複数のソースから入ってくるイベントを複数のターゲットにルールベースでルーティングします。
モデル #
イベントソース (S3, EC2 状態変更, 外部 SaaS, 自分のコード ...)
│
▼
Event Bus (default またはユーザー定義)
│
├─ Rule A (パターン: source=aws.s3, eventName=ObjectCreated:Put)
│ → Lambda
├─ Rule B (パターン: source=myapp, detail-type=user.signup)
│ → SQS + Step Functions (どちらもターゲット)
└─ Rule C (cron: 毎日 03:00)
→ Lambda (バッチ作業)2種類のイベント #
1) AWS サービスイベント — AWS が自動 publish します。
- EC2 状態変更 (running → stopped)
- S3 ObjectCreated
- CodePipeline 段階完了
- …
2) Custom イベント — 自分のコードが publish します。
aws events put-events --entries '[{
"Source": "myapp.users",
"DetailType": "user.signup",
"Detail": "{\"userId\":42,\"plan\":\"pro\"}",
"EventBusName": "default"
}]'Rule を作る #
aws events put-rule \
--name on-user-signup \
--event-pattern '{
"source": ["myapp.users"],
"detail-type": ["user.signup"],
"detail": {"plan": ["pro"]}
}'
# ターゲット追加
aws events put-targets \
--rule on-user-signup \
--targets 'Id=1,Arn=arn:aws:lambda:ap-northeast-2:123456789012:function:welcome-pro'aws events put-rule \
--name nightly-cleanup \
--schedule-expression 'cron(0 18 * * ? *)' # UTC 18:00 = KST 03:00
aws events put-targets \
--rule nightly-cleanup \
--targets 'Id=1,Arn=arn:aws:lambda:ap-northeast-2:123456789012:function:cleanup'スケジューリングはより整理されたツールとして EventBridge Scheduler が別にあります (200,000 個まで / cron または rate / 一回限りまたは反復)。新規プロジェクトでは Scheduler を優先します。
Schema Registry / Pipes #
大規模なイベントエコシステムで使います。
- Schema Registry: イベントのスキーマを登録 / 自動発見します。コードジェネレータで型安全なクライアントを作ります。
- EventBridge Pipes: SQS / Kinesis / DynamoDB Streams → (選択的 enrichment / filter) → ターゲットへつなぎます。
適した場合 #
- AWS サービスイベントへの反応 (S3 アップロード → 処理)
- ドメインイベントのルーティング (
user.signup→ 5種類の処理) - スケジューリング (cron) — Lambda + EventBridge Scheduler が標準
- SaaS 統合 (Datadog、PagerDuty、Stripe などのマネージド統合)
Fan-out パターン #
最もよくある運用パターンの1つです。1イベント → 複数の非同期処理です。
生産者 ─→ SNS Topic ──┬─→ SQS Queue A ─→ Lambda A
├─→ SQS Queue B ─→ Lambda B
└─→ SQS Queue C ─→ Lambda Cなぜ SNS + SQS なのか? Lambda を SNS に直接付けてもよいですが、SQS を一段挟むと次の利点があります。
- 各処理のバックプレッシャーが独立です (B が遅くても A は影響なし)。
- 各処理の retry / DLQ が独立です。
- Lambda が一時的に死んでもメッセージが SQS に 14日まで保管されます。
EventBridge も同じパターンです — 1イベントが複数のルールにマッチすると複数のターゲットに同時に伝わります。
冪等性 (Idempotency) の重要性 #
非同期システムの核心です。同じメッセージを2回受け取っても結果が同じでなければなりません。
なぜ2回受け取るのかは次のとおりです。
- SQS Standard は at-least-once なのでたまに重複します。
- Visibility Timeout の中で処理を終えられないと再配信されます。
- Lambda の自動 retry (非同期呼び出し) があります。
- ネットワーク / クライアントの再試行があります。
パターン 1: 自然な冪等演算 #
# 冪等 (何度やっても結果が同じ)
user.set_status("active")
s3.put_object(Bucket=b, Key=k, Body=data)
# 非冪等
user.add_credit(100)
queue.send(...)可能なら自然な冪等で設計します。
パターン 2: ID + DB マーカー #
def handler(event, context):
msg = json.loads(event["body"])
msg_id = msg["id"]
# すでに処理した ID か?
if redis.get(f"processed:{msg_id}"):
return # skip
process(msg)
redis.setex(f"processed:{msg_id}", 86400, "1") # 1 日保管Lambda Powertools の Idempotency がこのパターンを DynamoDB バックエンドできれいに処理します。
パターン 3: FIFO Queue の deduplication #
MessageDeduplicationId またはコンテンツベースの deduplication です — 5分以内に同じ ID なら自動で拒否します。
どのツールをいつ #
| 場合 | ツール |
|---|---|
| 1イベント、複数の受け取る側 | SNS Fan-out (+ SQS を挟む) または EventBridge |
| 作業キュー | SQS |
| AWS サービスイベントへの反応 | EventBridge (S3、EC2 などが自動 publish) |
| スケジューリング | EventBridge Scheduler (または EventBridge Rule) |
| コンポーネント間の単純なメッセージ (1:1) | SQS |
| Email / SMS / Mobile Push | SNS |
| 外部 SaaS 統合 | EventBridge (マネージド統合) または EventBridge Pipes |
EventBridge が豊富なルール / フィルター / AWS サービス統合を提供します。単純な fan-out だけなら SNS + SQS です。
コスト #
| 価格 | |
|---|---|
| SQS | 100万 request あたり $0.40 (Standard)、$0.50 (FIFO) |
| SNS | publish 100万あたり $0.50 (Email / SMS / Mobile は別途) |
| EventBridge | publish 100万あたり $1.00 (custom イベント)、AWS 自体のイベントは無料 |
月 1,000万メッセージの SQS は $4 です。小さなワークロードは事実上無視できる水準です。
よく出会う落とし穴 #
1) メッセージの重複処理 #
自然な冪等ではない演算 (決済 / クレジット追加など) を SQS Standard でやると、1回の決済が2回の決済になります。常に冪等パターンまたは FIFO を使います。
2) Visibility Timeout のミス #
処理に 60秒かかるのに Visibility Timeout が 30秒だと、処理中のメッセージが再びキューに浮かんで他の消費者が受け取ります → 2回処理されます。Visibility Timeout を処理時間 + 余裕にしておきます。
3) DLQ なし #
失敗したメッセージが永遠にキューに浮かんでいると CloudWatch アラームだけがうるさくなります。すべてのキューに DLQ + アラームを置きます。DLQ 自体にもアラームを置きます (DLQ にメッセージが入る = 人が見るべき)。
4) Lambda の SQS ポーリングが高く見える #
Lambda が空のキューを高頻度でポーリングすると SQS request コストがかかります。long polling (WaitTimeSeconds=20) がデフォルトか確認します。
5) EventBridge rule が多くなりすぎる #
ドメインイベントごとにルールが増えるとコンソールがカオスになります。ドメインごとにユーザー定義の Event Bus (default ではない) を分離し、IaC で管理します。
6) SNS Email / SMS の用途 #
SNS の Email は形式が単調で (テキストのみ、From の変更が難しい) Spam に分類されやすいです。トランザクショナルメール (会員登録など) は Amazon SES が正解です。SNS Email は運用者への通知程度にだけ使います。
7) 非同期処理の結果をクライアントに知らせる方法 #
API → SQS → Lambda の処理後、結果をクライアントにどう知らせるのか? 2つのパターンがあります。
- クライアントが polling (作業 ID で GET リクエスト)
- WebSocket (API Gateway WebSocket API) で push
非同期システムの設計時に最初に決めるべき基準です。
練習問題 #
- 自分のシステムに「1人のユーザーが登録すると歓迎メール · 分析記録 · 管理者通知を同時に送る」という要求があるとして、§「どのツールをいつ」を根拠に SNS · SQS · EventBridge のどの組み合わせを使うかを1段落で設計してみましょう(第18章 API Gateway + Lambda の同期呼び出しとどこで分かれるかも併せて書きます)。
- 決済処理を SQS Standard + Lambda でやるとして、§「冪等性」の3つのパターンのうちどれを適用するかを選び、Visibility Timeout をどう設定すれば §「よく出会う落とし穴」の重複処理を防げるかを 第17章 Lambda 基礎 の同時実行とまとめて説明してみましょう。
- すべての作業キューに DLQ が必要な理由を §「Dead Letter Queue」と §「よく出会う落とし穴」を根拠に1行で書き、DLQ にメッセージが積もったとき運用者が何をすべきかを書いておきましょう。
一行まとめ: 非同期メッセージのツールは SNS(pub/sub push)、SQS(queue pull)、EventBridge(ルーティングルール)に分かれる。SQS はバックプレッシャーをかけてくれて Visibility Timeout が最も重要な設定で、すべてのキューに DLQ が必須。1イベントを複数の場所に送るには SNS → 複数の SQS → 各 Lambda の fan-out を使い、AWS サービスイベントへの反応とスケジューリングは EventBridge と Scheduler が担う。at-least-once 環境なので自然な冪等 · DB マーカー · FIFO dedup で冪等性を保証しなければならず、トランザクショナルメールは SNS ではなく SES が正解。
次の章 #
次の 第20章 Secrets Manager / Parameter Store では、運用の真剣な一軸であるパスワードと設定値をどこに保管するのかを扱います。2つのツールの違い、自動回転、コードから取得、ECS / Lambda 統合、IaC 連携、コスト比較まで AWS のシークレット管理2ツールを整理します。