AWS上級 #5 EventBridge / SQS / SNS
#3 Lambda、#4 API Gateway が同期呼び出しの領域だったなら、今回は 非同期 / イベント駆動 方式です。呼び出し元が結果を待たず、コンポーネント間がメッセージで緩く繋がるパターン。
AWS にこの領域のツールが 3 つ — SNS / SQS / EventBridge。3 つは似て見えますが強調点が違います。この記事でその違いを正確に分け、fan-out パターン、DLQ、冪等性のような運用ポイントまで一気に。
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+ |
最もよく見るパターンを一行で:
┌──────────────┐
│ │
生産者 ─→ 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: グループ内順序保証、正確に 1 度配信。処理量制限 (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 人の 消費者 が 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 をトリガーとして付ければ polling / 削除は 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: グループ内順序、正確に 1 度 (
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 = JST 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 / 1 回または繰り返し)。新規プロジェクトでは 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 を 1 段挟むと:
- 各処理のバックプレッシャーが独立 (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
EventBridge が豊富なルール / フィルタ / AWS サービス統合。シンプルな fan-out だけなら SNS+SQS。
作業キュー #
→ SQS
AWS サービスイベントへの反応 #
→ EventBridge (S3、EC2 等が自動 publish)
スケジューリング #
→ EventBridge Scheduler (または EventBridge Rule)
コンポーネント間の単純メッセージ (1:1) #
→ SQS
Email / SMS / Mobile Push #
→ SNS
外部 SaaS 統合 #
→ EventBridge (マネージド統合) または EventBridge Pipes
費用 — 短く #
| 価格 | |
|---|---|
| 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 polling が高く見える #
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
非同期システム設計時に最初に決める基準です。
まとめ #
今回つかんだもの:
- 3 つの違い — SNS (pub/sub)、SQS (queue)、EventBridge (ルーティングルール)
- SNS — Topic に publish、複数購読者に即時 push。Email / SMS / Mobile Push 統合
- SQS — Queue + polling。Visibility Timeout が最も重要な設定
- DLQ — すべてのキューに必須。
maxReceiveCount回失敗後に送付 - Standard vs FIFO — Standard は at-least-once / 無限処理量。FIFO は順序 + 重複除去 + 処理量制限
- EventBridge — AWS サービスイベント + custom イベント。ルールパターンでルーティング。Scheduler で cron
- Fan-out パターン — SNS → 複数 SQS → 各 Lambda。バックプレッシャー / retry / DLQ が受け手毎に独立
- 冪等性 — at-least-once 環境では必須。自然冪等 / DB マーカー / FIFO dedup
- 選択ガイド — 1 イベント N 受信 (SNS / EventBridge)、作業キュー (SQS)、AWS イベント反応 (EventBridge)、スケジュール (EventBridge Scheduler)、Email (SES、SNS でない)
- 費用 — すべて非常に安い。小さなワークロードは無視
- 落とし穴 — 重複処理、Visibility Timeout ミス、DLQ 欠如、polling 費用 (long polling)、ルール暴走、SNS Email の用途、結果通知パターン
次回 — 秘密 / 設定 #
次のテーマは運用の真剣な一角 — パスワードと設定値をどこに保管するか です。
#6 Secrets Manager / Parameter Store では 2 つの違い、自動ローテーション、コードから取得、IaC との接続、費用比較まで — AWS のシークレット管理 2 つのツールを一気に整理します。