AWSコンソールだけでSNS + SQS + Lambda 通知システムを構築する手順【Pub/Sub・ファンアウト・DLQ / SAM版との比較付き】

AWS Basic
スポンサーリンク
スポンサーリンク
  1. はじめに
  2. キーワード解説
  3. 使用するAWSサービス
  4. 全体の作業順序
  5. ① SNS Topic を作成する
  6. ② SQS キューを3つ作成する
    1. 2-1. AlertDLQ(デッドレターキュー)を先に作成する
    2. 2-2. LogQueue を作成する(フィルターなし・全メッセージ用)
    3. 2-3. AlertQueue を作成する(フィルターあり・アラート用)
  7. ③ SNS → SQS サブスクリプションを2つ作成する
    1. 3-1. LogQueue サブスクリプション(フィルターなし)
    2. 3-2. AlertQueue サブスクリプション(フィルターあり)
  8. ④ Lambda 関数を2つ作成する
    1. 4-1. LogFunction(全ログ処理)
    2. 4-2. AlertFunction(アラート処理・DLQ テスト機能付き)
  9. ⑤ SQS トリガーを各 Lambda に追加する
    1. 5-1. LogFunction に LogQueue トリガーを追加する
    2. 5-2. AlertFunction に AlertQueue トリガーを追加する
  10. ⑥ 動作テスト
    1. テスト1: level=info(LogFunction のみ受信)
    2. テスト2: level=warning(両 Lambda が受信 = ファンアウト)
    3. テスト3: level=warning + body=error(AlertFunction 失敗 → DLQ)
  11. ⑦ リソースの削除
    1. 1. Lambda のトリガーを削除する
    2. 2. Lambda 関数を削除する
    3. 3. SNS サブスクリプションを削除する
    4. 4. SNS Topic を削除する
    5. 5. SQS キューを3つ削除する
    6. 6. IAM ロールを削除する(任意)
    7. 7. CloudWatch Logs のロググループを削除する(任意)
  12. SAMとの対比
  13. トラブルシューティング
  14. まとめ
    1. コンソール版で実感できたポイント
  15. コンソール版と SAM 版を比較してみる
  16. 関連記事

はじめに

「1回メッセージを送るだけで、複数のシステムに同時に通知したい」——そんな要件を実現する設計パターンが Pub/Sub(パブリッシュ・サブスクライブ)ファンアウト です。

この記事では、AWSコンソールのみを使って、SNS + SQS + Lambda による通知システムをゼロから構築するハンズオンを紹介します。

Publisher(aws sns publish)
  ↓ メッセージを1回発行するだけ
SNS Topic(NotificationTopic)
  │
  ├─ サブスクリプション(フィルターなし)
  │    → LogQueue → LogFunction → CloudWatch Logs(全メッセージを記録)
  │
  └─ サブスクリプション(level=warning/critical のみ)
       → AlertQueue → AlertFunction → CloudWatch Logs(アラート処理)
                          ↓ 処理失敗(3回)
                        AlertDLQ

このハンズオンで体験できること:

  • Pub/Sub パターン — Publisher と Subscriber が疎結合で通信する仕組み
  • ファンアウト — 1回の publish で複数の Lambda が並行して動作する体験
  • SNS フィルターポリシー — メッセージ属性で配信先を絞り込む設定
  • DLQ(デッドレターキュー) — 処理失敗メッセージの退避先を実際に確認

この記事は SAM版ハンズオン の比較記事です。
コンソール操作で SNS・SQS・Lambda の連携を視覚的に学び、SAM と何が違うのかを比較したい方向けです。


Amazon検索[本 AWS 開発]

スポンサーリンク

キーワード解説

用語意味
SNS Topicメッセージの送信先。複数のサブスクライバーに同時配信できる
サブスクリプションTopic からメッセージを受け取るエンドポイントの設定
Pub/SubPublisher(発行者)と Subscriber(購読者)が疎結合で通信するパターン
ファンアウト1つのメッセージを複数の宛先に同時配信するパターン
フィルターポリシーメッセージ属性に基づき、配信するかどうかを制御するルール
DLQ(デッドレターキュー)処理に失敗したメッセージを退避させるキュー
SNS エンベロープSNS が SQS に配信する際にメッセージを包む JSON 構造
可視性タイムアウトSQS がメッセージを処理中に他のコンシューマーから見えなくする時間

スポンサーリンク

使用するAWSサービス

サービス役割料金
SNSメッセージの発行・ファンアウト配信月100万リクエストまで無料
SQSメッセージキューイング(LogQueue / AlertQueue / AlertDLQ)月100万リクエストまで無料
Lambdaキューからメッセージを受信して処理(LogFunction / AlertFunction)月100万リクエスト・400,000 GB-秒まで無料
IAMLambda の実行権限管理無料
CloudWatch LogsLambda の実行ログ月5GBまで無料

全体の作業順序

① SNS Topic を作成する
      ↓
② SQS キューを3つ作成する(AlertDLQ / LogQueue / AlertQueue)
      ↓
③ SNS → SQS サブスクリプションを2つ作成する
  (LogQueue: フィルターなし / AlertQueue: フィルターあり)
      ↓
④ Lambda 関数を2つ作成する
      ↓
⑤ SQS トリガーを各 Lambda に追加する
      ↓
⑥ 動作テスト(3パターン)
      ↓
⑦ リソースの削除

AlertDLQ を先に作成する理由:
AlertQueue の作成時に DLQ として AlertDLQ の ARN を指定するため、AlertDLQ を先に作る必要があります。


① SNS Topic を作成する

AWSコンソール → SNS → 「トピック」→「トピックを作成」

設定項目
タイプスタンダード
名前NotificationTopic

その他の設定はデフォルトのまま。「トピックを作成」をクリック。

控えておく情報:

  • トピック ARN(例: arn:aws:sns:ap-northeast-1:123456789012:NotificationTopic

スタンダードとFIFOの違い:
スタンダードは順序保証なし・高スループット。FIFO は順序保証あり・1回限りの配信が必要な場合に使用します。今回のログ/アラート通知にはスタンダードが適しています。


② SQS キューを3つ作成する

AWSコンソール → SQS → 「キューを作成」

2-1. AlertDLQ(デッドレターキュー)を先に作成する

設定項目
タイプスタンダード
名前AlertDLQ
メッセージ保持期間1 日(学習用なので短く設定)

「キューを作成」をクリック。

控えておく情報:

  • AlertDLQ の ARN(例: arn:aws:sqs:ap-northeast-1:123456789012:AlertDLQ

2-2. LogQueue を作成する(フィルターなし・全メッセージ用)

設定項目
タイプスタンダード
名前LogQueue
可視性タイムアウト180

「キューを作成」をクリック。

可視性タイムアウトを 180 秒にする理由:
Lambda のデフォルトタイムアウト(3秒)より長く設定することで、処理中に他のコンシューマーがメッセージを二重取得するのを防ぎます。DLQ テストでは 180秒 × 3回 ≒ 9分待つことになります。


2-3. AlertQueue を作成する(フィルターあり・アラート用)

設定項目
タイプスタンダード
名前AlertQueue
可視性タイムアウト180

「デッドレターキュー」セクション:

設定項目
デッドレターキューを有効にするオン
デッドレターキューの ARNAlertDLQ の ARN を貼り付ける
最大受信数3

「キューを作成」をクリック。

控えておく情報:

  • LogQueue の ARN
  • AlertQueue の ARN

③ SNS → SQS サブスクリプションを2つ作成する

SQS キューポリシーの自動追加について:
コンソールで SNS → SQS サブスクリプションを作成すると、
SNS が SQS キューのアクセスポリシーに sns.amazonaws.com からの sqs:SendMessage 権限を自動追加します。
手動でのポリシー設定は不要です(SAM版では AWS::SQS::QueuePolicy を明示的に定義する必要があります)。

3-1. LogQueue サブスクリプション(フィルターなし)

SNS → NotificationTopic → 「サブスクリプション」タブ → 「サブスクリプションを作成」

設定項目
プロトコルAmazon SQS
エンドポイントLogQueue の ARN
サブスクリプションフィルターポリシー設定しない(空欄のまま)

「サブスクリプションを作成」をクリック。


3-2. AlertQueue サブスクリプション(フィルターあり)

SNS → NotificationTopic → 「サブスクリプション」タブ → 「サブスクリプションを作成」

設定項目
プロトコルAmazon SQS
エンドポイントAlertQueue の ARN

「サブスクリプションフィルターポリシー」セクション:

設定項目
サブスクリプションフィルターポリシー有効にする
フィルターポリシーのスコープメッセージ属性(デフォルト)
JSON エディタ以下を入力
{
  "level": ["warning", "critical"]
}

フィルターポリシーの意味:
level メッセージ属性の値が "warning" または "critical" のメッセージのみ AlertQueue に配信します。
level=info のメッセージは AlertQueue に届かない(LogQueue には届く)。

よくある間違い(フィルターが動作しない場合):

  • スコープが「メッセージ本文」になっている → **「メッセージ属性」**に変更する
  • JSON のスペルミス("warning" のクォートが抜けている等)

「サブスクリプションを作成」をクリック。


④ Lambda 関数を2つ作成する

AWSコンソール → Lambda → 「関数の作成」(共通設定)

設定項目
作成方法一から作成
ランタイムPython 3.12
アーキテクチャx86_64
実行ロール「基本的な Lambda アクセス権限で新しいロールを作成」(デフォルトのまま)

コードを貼り付けたあと、必ず 「Deploy」 ボタンを押してコードを保存します。


4-1. LogFunction(全ログ処理)

関数名: LogFunction

コードエディタで lambda_function.py を開き、以下を貼り付けて「Deploy」をクリック。

import json


def lambda_handler(event, context):
    results = []

    for record in event["Records"]:
        sns_envelope = json.loads(record["body"])
        message = sns_envelope["Message"]  # 実際のメッセージ本文
        attributes = sns_envelope.get("MessageAttributes", {})
        level = attributes.get("level", {}).get("Value", "info")

        result = {
            "queue": "log",
            "level": level,
            "message": message,
        }
        print(json.dumps(result, ensure_ascii=False))
        results.append(result)

    print(json.dumps({"processedCount": len(results)}, ensure_ascii=False))
    return {"processedCount": len(results)}

json.loads(record["body"]) が必要な理由:
SNS → SQS 配信では、SQS のメッセージボディに SNS エンベロープ(JSON文字列)が格納されます。
そのため record["body"] はそのまま使えず、json.loads でパースする必要があります。

{
  "Type": "Notification",
  "TopicArn": "arn:aws:sns:...:NotificationTopic",
  "Message": "警告メッセージ",
  "MessageAttributes": {
    "level": {"Type": "String", "Value": "warning"}
  }
}

4-2. AlertFunction(アラート処理・DLQ テスト機能付き)

関数名: AlertFunction

import json


def lambda_handler(event, context):
    results = []

    for record in event["Records"]:
        sns_envelope = json.loads(record["body"])
        message = sns_envelope["Message"]
        attributes = sns_envelope.get("MessageAttributes", {})
        level = attributes.get("level", {}).get("Value", "unknown")

        # DLQテスト用: "error" というメッセージを受信したら意図的に例外発生
        if message.strip().lower() == "error":
            raise ValueError(
                f"アラート処理に失敗: level={level}, message={message}"
            )

        result = {
            "queue": "alert",
            "level": level,
            "message": message,
            "alert_triggered": True,
        }
        print(json.dumps(result, ensure_ascii=False))
        results.append(result)

    print(json.dumps({"processedCount": len(results)}, ensure_ascii=False))
    return {"processedCount": len(results)}

DLQ テストのしくみ:
message == "error" のとき意図的に ValueError を発生させています。
SQS は処理失敗を検知してメッセージをキューに戻し、可視性タイムアウト(180秒)後に再試行します。
これを3回繰り返すと AlertDLQ に移動します。


⑤ SQS トリガーを各 Lambda に追加する

5-1. LogFunction に LogQueue トリガーを追加する

Lambda → LogFunction → 「設定」タブ → 「トリガー」→「トリガーを追加」

設定項目
ソースSQS
SQS キューLogQueue
バッチサイズ5
トリガーの有効化オン

「追加」をクリック。

権限の追加:

Lambda → LogFunction → 「設定」タブ → 「アクセス権限」→ 実行ロール名をクリック(IAM コンソールへ)
→「許可を追加」→「ポリシーをアタッチ」→ AWSLambdaSQSQueueExecutionRole をアタッチ。

AWSLambdaSQSQueueExecutionRole が必要な理由:
Lambda が SQS からメッセージを受信(sqs:ReceiveMessage)・削除(sqs:DeleteMessage)するために必要な権限がまとまったポリシーです。これがないと Lambda がメッセージを取得できません。


5-2. AlertFunction に AlertQueue トリガーを追加する

Lambda → AlertFunction → 「設定」タブ → 「トリガー」→「トリガーを追加」

設定項目
ソースSQS
SQS キューAlertQueue
バッチサイズ1
トリガーの有効化オン

「追加」をクリック。権限の追加(AWSLambdaSQSQueueExecutionRole)も同様に実施する。

AlertFunction のバッチサイズを 1 にする理由:
1件ずつ処理することで、1件が失敗しても他のメッセージに影響が出ません。
DLQ へ移動するメッセージを1件に限定できるため、テストが分かりやすくなります。


⑥ 動作テスト

3つのシナリオで SNS フィルター・ファンアウト・DLQ の動作を確認します。

テストメッセージ属性LogFunctionAlertFunction確認ポイント
テスト1level=info処理 ✓処理しないフィルター動作
テスト2level=warning処理 ✓処理 ✓ファンアウト(1発行→2Lambda)
テスト3level=warning + body=error処理 ✓失敗→DLQDLQ 動作

テスト1: level=info(LogFunction のみ受信)

aws sns publish ^
  --topic-arn arn:aws:sns:ap-northeast-1:123456789012:NotificationTopic ^
  --message "情報メッセージ" ^
  --message-attributes "{\"level\":{\"DataType\":\"String\",\"StringValue\":\"info\"}}" ^
  --region ap-northeast-1

123456789012 を自分のアカウントIDに置き換えてください。

期待する動作:

  • LogFunction が処理 → CloudWatch Logs にログが記録される
  • AlertFunction は動作しない(フィルターで除外)

CloudWatch Logs で確認:

Lambda → LogFunction → 「モニタリング」タブ → 「CloudWatch Logs を表示」

{"queue": "log", "level": "info", "message": "情報メッセージ"}
{"processedCount": 1}

テスト2: level=warning(両 Lambda が受信 = ファンアウト)

aws sns publish ^
  --topic-arn arn:aws:sns:ap-northeast-1:123456789012:NotificationTopic ^
  --message "警告メッセージ" ^
  --message-attributes "{\"level\":{\"DataType\":\"String\",\"StringValue\":\"warning\"}}" ^
  --region ap-northeast-1

期待する動作:

  • LogFunction が処理(level=warning を受信)
  • AlertFunction も処理(フィルターを通過)
  • 1回の publish で 2つの Lambda が並行して動作する ← ファンアウトのポイント

LogFunction のログ:

{"queue": "log", "level": "warning", "message": "警告メッセージ"}

AlertFunction のログ:

{"queue": "alert", "level": "warning", "message": "警告メッセージ", "alert_triggered": true}


テスト3: level=warning + body=error(AlertFunction 失敗 → DLQ)

aws sns publish ^
  --topic-arn arn:aws:sns:ap-northeast-1:123456789012:NotificationTopic ^
  --message "error" ^
  --message-attributes "{\"level\":{\"DataType\":\"String\",\"StringValue\":\"warning\"}}" ^
  --region ap-northeast-1

期待する動作:

  • LogFunction → 正常処理(message=error でも例外なし)
  • AlertFunctionValueError 発生
  • AlertQueue の可視性タイムアウト(180秒)後に再試行 × 3回 → AlertDLQ に移動

DLQ に移動するまでの待機時間: 最大 180秒 × 3回 ≒ 9分かかります。
CloudWatch Logs で AlertFunction[ERROR] ValueError が 3回記録されたことを確認してから DLQ をポーリングするとよいです。

DLQ にメッセージが届いたか確認:

SQS → AlertDLQ → 「メッセージを送受信」→「メッセージをポーリング」

"error" のメッセージ(SNS エンベロープ形式)が表示されれば DLQ 動作確認完了。


⑦ リソースの削除

課金を止めるために、ハンズオン完了後は必ず削除してください。

1. Lambda のトリガーを削除する

  • Lambda → LogFunction → 「設定」→「トリガー」→ SQS トリガーを削除
  • Lambda → AlertFunction → 同様に削除

2. Lambda 関数を削除する

  • LogFunction / AlertFunction を削除

3. SNS サブスクリプションを削除する

SNS → NotificationTopic → 「サブスクリプション」タブ → 2つのサブスクリプションを削除

4. SNS Topic を削除する

SNS → トピック → NotificationTopic → 「削除」

5. SQS キューを3つ削除する

SQS → LogQueue / AlertQueue / AlertDLQ を各々削除

6. IAM ロールを削除する(任意)

IAM → ロール → LogFunction-role-XXXX / AlertFunction-role-XXXX を削除

7. CloudWatch Logs のロググループを削除する(任意)

CloudWatch → ロググループ → /aws/lambda/LogFunction / /aws/lambda/AlertFunction を削除

SAM版との大きな違い(SAMのメリット):
SAM版では sam delete 1コマンドで上記すべてのリソースを一括削除できます。


SAMとの対比

SAMの記述コンソールでやること
AWS::SNS::TopicSNS → トピックを作成
AWS::SQS::QueuePolicySNS サブスクリプション作成時に自動追加される
AWS::SNS::SubscriptionSNS → サブスクリプションを作成(フィルターポリシー含む)
FilterPolicy: '{"level": ...}'サブスクリプション作成時の「フィルターポリシー」に JSON を入力
SQSPollerPolicy × 2Lambda の IAM ロールに AWSLambdaSQSQueueExecutionRole をアタッチ
sam deleteSNS / SQS × 3 / Lambda × 2 / IAM / ロググループを個別に削除

コンソール版の最大のつまずきポイント:
SNS の「サブスクリプション」を作り忘れると、SNS publish しても SQS キューにメッセージが届きません。
「キューにメッセージが来ない」と感じたら、まずサブスクリプションが正しく作成されているか確認しましょう。


トラブルシューティング

症状原因対処
SNS publish してもキューにメッセージが来ないSNS サブスクリプションが未作成SNS → NotificationTopic → 「サブスクリプション」タブで2つ作成されているか確認
SNS publish してもキューにメッセージが来ない(その2)SQS キューポリシーが設定されていないSQS → キュー → 「アクセスポリシー」タブで sns.amazonaws.com からの sqs:SendMessage があるか確認
level=warning でも AlertQueue に届かないフィルターポリシーのスコープが「メッセージ本文」になっているSNS → サブスクリプション → フィルターポリシーのスコープを**「メッセージ属性」**に変更
Lambda が実行されないSQS トリガーが設定されていない⑤ の手順でトリガーを追加する
Lambda が実行されない(SQS権限エラー)AWSLambdaSQSQueueExecutionRole がアタッチされていない⑤ の権限追加手順を実施する
DLQ にメッセージが届かない可視性タイムアウト(180秒)× 3回 の待機中最大 9分待つ。CloudWatch Logs で 3回の ERROR ログを確認してからポーリング
SNS エンベロープの構造が分からないLambda のコードで print(record["body"]) して CloudWatch Logs で確認する

まとめ

今回のハンズオンで体験できたこと:

確認項目内容
Pub/Sub パターンPublisher は誰が受け取るか知らずに SNS Topic に発行するだけ。Subscriber(SQS)が購読して処理
ファンアウトlevel=warning の1回の publish で LogFunction と AlertFunction の両方が並行して動作
SNS フィルターポリシーlevel=info は LogQueue のみ配信、level=warning/critical は両キューに配信
DLQAlertFunction が 3回失敗したメッセージが AlertDLQ に退避

コンソール版で実感できたポイント

  • SNS Topic / SQS キュー / Lambda という3つのリソースの組み合わせ方が視覚的に理解できる
  • SNS サブスクリプションのフィルターポリシーJSON を直接入力することで、ルールの書き方が身につく
  • リソースを1つずつ作成することで、各サービスの役割と依存関係が明確になる

コンソール版と SAM 版を比較してみる

コンソールで SNS + SQS + Lambda の連携を理解したら、SAM で同じ構成をコードで定義することで「SAM が何を自動化しているか」が明確になります。AWS::SQS::QueuePolicy の明示的な記述や SQSPollerPolicy によるワンライン権限付与など、コンソールでの手動操作がコードに対応しています。


関連記事

Amazon検索[本 AWS 開発]

コメント