Dev Study
AWSサービスの内部原理 コース

50. プッシュ配信の宿命 — SNSは再試行し尽くすと捨てる

SNSに送ったメッセージが受信側の障害でどう扱われ、最後にどこへ行き着くのかを、配信ポリシーの4フェーズを図で追っていきます。

① プッシュ型では送信側が受信側の面倒を見る

Publishメッセージがトピックに届く
誰がリトライを担うか?
SNS=ルーターエンドポイントを叩きに行く
受信側が5XX/429を返す(=一時的失敗としてretryable)
プル型(SQS)受信側が取りに来る
キューが貯蔵して待てる
プッシュ型(SNS)送信側が再送で面倒を見る
  • SNSは配信プロトコルごとに delivery policy を持ち、「when server-side errors occur(サブスク先エンドポイントを動かすシステムが利用不能になったとき)」に再試行する

プッシュ型の宿命は、受信側の障害を送信側が肩代わりすること。SNSはその肩代わりを「配信ポリシー」という決まった手順で行う。

② 一時的失敗と恒久的失敗を区別する

受信側のレスポンス
扱いが分かれる
5XX・429retryable(一時的失敗)
それ以外permanent(恒久的失敗)
429以外の4XXなど・エンドポイント削除・権限変更
再試行する配信ポリシーの対象
即破棄DLQがあればDLQへ
  • 公式は「Amazon SNS considers all 5XX errors and 429 (too many requests sent) errors as retryable. ... All other errors are considered as permanent failures and retries will not be attempted」
  • クライアント側エラー(stale subscription metadata=エンドポイント削除やポリシー変更)は「Amazon SNS doesn't retry」

再試行は「一時的失敗」にだけ意味がある。恒久的失敗を再試行しても輻輳を増やすだけなので、SNSは5XX/429以外を即座に恒久失敗と判定して手を引く。

③ 配信ポリシーの4フェーズ — 即時→pre-backoff→指数バックオフ→post-backoff

初回配信が失敗
①即時再試行遅延なし・すぐ叩き直す
一瞬のゆらぎならここで復活
②pre-backoff最小遅延の一定間隔
バックオフ関数をかける前の助走
③backoff指数バックオフ(min→max)
相手が重いほど間隔を空け、負荷を下げる
それでも失敗し続けたら
④post-backoff最大遅延で一定間隔
最後まで粘る最終フェーズ
使い果たし→破棄DLQがあればDLQへ
  • 公式の4フェーズ名は Immediate retry (no delay) / Pre-backoff / Backoff / Post-backoff
  • Backoff phaseは最小遅延・最大遅延・retry-backoff関数で構成。関数は arithmetic / exponential / geometric / linear から選べる(AWS管理エンドポイントはexponential)
  • 「Amazon SNS applies jittering to delivery retries」— ジッター(ゆらぎ)で大量サブスクリプションが同時に復旧先を叩くサンダリングハードを回避

4フェーズは「最初は素早く、途中で指数的に間隔を広げ、最後は粘る」という再送戦略。ジッターと指数バックオフで、復旧しかけた受信側を再び潰さないよう設計されている。

④ 同じ4フェーズ、宛先で数字が桁違い — SQS/Lambdaは23日、HTTP/Sは3,600秒

AWS管理SQS / Lambda
HTTP/S顧客管理 ※カスタム可・以下は例
①即時 3回遅延なし
例: 3回遅延なし
②2回1秒間隔
例: 2回1秒間隔
③10回指数: 1秒→20秒
例: 10回指数: 1秒→60秒
④100,000回20秒間隔
例: 35回60秒間隔
計100,015回約23日
計50回ハードリミット3,600秒
  • AWS管理エンドポイントは公式に「Total attempts: 100,015 times, over 23 days」
  • HTTP/Sは numRetries 最大100・maxDelayTarget 最大3,600秒。「The total policy retry time for an HTTP/S endpoint cannot be greater than 3,600 seconds. This is a hard limit and cannot be increased」
  • 顧客管理エンドポイント(SMTP/SMS/mobile push)は50回・6時間固定。HTTP/S列の数値はサンプルポリシー(例)

SNSは自分が挙動を握れる宛先(SQS/Lambda)には23日・10万回超と手厚く、握れない外部HTTP/Sには3,600秒の上限で見切りをつける。「どこまで面倒を見られるか」が相手の性質で決まる。

⑤ SNSは貯蔵しないルーター — だからDLQで取りこぼしを受け止める

ポリシー使い果たしまたは恒久的失敗と判定
deadLetterTargetArn が指すSQSキューへ
DLQなし破棄・二度と戻らない
DLQありredrive policyで付与
後で再処理
SQS=DLQメッセージを貯蔵(推奨保持14日)
subscription単位で付く→どのエンドポイント宛だったか特定しやすい
再処理Lambdaをイベントソースに / SQS APIで自前消費
  • 「When the delivery policy is exhausted, Amazon SNS stops retrying the delivery and discards the message—unless a dead-letter queue is attached」
  • DLQは普通のSQSキュー。topicでなくsubscriptionに付く(配信はsubscription単位で起こるため)
  • DLQとサブスクリプションは同一アカウント・同一リージョンであること

SNSがルーターで貯蔵しないからこそ、取りこぼしはSQS(=DLQ)に受け止めさせる。前レッスンで見た「SNS+SQS構成」の根拠がここで完結する — SQSの貯蔵能力が、SNSの非貯蔵性を補う。

⑥ 同じ問題への別解 — Lambda非同期呼び出しの内部キューと並べて見る

同じ問題受信側が一時的に落ちている
再試行し尽くしたら
Lambda非同期AWS内部キューに貯蔵→再試行(既定2回)
貯蔵してから捌く
SNSプッシュ配信貯蔵せず配信ポリシーで送信側が再送
貯蔵せず送信側が粘る
送信先DLQへLambdaの受け皿
サブスクDLQへSNSの受け皿(サブスクリプション単位)
  • SNSは「discards the message—unless a dead-letter queue is attached」で、DLQは共通の受け皿
  • 両者とも at-least-once(既習)の世界。再試行がある以上重複配信は起こりうるため、受信側は冪等性(既習)で受ける
  • Lambda内部キューの挙動(非同期呼び出しは既定2回再試行)はLambda編の既習事項として参照

「再試行し尽くしたらDLQへ」という骨格はAWS横断で共通の設計。違いは「途中で貯蔵するか(Lambda)」「送信側が粘るか(SNS)」。SNSはキューでなくルーターだから、貯蔵をSQS(DLQ)に外出しする。

公式ドキュメントで詳しく ↗