🍽️ レストランの注文システムで例えると超わかりやすい!
SQSは「レストランの注文伝票システム」のようなもの!
注文が正常に処理できない場合、どうしますか?
Dead-letter Queue (DLQ)
= 問題のある注文を別の場所に保管
Redrive Policy
= 何回失敗したら別の場所に移すかのルール
この仕組みを完璧にマスターしましょう✨
📚 基本概念:レストラン vs AWS
📋 注文伝票トレイ
厨房に届く注文伝票を置く場所
👨🍳 シェフ(処理担当)
注文を見て料理を作る人
❌ 作れない注文
材料不足、レシピ不明など
🗂️ 問題注文ボックス
処理できない注文を別管理
📏 再試行ルール
「3回失敗したら問題ボックスへ」
📬 Standard Queue(通常キュー)
メッセージを保管するメインキュー
⚙️ Consumer(コンシューマー)
メッセージを処理するアプリケーション
❌ 処理失敗メッセージ
エラーや例外で処理できないメッセージ
💀 Dead-letter Queue (DLQ)
失敗メッセージを隔離する専用キュー
🔄 Redrive Policy
maxReceiveCount = 何回で移動するか
🎨 全体の流れ - ビジュアル図解
メッセージが3回処理失敗したら自動的にDLQへ移動
🔄 メッセージ処理フロー:5つのステップ
☁️ AWS: Consumerがメインキューからメッセージを取得
→ ReceiveMessageが実行される
☁️ AWS: アプリケーションロジックでメッセージを処理
→ ビジネスロジックの実行
☁️ AWS: 例外エラーが発生、DeleteMessageが呼ばれない
→ メッセージはキューに残る(ReceiveCountが+1)
☁️ AWS: ReceiveCount < maxReceiveCount なら再度キューに戻る
→ Visibility Timeout後に再度取得可能
☁️ AWS: ReceiveCount ≥ maxReceiveCount でDLQへ自動移動
→ 後で原因調査と修正が可能
⚖️ 正常処理 vs 問題発生時の違い
- 1️⃣ メッセージ受信 (ReceiveMessage)
- 2️⃣ 処理成功 (ビジネスロジック実行)
- 3️⃣ メッセージ削除 (DeleteMessage)
- 🎉 完了!キューから消える
- 1️⃣ メッセージ受信 (ReceiveMessage)
- 2️⃣ 処理失敗 (例外エラー発生)
- 3️⃣ DeleteMessage呼ばれず
- 4️⃣ ReceiveCount +1 (受信回数カウント)
- 5️⃣ Visibility Timeout後に再度出現
- 6️⃣ maxReceiveCount到達でDLQへ
- 💀 DLQで隔離・原因調査
⚙️ Redrive Policy 設定方法
推奨値: 3〜5回
🍽️ 例: 「3回作れなかったら問題ボックスへ」
注意: 1回だと誤検知が多く、10回以上だと遅すぎる
形式: arn:aws:sqs:region:account:queue-name
🍽️ 例: 「問題注文ボックスの場所」
注意: 事前にDLQ用のキューを作成しておく必要あり
推奨値: 処理時間の6倍
🍽️ 例: 「この注文は今調理中」の札を付ける時間
注意: 短すぎると重複処理、長すぎるとリトライが遅い
推奨値: 14日間(最大)
🍽️ 例: 「問題注文を2週間保管」
注意: DLQは長めに設定して原因調査の時間を確保
# 1. DLQ用のキューを作成 aws sqs create-queue \ --queue-name my-app-dlq \ --attributes MessageRetentionPeriod=1209600 # 14日間 # 2. DLQのARNを取得 aws sqs get-queue-attributes \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/my-app-dlq \ --attribute-names QueueArn # 3. メインキューにRedrive Policyを設定 aws sqs set-queue-attributes \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/my-main-queue \ --attributes '{ "RedrivePolicy": "{ \"deadLetterTargetArn\": \"arn:aws:sqs:ap-northeast-1:123456789012:my-app-dlq\", \"maxReceiveCount\": \"3\" }", "VisibilityTimeout": "300" }'
# DLQ用のキュー resource "aws_sqs_queue" "dlq" { name = "my-app-dlq" message_retention_seconds = 1209600 # 14日 tags = { Name = "My App DLQ" Environment = "production" } } # メインキュー(Redrive Policy設定済み) resource "aws_sqs_queue" "main" { name = "my-main-queue" visibility_timeout_seconds = 300 # 5分 message_retention_seconds = 345600 # 4日 # 🔄 Redrive Policy設定 redrive_policy = jsonencode({ deadLetterTargetArn = aws_sqs_queue.dlq.arn maxReceiveCount = 3 }) tags = { Name = "My Main Queue" Environment = "production" } } # 💀 DLQからメインキューへのRedrive設定(オプション) resource "aws_sqs_queue_redrive_allow_policy" "dlq_redrive" { queue_url = aws_sqs_queue.dlq.id redrive_allow_policy = jsonencode({ redrivePermission = "byQueue" sourceQueueArns = [aws_sqs_queue.main.arn] }) }
💼 実際のユースケース
メール配信システム
メールアドレスが無効、SMTPサーバーダウン
設定:
maxReceiveCount = 5
→ 5回失敗したらDLQへ
対応:
DLQのメッセージを見て無効アドレスをDBから削除
決済処理システム
外部API障害、タイムアウト、データ不整合
設定:
maxReceiveCount = 3
→ すぐに隔離して手動確認
対応:
重要度が高いので即座にアラート発行、手動再処理
データ分析バッチ
不正なデータフォーマット、計算エラー
設定:
maxReceiveCount = 2
→ 少ない回数で早めに分離
対応:
DLQメッセージを分析してデータバリデーション改善
画像変換サービス
破損画像、未対応フォーマット、メモリ不足
設定:
maxReceiveCount = 4
→ 一時的エラーを考慮して少し多め
対応:
問題ファイルのパターンを分析してエラー処理強化
✅ ベストプラクティス
• 1回:誤検知が多すぎる
• 10回以上:問題発見が遅れる
• 処理の重要度とコストを考慮して決定
• ApproximateNumberOfMessagesVisible > 0
• メッセージがDLQに入ったら即座に通知
• Slackやメールで開発チームへアラート
• エラー理由、タイムスタンプ
• 元のReceiveCount
• 処理試行時のログID
→ 原因調査が劇的に楽になる
• AWSコンソールの「Start DLQ redrive」
• 修正済みメッセージを元のキューへ
• 一括処理が可能で効率的
• メインキュー:4日間
• DLQ:14日間
→ 問題調査と修正の時間を十分確保
• my-app-dev-dlq
• my-app-staging-dlq
• my-app-prod-dlq
→ 環境間の混乱を防止
→ 失敗メッセージが永遠にリトライされ続ける。Visibility Timeout後に何度も処理されてコストが増大。
❌ 間違い2: maxReceiveCountを1に設定
→ 一時的なネットワークエラーなどでも即DLQ行きになり、誤検知が多すぎる。
❌ 間違い3: DLQの監視をしない
→ メッセージがDLQに溜まっていることに気づかず、重要な処理が止まったまま。
❌ 間違い4: 処理失敗時にDeleteMessageを呼ぶ
→ リトライの機会を失い、データロスの原因に。エラー時はDeleteしてはいけない。
❌ 間違い5: DLQのRetention期間が短い
→ 原因調査中にメッセージが消えてしまい、問題の再現ができなくなる。
CloudWatch Logsにエラーパターンを集約し、どの種類のエラーが多いか可視化。優先度をつけて対応。
🔍 Tip 2: Lambda DLQトリガーで自動分析
DLQにメッセージが入ったらLambdaを起動し、エラー分類を自動実行。Slackに詳細レポート送信。
⚙️ Tip 3: 段階的リトライ戦略
maxReceiveCount=3でDLQ行き → Lambda処理 → 修正可能なら元のキューへRedrive → 不可能ならS3へアーカイブ。
🧪 Tip 4: DLQでテスト環境を作る
本番のDLQメッセージをコピーして開発環境で再現テスト。実際の問題データで検証できて確実。
📈 Tip 5: エラー率をKPIとして追跡
(DLQメッセージ数 / 総メッセージ数) × 100 = エラー率。週次レポートで改善トレンドを可視化。
import boto3 import json import logging from time import sleep logger = logging.getLogger() logger.setLevel(logging.INFO) sqs = boto3.client('sqs', region_name='ap-northeast-1') QUEUE_URL = 'https://sqs.ap-northeast-1.amazonaws.com/123456789012/my-main-queue' def process_message(message_body): """ビジネスロジック:ここで実際の処理を実行""" # 例:外部APIを呼び出す、DBに書き込むなど data = json.loads(message_body) # 何らかの処理... if data.get('invalid'): raise ValueError("Invalid data format") return True def consume_messages(): """メッセージを受信して処理する""" while True: # メッセージを受信(Long Polling: 20秒) response = sqs.receive_message( QueueUrl=QUEUE_URL, MaxNumberOfMessages=10, # 一度に10件まで WaitTimeSeconds=20, # Long Polling AttributeNames=['ApproximateReceiveCount'] ) messages = response.get('Messages', []) if not messages: logger.info("No messages, waiting...") continue for message in messages: receipt_handle = message['ReceiptHandle'] message_id = message['MessageId'] body = message['Body'] receive_count = int(message['Attributes'].get('ApproximateReceiveCount', 0)) logger.info(f"Processing message {message_id} (ReceiveCount: {receive_count})") try: # ✅ ビジネスロジック実行 process_message(body) # ✅ 成功したらメッセージを削除 sqs.delete_message( QueueUrl=QUEUE_URL, ReceiptHandle=receipt_handle ) logger.info(f"Successfully processed message {message_id}") except Exception as e: # ❌ エラー発生時はDeleteしない → 自動的にキューに戻る logger.error(f"Failed to process message {message_id}: {str(e)}") logger.error(f"Receive count: {receive_count}. Will retry or move to DLQ.") # ⚠️ DeleteMessageを呼ばないことで: # 1. Visibility Timeout後に再度処理可能になる # 2. ReceiveCountが+1される # 3. maxReceiveCountに達したら自動的にDLQへ continue if __name__ == "__main__": logger.info("Starting SQS Consumer...") consume_messages()
🎓 まとめ
🍽️ レストランの問題注文システム = SQS DLQ
Dead-letter Queue と Redrive Policy で
失敗メッセージを適切に管理
できる✨
失敗メッセージを
安全に隔離して
後で調査
何回失敗したら
DLQへ移動するかの
ルール設定
DLQにメッセージが
入ったら即座に
アラート通知
🎯 重要ポイント:
1️⃣
maxReceiveCount = 3〜5
が推奨
2️⃣ エラー時は
DeleteMessage を呼ばない
3️⃣
CloudWatch Alarm
でDLQ監視
4️⃣ 問題修正後は
Redrive機能
で再処理
5️⃣ DLQのRetention期間は
14日間
(最大)
🎉
これでSQSの失敗処理はバッチリ!
安心してメッセージキューを運用できます!