SNSのリトライロジックが公開され、DLQがサポートされていたので試してみた

Amazon SNSでデッドレターキュー(DLQ)がサポートされるようになっていました。
2019.12.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

西澤です。11月のre:Invent前のアップデートラッシュの復習をしていたところ、嬉しいアップデートを見つけたので試してみました。AWSで構成するアーキテクチャーの中でも非常に重要な役割を担っているメッセージングサービスであるAmazon SNSでデッドレターキュー(DLQ)がサポートされるようになっていました。

そもそもSNSとは?

Amazon SNSは、フルマネージドのPub/Subメッセージ配信サービスです。ユーザは何も考えずに配信したメッセージをPublishすれば、登録したエンドポイントに対してメッセージが配信される仕組みです。これまでも非常に信頼性の高いサービスだったのですが、今回のDLQサポートにより、エンドポイントへの配信が失敗した際のメッセージを保存しておくことで、エラーの検知とそのリカバリを容易にすることができるようになりました。

SNSのリトライロジックはどうなっているのか?

この記事を執筆している時点では英語版のドキュメントしか存在しないようだったのですが、こちらを抜粋してまとめておきたいと思います。下記をご確認いただきたいのですが、"23日間で100,015回リトライ"って、SNSがいかに堅牢に設計されたメッセージングシステムなのかを確認することができると思います。私が把握している範囲では、これまで明確に公開されていなかった情報だったのではないでしょうか?

  • AWS-managed endpoints
    • プロトコル: SQS、Lambda
    • 即時リトライ: 3回
    • Preバックオフ: 1秒おきに2回
    • バックオフ: 最大20秒までエクスポネンシャルバックオフで10回
    • Postバックオフ: 20秒おきに100,000回
    • 合計リトライ: 23日間で100,015回
  • Customer-managed endpoints
    • プロトコル: SMTP、SMS、MobilePush
    • 即時リトライ: 0回
    • Preバックオフ: 10秒おきに2回
    • バックオフ: 最大10分までエクスポネンシャルバックオフで10回
    • Postバックオフ: 10分おきに38回 * 合計リトライ: 6時間で50回

AWSで推奨されるリトライ方式である"エクスポネンシャルバックオフ"については、下記公式ドキュメントが詳しいので、合わせてご確認ください。

また、今回同時にHTTP/Sプロコトルへの配信については、独自の配信ポリシーも設定できるようになっているようです。詳細は下記公式ドキュメントをご覧ください。

SNS配信の失敗原因とリトライ

SNSからの配信が失敗する理由には、以下のようなものがあり、それぞれSNSのリトライ有無が変わることに注意しておきましょう。

  • 4xx(クライアントサイドエラー)
    • エンドポイントを削除した
    • エンドポイントのアクセスポリシーを不適切に変更した
    • ->->-> リトライは一切行われない
  • 5xx(サーバサイドエラー)
    • エンドポイント側の一時的な問題や障害
    • ->->-> エクスポネンシャルバックオフでリトライ

SNSのDLQを設定してみた

ということで、早速試してみました。実際にはサブスクライブするエンドポイントは何でも良いのですが、かんたんに4xxエラーを発生することができる(登録したエンドポイントを削除)という理由で、SQSキューを利用してやってみます。

事前準備

既存の仕組みに追加で実装するような想定で、下記のような配信セットが既に用意されているものとします。

  • SNSトピック作成
  • 正常時の配信用SQSキュー(今回はTestQueue)作成
  • 正常時の配信用SQSキューをSNSトピックにサブスクライブ

ここで、まずはデッドレターキュー(DLQ)として利用するSQSキューを作成します。このキューはFIFOキューではなく、スタンダードキューである必要があります。そして、このDLQに設定するアクセス許可設定を追加します。"アクセス許可の追加"ボタンからは設定できないので、"ポリシードキュメントの編集(高度)"を利用する必要がある点に注意しましょう。今回は以下のようなアクセス許可設定を行いました。

{
  "Version": "2012-10-17",
  "Id": "MyDeadLetterQueuePolicy",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "sns.amazonaws.com"
      },
      "Action": "SQS:SendMessage",
      "Resource": "arn:aws:sqs:us-west-2:123456789012:DeadLetterQueue",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:sns:us-west-2:123456789012:cm-nishizawa-topic-us-west-2"
        }
      }
    }
  ]
}
  • ResourceにDLQとして利用するSQSキューのARNを指定
  • aws:SourceArnに利用するSNSトピックのARNを指定

続けて、SNSのサブスクリプション設定から、"Redriveポリシー(デッドレターキュー)"を追加します。SNSトピックに対する設定ではなく、サブスクリプション単位での設定となる点に注意です。

設定はこれだけです、簡単ですね。それではテストしてみます。まずは正常に配信できることを確認した上で、登録したエンドポイントであるSQSキュー(TestQueue)を削除してしまいます。その上で、再びSNSトピックにテストメッセージをPublishしてみると、、、

DLQ側にメッセージが配信されていることを確認できました!

合わせて読みたい

参考までに、SQS利用時のお作法についてまとめた 都元 の記事をお読みになったことが無い方は、こちらも合わせてお読みいただくと理解が深まると思いますので、おすすめしておきます。

【AWS】SQSキューの前には難しいこと考えずにSNSトピックを挟むと良いよ、という話

また、サーバーレスな非同期処理等の実装の参考例として、SNS/SQS/LambdaとすべてにおいてDLQを活用するユースケースを紹介したAWSブログもぜひご覧ください。

Amazon SNS, Amazon SQS, AWS Lambda のデッドレターキューによる耐久性のあるサーバーレスアプリケーション設計 | Amazon Web Services ブログ

まとめ

マネージドサービスを活用することは、クラウドネイティブなアーキテクチャーを採用する為には非常に重要になるわけですが、今回のようなエラー処理のための仕組みを簡単に用意できるようになったことで、より信頼性の高いシステムを構築することができるようになりました。歴史のあるサービスも機能改善が進みどんどん使いやすくなっていますね。今年のre:Invent本番ではどんなアップデートや新サービスが発表されるのか、非常に楽しみです。

どこかの誰かのお役に立てば嬉しいです。