---
title: "デッドレターキュー（DLQ）とは：退避条件・再処理・監視の設計とSQS・Pub/Sub・Service Busの設定例"
url: "https://www.issoh.co.jp/tech/details/19037/"
published: 2026-10-29
updated: 2026-10-29
categories: ["インフラ・クラウド"]
publisher: "株式会社一創"
---

# デッドレターキュー（DLQ）とは：退避条件・再処理・監視の設計とSQS・Pub/Sub・Service Busの設定例

デッドレターキュー（DLQ）は、何度受信しても処理に失敗するメッセージを本来のキューから外し、別の場所に保管しておくための退避先です。この記事では、メッセージがDLQへ移る条件、SQS・Pub/Sub・Service Bus・RabbitMQ・Kafka Connectでの設定値の違い、AWS CLIとgcloudによる設定手順、溜まったメッセージを再処理する流れ、滞留を検知するアラームの掛け方までを順に扱います。DLQを置いたのに誰も中身を見ていない、という状態を避けるための設計判断も条件付きで示します。

## まとめ：DLQは失敗の隔離先であり、再処理と監視を同時に設計して初めて機能する

DLQの役割は、処理できないメッセージ（毒メッセージ）が後続の処理を詰まらせないよう隔離することにあります。隔離しただけでは失敗は解決しません。原因を直したあとに元のキューへ戻す手順と、DLQに1件でも入ったら気づける監視をセットで用意して、ようやく運用に乗ります。

受信回数の上限は基盤ごとに既定値が違い、Pub/Subは既定5回、Service Busは既定10回、SQSは自分で決める方式です。Kafkaのようにブローカー側にDLQを持たない基盤もあります。厳密な順序が必要な処理や、呼び出し元へ即座にエラーを返す同期APIでは、DLQより別の失敗処理が向いています。

## デッドレターキューの定義と、メッセージがDLQへ退避される4つの条件

### 毒メッセージを隔離し、後続の処理が詰まるのを防ぐというDLQの役割

名前の由来は郵便の「配達も返送もできない郵便物」を保管する部署で、メッセージングでも同じく「届け先で処理できず、捨てることもできないメッセージ」の置き場を指します。不正な形式のJSON、存在しない顧客IDを参照する注文、コンシューマーのバグで必ず例外になる入力などが典型例です。

DLQが無い場合、こうしたメッセージはキューに戻されて再配信され続けます。SQSのFIFOキューでは、失敗したメッセージが同じメッセージグループの後続を止めてしまうと[SQSのCloudWatchメトリクスの説明](https://docs.aws.amazon.com/ja%5Fjp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html)に明記されています。1件の不良データが業務全体の遅延になる構造を断つのがDLQの仕事です。

### 受信回数超過・有効期限切れ・明示的な拒否・サイズ超過という退避条件

どの基盤でも、退避の引き金はおおむね次の4種類に分かれます。

- 受信・配信の回数超過：SQSのmaxReceiveCount、Pub/Subの最大配信試行回数、Service BusのMaxDeliveryCount
- 有効期限（TTL）切れ：Service BusやRabbitMQで、期限を過ぎたメッセージを退避する設定
- アプリケーションによる明示的な拒否：RabbitMQのbasic.rejectやService BusのDeadLetterMessageAsync
- サイズや長さの上限超過：RabbitMQのキュー長制限、Service BusのHeaderSizeExceeded

実務で最も多いのは1つ目の回数超過です。RabbitMQの[Dead Letter Exchangesのドキュメント](https://www.rabbitmq.com/docs/dlx)では、拒否・TTL切れ・キュー長超過・クォーラムキューのdelivery-limit超過の4つが条件として並び、キュー自体の期限切れでは退避されないと書かれています。

### リトライと冪等性が前提になる理由と、DLQだけでは足りない場面

DLQはリトライを使い切ったあとの受け皿です。何回・どの間隔で再試行するかは[リトライパターンの設計（指数バックオフとリトライ予算）](https://www.issoh.co.jp/tech/details/16185/)の領分で、DLQの上限回数はその設計と整合している必要があります。

もう1つの前提が冪等性です。DLQから戻したメッセージは「一度は途中まで処理された」可能性を持ちます。在庫の引き当てや課金のように副作用がある処理は、[冪等性キーや一意制約による二重処理の防止](https://www.issoh.co.jp/tech/details/13382/)が無いと、再処理のたびに二重計上が起きます。

## 主要メッセージ基盤のDLQ設定比較：上限回数・既定値・保持の違い

### 5つの基盤で異なる受信回数の上限・既定値・DLQの作り方の比較表

同じ「DLQ」でも、作り方と既定値はかなり違います。2026年10月時点の各公式ドキュメントから要点をまとめました。

| 基盤            | 回数の設定            | 既定値       | DLQの実体   |
| ------------- | ---------------- | --------- | -------- |
| Amazon SQS    | maxReceiveCount  | 自分で指定     | 別キューを作成  |
| Pub/Sub       | 最大配信試行回数         | 5回（5〜100） | 別トピックを作成 |
| Service Bus   | MaxDeliveryCount | 10回       | 自動のサブキュー |
| RabbitMQ      | delivery-limit   | クォーラムのみ   | DLXで転送   |
| Kafka Connect | errors.tolerance | none      | DLQトピック  |

Service Busは[配信不能キューの公式解説](https://learn.microsoft.com/ja-jp/azure/service-bus-messaging/service-bus-dead-letter-queues)のとおり、キューごとに`$deadletterqueue`というサブキューが自動で付き、明示的に作る必要がありません。一方でDLQは自動で掃除されず、取り出して完了するまで残り続けます。Pub/Subの上限回数は[Dead-letter topicsのドキュメント](https://docs.cloud.google.com/pubsub/docs/dead-letter-topics)で「概数」とされ、設定値より少ない回数で転送されることもあります。

### KafkaのブローカーにDLQは無く、Connectやコンシューマーで退避先を組む構成

Kafkaのブローカーには、受信回数を数えて自動で退避する仕組みがありません。コンシューマーがオフセットを進めるかどうかを自分で決める設計のため、DLQはアプリケーション側で「失敗したレコードを別トピックへ書く」形で実装します。

Kafka Connectのシンクコネクタには標準の設定があります。[Confluentのシンクコネクタ設定リファレンス](https://docs.confluent.io/platform/current/installation/configuration/connect/sink-connect-configs.html)によると、errors.toleranceの既定はnoneで、1件のエラーでタスクが停止する設定です。allにしてDLQトピック名を指定すると、変換や書き込みに失敗したレコードだけがDLQへ回ります。コネクタ全体の構成は[Kafka Connectの構成要素とコネクタ運用](https://www.issoh.co.jp/tech/details/16086/)で扱っています。

```
# シンクコネクタの設定（失敗レコードをDLQトピックへ回す）
errors.tolerance=all
errors.deadletterqueue.topic.name=dlq-orders-sink
errors.deadletterqueue.topic.replication.factor=3
errors.deadletterqueue.context.headers.enable=true
```

context.headers.enableの既定はfalseです。trueにすると`__connect.errors.`で始まるヘッダに例外の情報が入るため、原因の切り分けが格段に楽になります。

### Lambda非同期呼び出しのDLQと失敗時の送信先で、残る情報が異なる点

AWS Lambdaの非同期呼び出しには、関数単位のDLQと「失敗時の送信先（on-failure destination）」の2つの退避先があります。[Lambda非同期呼び出しのレコードのキャプチャ](https://docs.aws.amazon.com/ja%5Fjp/lambda/latest/dg/invocation-async-retain-records.html)によれば、DLQに入るのはイベント本体とRequestID・ErrorCode・ErrorMessage（先頭1KB）の属性だけです。送信先のほうは、条件や試行回数、関数の応答まで含むJSONレコードを送ります。

送信先はSQS・SNSに加えてS3・Lambda・EventBridgeも選べます。新しく作るなら送信先を選び、既存のDLQ設定は理由が無ければ移行するのが筋です。EventBridgeとSQSを組み合わせた構成でDLQをどこに置くかは[EventBridge・SQS・Lambda構成でのDLQの置き場所](https://www.issoh.co.jp/tech/details/6034/)にまとめています。

## DLQを設定する手順：AWS CLI・gcloud・rabbitmqctlのコマンド例

### SQSのRedrivePolicyで受信5回後にDLQへ送る設定のコマンド例

SQSでは、先にDLQ用のキューを作り、そのARNを元キューのRedrivePolicyに書きます。DLQは元キューと同じAWSアカウント・同じリージョンに置く決まりです。

```
# 1. DLQを作る（保持期間は元キューより長い10日に）
aws sqs create-queue --queue-name orders-dlq \
  --attributes MessageRetentionPeriod=864000

# 2. 元キューにRedrivePolicyを設定する（redrive.json）
# {"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:ap-northeast-1:123456789012:orders-dlq\",\"maxReceiveCount\":\"5\"}"}
aws sqs set-queue-attributes \
  --queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/orders \
  --attributes file://redrive.json
```

DLQ側に付けられるのがredriveAllowPolicyです。[SQSのデッドレターキューの説明](https://docs.aws.amazon.com/ja%5Fjp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)では、既定は全キューに許可、byQueueなら送信元を最大10個まで指定でき、denyAllでDLQとしての利用を禁止できます。本番では無関係なキューが紛れ込まないよう、byQueueで送信元を絞っておくことが事故を減らす対策です。FIFOキューや可視性タイムアウトとの関係は[Amazon SQSのFIFOキューとDLQ設計](https://www.issoh.co.jp/tech/details/17241/)で詳しく扱っています。

### Pub/Subのデッドレタートピック作成と、2つのロールを付与する手順

Pub/Subでは、DLQはトピックとして作り、サブスクリプションに紐づけます。見落としやすいのが権限で、Pub/Subのサービスエージェントに、DLトピックへのパブリッシャー権限と元サブスクリプションへのサブスクライバー権限の2つが必要です。

```
PROJECT_NUMBER=123456789012
SA_LOCAL="service-${PROJECT_NUMBER}"
SA_DOMAIN="gcp-sa-pubsub.iam.gserviceaccount.com"

gcloud pubsub topics create orders-dead-letter
gcloud pubsub subscriptions update orders-sub \
  --dead-letter-topic=orders-dead-letter \
  --max-delivery-attempts=5

gcloud pubsub topics add-iam-policy-binding orders-dead-letter \
  --member="serviceAccount:${SA_LOCAL}@${SA_DOMAIN}" \
  --role="roles/pubsub.publisher"
gcloud pubsub subscriptions add-iam-policy-binding orders-sub \
  --member="serviceAccount:${SA_LOCAL}@${SA_DOMAIN}" \
  --role="roles/pubsub.subscriber"
```

サブスクライバー権限が抜けていると、転送後に元のメッセージを確認応答できず、同じメッセージが元のサブスクリプションに残ります。DLトピック自体にもサブスクリプションを作っておかないと、退避したメッセージは誰にも読まれずに消えていく点に注意してください。トピックとサブスクリプションの基本構造は[Cloud Pub/Subの仕組みと送受信の実装](https://www.issoh.co.jp/tech/details/12385/)で確認できます。

### RabbitMQはポリシーでDLXを指定し、キューの再宣言を避ける設定

RabbitMQでは、退避先をキューではなくエクスチェンジ（DLX）で指定します。キュー宣言時の引数でも書けますが、公式はポリシーでの指定を勧めています。引数は、アプリを再デプロイしてキューを削除・再宣言しないと変えられないからです。

```
rabbitmqctl set_policy DLX "^orders$" \
  '{"dead-letter-exchange":"orders.dlx","delivery-limit":5}' \
  --apply-to queues --priority 7
```

DLXは同じvhostに存在している必要があり、退避の時点で無ければメッセージは黙って破棄されます。退避されたメッセージには`x-death`ヘッダが付き、reasonにrejected・expired・maxlen・delivery\_limitのいずれかが入るので、再処理の振り分けに使えます。

## DLQに溜まったメッセージの再処理設計：原因の切り分けと戻し方の手順

### 再処理の前に、一時障害と恒久障害を失敗理由の属性で振り分ける

DLQの中身は、戻せば通るものと何度戻しても失敗するものが混ざっています。外部APIの一時的な停止で失敗したメッセージは原因の復旧後にそのまま戻せますが、データ不正やバグ由来のものは、修正を出すまで戻しても再びDLQへ落ちるだけです。

振り分けに使える材料は、基盤ごとに異なる属性です。Service BusにはDeadLetterReasonとDeadLetterErrorDescriptionがあり、RabbitMQには`x-death`、Kafka Connectにはエラー用ヘッダ、Lambdaの退避先にはErrorCodeが付きます。SQSのRedrivePolicyで移ったメッセージには失敗理由を示す属性が付かないため、コンシューマーが失敗時にMessageIdと例外をログへ出しておくことが前提になります。

```
import boto3

sqs = boto3.client("sqs", region_name="ap-northeast-1")
url = sqs.get_queue_url(QueueName="orders-dlq")["QueueUrl"]

# 中身の確認だけ行い、削除はしない（可視性タイムアウト後に戻る）
resp = sqs.receive_message(
    QueueUrl=url,
    MaxNumberOfMessages=10,
    WaitTimeSeconds=5,
    VisibilityTimeout=30,
    MessageSystemAttributeNames=["ApproximateReceiveCount", "SentTimestamp"],
    MessageAttributeNames=["All"],
)
for m in resp.get("Messages", []):
    print(m["MessageId"], m["Attributes"], m.get("MessageAttributes", {}))
```

### SQSのStartMessageMoveTaskで毎秒の移動件数を絞って元のキューへ戻す

SQSには、DLQのメッセージを一括で戻すAPIがあります。[StartMessageMoveTaskのAPIリファレンス](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API%5FStartMessageMoveTask.html)によると、移動先を省略すれば元のキューへ戻り、移動速度は毎秒最大500件まで指定できます。1つのキューで同時に動かせるタスクは1つだけです。

```
aws sqs start-message-move-task \
  --source-arn arn:aws:sqs:ap-northeast-1:123456789012:orders-dlq \
  --max-number-of-messages-per-second 10

# 進捗の確認と中止
aws sqs list-message-move-tasks \
  --source-arn arn:aws:sqs:ap-northeast-1:123456789012:orders-dlq
aws sqs cancel-message-move-task --task-handle "<TaskHandle>"
```

速度を空欄にすると、滞留量に応じてSQSが速度を決めます。下流のDBや外部APIが復旧直後で弱っている場面では、10件程度から始めて様子を見るほうが安全です。この機能は送信元がSQSキューであるDLQだけが対象で、LambdaやSNSのDLQには使えません。その場合は自前のスクリプトで受信して再送信します。

### 戻す前に冪等性を確かめないと二重処理が起きる、FIFOでの順序の崩れ

再処理で最も多い事故は、途中まで成功していた処理をもう一度走らせることです。決済の確定まで進んでから通知の送信で失敗したメッセージを戻すと、決済が二重に走ります。冪等性キーで「処理済み」を判定できる作りかどうかを、戻す前に確認してください。

FIFOキューでは順序の問題も起きます。DLQへ移ったメッセージは元の並びから外れており、後続のメッセージはすでに処理済みの状態です。SQSの公式ドキュメントも、厳密な順序を守る必要がある場合はFIFOキューでDLQを使わないよう注意しています。

## DLQの監視とアラート設計：見るべきメトリクスと誤検知を生む落とし穴

### DLQの滞留件数メトリクスに1件以上でアラームを掛けるCLIの設定例

DLQの監視は、滞留件数が1件以上になったら通知、という単純な条件で十分です。DLQに入るのは「通常は起きないこと」なので、件数のしきい値を高くすると、気づいたときには保持期間切れで消えていることになります。

```
aws cloudwatch put-metric-alarm \
  --alarm-name orders-dlq-not-empty \
  --namespace AWS/SQS \
  --metric-name ApproximateNumberOfMessagesVisible \
  --dimensions Name=QueueName,Value=orders-dlq \
  --statistic Maximum --period 300 --evaluation-periods 1 \
  --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold \
  --alarm-actions arn:aws:sns:ap-northeast-1:123456789012:ops-alerts
```

あわせてApproximateAgeOfOldestMessageを見ると、放置されている期間がわかります。EventBridgeのターゲットに付けたDLQの調べ方は[EventBridgeのログとDLQのERROR\_CODEでの原因特定](https://www.issoh.co.jp/tech/details/18449/)が参考になります。

### NumberOfMessagesSentでは自動退避を数えられない、という計測上の注意

DLQへの流入件数をNumberOfMessagesSentで数えようとすると、0のまま動きません。[SQSのメトリクス一覧](https://docs.aws.amazon.com/ja%5Fjp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html)には、maxReceiveCountを超えて自動で移ったメッセージはこのメトリクスに含まれないと書かれています。手動でDLQへ送信した分だけが数えられる仕様です。

ダッシュボードで「DLQ流入0件」と表示されていても安心できない、ということになります。DLQの監視にはApproximateNumberOfMessagesVisibleを使うよう公式も推奨しています。

### DLQの保持期間を元キューより長くする理由と、エンキュー時刻の扱い

SQSの標準キューでは、DLQに移ったあとも有効期限は元のエンキュー時刻から数えられます。元キューで1日経ってからDLQ（保持4日）に移ると、残りは3日しかありません。週末をまたぐと調査前に消える計算です。

FIFOキューでは移動時にエンキュー時刻がリセットされ、DLQの保持期間をまるごと使えます。どちらの場合も、DLQの保持期間は元キューより長く取るのが公式のベストプラクティスです。

## DLQを入れるべき処理と入れない処理：採用条件と見送る場面の線引き

### 非同期で順序に依存しない処理はDLQを必ず置き、退避先を監視する

キューやイベント経由で非同期に動く処理で、1件ずつ独立して成否が決まるものは、DLQを置かない理由がありません。メール送信、画像変換、外部SaaSへのデータ連携、注文イベントの集計などが該当します。

DLQを置くときは、上限回数・保持期間・アラーム・再処理の手順の4点を同時に決めます。DLQだけ作って監視が無い構成は、エラーを見えない場所へ移しただけで、DLQが無い状態より発見が遅れる分むしろ悪化します。

### 厳密な順序が要る処理や同期APIではDLQを置かず、別の失敗処理にする

口座残高の更新のように、前のメッセージが失敗したら後続も止めるべき処理では、DLQで失敗を外すと整合性が壊れます。この場合はDLQを置かず、処理を止めてアラートを上げ、人が判断してから再開する設計にします。

ユーザーの画面から呼ばれる同期APIも対象外です。呼び出し元へエラーを返せば利用者が再操作できるので、裏側で失敗を溜めておく意味がありません。DLQは「誰も待っていない処理」のための仕組みと割り切るのが判断の軸です。

### 設計レビューでDLQ運用の抜けを点検する観点と、外部へ相談する場面

既存システムのレビューでは、DLQの有無より「DLQに入った後」を確認します。アラームの通知先が実在する担当者に届くか、再処理の手順書があるか、再処理しても二重処理にならないか、の3点で多くの抜けが見つかります。

メッセージ基盤の選定やAWS上の非同期構成の設計から見直したい場合は、[AWS・Google Cloud・Azureのインフラ構築支援](https://www.issoh.co.jp/service/system/aws/)で、キュー設計と監視の組み立てを含めてご相談いただけます。

## デッドレターキューの設定・再処理・監視の判断についてのよくある質問

DLQの設計でよく寄せられる疑問に、公式ドキュメントの記述をもとに回答します。

### DLQの最大受信回数（maxReceiveCount）は何回に設定すればよいですか？

設定の基準は、一時障害がリトライで回復するのに必要な回数です。SQSの公式は、1のような低い値だと1回の失敗でDLQへ移るため、回復力を持たせるなら高めに設定するよう勧めています。回数の目安は、Pub/Subの既定5回、Service Busの既定10回です。可視性タイムアウトとの掛け算で、DLQへ移るまでの時間が決まる点も考慮してください。

### デッドレターキューとリトライはどう使い分けますか？

リトライは一時障害から自動で回復するための仕組みで、DLQはリトライを使い切っても失敗したメッセージの退避先です。どちらか一方を選ぶものではなく、リトライの上限に達した後の行き先としてDLQを置く関係にあります。リトライの回数と間隔はDLQの上限回数と整合させて設計します。

### DLQに入ったメッセージは自動で消えますか？

自動で消えるかどうかは、基盤ごとに異なる仕様です。SQSは保持期間を過ぎると削除され、標準キューでは元のエンキュー時刻から数えられます。Service Busの配信不能キューは自動でクリーンアップされず、取り出して完了するまで残る仕様です。消える基盤では保持期間内に調査できるよう、アラームとの組み合わせが前提になります。

### SQSのFIFOキューでもDLQは使えますか？

SQSのFIFOキューでもDLQは利用可能です。ただし、DLQへ移ったメッセージは元の順序から外れ、後続のメッセージが先に処理される仕組みです。SQSの公式ドキュメントも、正確な順序を維持する必要がある場合はFIFOキューでDLQを使わないよう注意しています。順序が業務上の整合性に直結するなら、DLQではなく処理停止とアラートで対応します。

### KafkaでDLQを実装するにはどうすればよいですか？

Kafkaのブローカーには自動で退避する仕組みが無いため、アプリケーション側で失敗レコードを別トピックへ書き込みます。Kafka Connectのシンクコネクタなら、errors.toleranceをallにし、errors.deadletterqueue.topic.nameにトピック名を指定するだけで設定が可能です。自前のコンシューマーでは、例外を捕まえてDLQトピックへ送信してからオフセットを進める実装にします。

## 関連記事

- [Amazon SQSとは？FIFOキューと標準キューの違い・重複排除・可視性タイムアウトとDLQの設計](https://www.issoh.co.jp/tech/details/17241/)：SQSでのmaxReceiveCountの決め方とFIFOでの挙動の詳細。
- [Azure Service Busとは？キューとトピックの仕組み・料金の実額と階層の選び方](https://www.issoh.co.jp/tech/details/15527/)：配信不能サブキューを持つService Busの全体像。
- [Cloud Pub/Subとは？トピックとサブスクリプションの仕組み・料金・Pythonでの送受信](https://www.issoh.co.jp/tech/details/12385/)：デッドレタートピックを設定する前提の基本構造。
- [RabbitMQとKafkaの違いとは？設計思想・性能・使い分けの判断基準](https://www.issoh.co.jp/tech/details/15305/)：DLQの作り方が異なる2つの基盤の選び分け。
- [EventBridgeとSQS・Lambdaの非同期構成｜キューポリシー・部分バッチ応答・DLQの置き場所](https://www.issoh.co.jp/tech/details/6034/)：AWSの非同期構成でDLQを置く位置の具体例。

---

出典: [デッドレターキュー（DLQ）とは：退避条件・再処理・監視の設計とSQS・Pub/Sub・Service Busの設定例](<https://www.issoh.co.jp/tech/details/19037/>)（株式会社一創）
