Amazon Web Services ブログ

Amazon SQS デッドレターキューリドライブ用の新しい API セット

6月8日、 Amazon Simple Queue Service (Amazon SQS) の新しい API セットをリリースいたしました。これらの新しい API により、デッドレターキュー (DLQ) リドライブをプログラムで管理できます。AWS SDK または AWS コマンドラインインターフェイス (AWS CLI) を使用して、メッセージを DLQ から元のキューまたはカスタムキューの宛先へプログラム的に移動し、再処理を試みることができるようになりました。DLQ は、コンシューマーアプリケーションで正しく処理されなかったメッセージを Amazon SQS が自動的に移動するキューです。

この新しい API がどのように役立つかを十分に理解するために、歴史を簡単に振り返ってみましょう。

メッセージキューは、現代のアプリケーションアーキテクチャに欠かせないものです。メッセージプロデューサーとコンシューマー間の非同期かつメッセージベースの通信を可能にすることで、デベロッパーはサービスを切り離すことができます。ほとんどのシステムでは、メッセージはコンシューマーが処理するまで共有ストレージ (キュー) に保持されます。メッセージキューを使用すると、デベロッパーは一時的なサービス障害に対して回復力のあるアプリケーションを構築できます。メッセージ処理の優先順位を設定し、メッセージを処理するワーカーノード群を拡張するのに役立ちます。メッセージキューは、イベント駆動型アーキテクチャでも人気があります。

非同期メッセージ交換は、アプリケーションアーキテクチャでは新しいものではありません。アプリケーション間でメッセージを非同期で交換するという概念は 1960 年代に登場し、1972 年に IBM が TCAM for OS/360 を発表したときに初めて普及しました。20 年後、 1993 年に IBM MQ シリーズ (現在の IBM MQ) が採用され、1998 年にサンマイクロシステムズが Java アプリケーションがメッセージキューとやり取りするための標準 API である Java メッセージングサービス (JMS) をリリースしたときに広く採用されました。

AWS は 2006 年 7 月 12 日Amazon SQS を立ち上げました。Amazon SQS はスケーラブルで信頼性が高く、伸縮自在なキューイングサービスで、「ちゃんと動く」ものです。 Werner 氏は当時、次のように書いています。「私たちは、メッセージを処理するプロセスがそのメッセージに対して自動的にリースロックを取得し、リースの期限が切れる前にメッセージを削除しなければ、再び処理可能になるという並行処理モデルを選択しました。これで、障害処理が非常に簡単になります。

2014 年 1 月 29 日に、デッドレターキュー (DLQ) を導入しました。DLQ を使用すると、処理に失敗したメッセージがキューの一番上に永遠に残り、キュー内の他のメッセージが処理されなくなるのを防ぐことができます。DLQ では、各キューには、メッセージを何回表示して処理できるか (maxReceiveCount) を Amazon SQS に伝えるプロパティが関連付けられています。各メッセージには受信カウンター (ReceiveCount) も関連付けられています。コンシューマーアプリケーションがメッセージをピックアップして処理するたびに、メッセージ受信カウントは 1 ずつ増加します。ReceiveCount > maxReceiveCount の場合、Amazon SQS はメッセージを指定された DLQ に移動して、人間による分析とデバッグを行います。通常、このようなイベントが発生したときに通知を送信するには、アラームを DLQ に関連付けます。メッセージを DLQ に移動する一般的な理由としては、形式が正しくない、コンシューマーアプリケーションにバグがある、メッセージの処理に時間がかかりすぎることが挙げられます。

AWS re: Invent 2021 で、AWS は Amazon SQS コンソールでデッドレターキューのリドライブを行うことを発表しました。リドライブは、障害が発生したメッセージライフサイクルの第 2 段階に対処します。これにより、メッセージを元のキューに再挿入して、処理を再試行できます。コンシューマーアプリケーションが修正され、失敗したメッセージを処理する準備が整ったら、DLQ からのメッセージをソースキューまたはカスタマイズされたキューの宛先に戻すことができます。コンソールを数回クリックするだけです。

現在、リドライブをプログラムで処理するアプリケーションやスクリプトを作成できる API を追加しています。人間がコンソールをクリックする必要はもうありません。API を使用すると、プロセスのスケーラビリティが向上し、ヒューマンエラーのリスクが軽減されます。

実際の動作
この新しい API を試すために、コマンドラインのみのデモ用のターミナルを開きます。始める前に、 AWS CLI が最新バージョンであることを確認します。macOS で、brew upgrade awscli を入力します。

最初に 2 つのキューを作成します。1 つはデッドレターキューで、もう 1 つはアプリケーションキューです。

# まず、デッドレターキューを作成します (キュー名の末尾に -dlq を追加することに注意してください)
➜ ~ aws sqs create-queue \
            --queue-name awsnewsblog-dlq                                            
{
    "QueueUrl": "https://sqs.us-east-2.amazonaws.com/012345678900/awsnewsblog-dlq"
}

# 次に、作成したばかりのキューの Arn を取得します
➜  ~ aws sqs get-queue-attributes \
             --queue-url https://sqs.us-east-2.amazonaws.com/012345678900/awsnewsblog-dlq \
             --attribute-names QueueArn
{
    "Attributes": {
        "QueueArn": "arn:aws:sqs:us-east-2:012345678900:awsnewsblog-dlq"
    }
}

# 3 番目に、アプリケーションキューを作成します。リドライブポリシーを入力: 配信を 3 回試みた後に DLQ にメッセージを投稿する
➜  ~ aws sqs create-queue \
             --queue-name awsnewsblog \
             --attributes '{"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:us-east-2:012345678900:awsnewsblog-dlq\",\"maxReceiveCount\":\"3\"}"}' 
{
    "QueueUrl": "https://sqs.us-east-2.amazonaws.com/012345678900/awsnewsblog"
}

2 つのキューの準備ができたので、アプリケーションキューにメッセージを投稿します。

➜ ~ aws sqs send-message \
            --queue-url https://sqs.us-east-2.amazonaws.com/012345678900/awsnewsblog \
            --message-body "Hello World"
{
"MD5OfMessageBody": "b10a8db164e0754105b7a99be72e3fe5",
"MessageId": "fdc26778-ce9a-4782-9e33-ae73877cfcb2"
}

次に、メッセージは消費しますが、キューからは削除しません。これは、メッセージコンシューマーアプリケーションのクラッシュをシミュレートします。メッセージコンシューマーは、処理が成功したらメッセージを削除することになっています。redrivePolicy を入力したときに maxReceivedCount プロパティを 3 に設定しました。そのため、この操作を 3 回繰り返して、3 回配信を試みた後に Amazon SQS にメッセージをデッドレターキューに移動させます。デフォルトの可視性タイムアウトは 30 秒なので、再試行の間には 30 秒以上待たなければなりません。

➜ ~ aws sqs receive-message \
            --queue-url https://sqs.us-east-2.amazonaws.com/012345678900/awsnewsblog
{
"Messages": [
{
"MessageId": "fdc26778-ce9a-4782-9e33-ae73877cfcb2",
"ReceiptHandle": "AQEBP8yOfgBlnjlkGXjyeLROiY7xg7cZ6Znq8Aoa0d3Ar4uvTLPrHZptNotNfKRK25xm+IU8ebD3kDwZ9lja6JYs/t1kBlwiNO6TBACN5srAb/WggQiAAkYl045Tx3CvsOypbJA3y8U+MyEOQRwIz6G85i7MnR8RgKTlhOzOZOVACXC4W8J9GADaQquFaS1wVeM9VDsOxds1hDZLL0j33PIAkIrG016LOQ4sAntH0DOlEKIWZjvZIQGdlRJS65PJu+I/Ka1UPHGiFt9f8m3SR+Y34/ttRWpQANlXQi5ByA47N8UfcpFXXB5L30cUmoDtKucPewsJNG2zRCteR0bQczMMAmOPujsKq70UGOT8X2gEv2LfhlY7+5n8z3yew8sdBjWhVSegrgj6Yzwoc4kXiMddMg==",
"MD5OfBody": "b10a8db164e0754105b7a99be72e3fe5",
"Body": "Hello World"
}
]
}

# 30 秒待って、
# 次に 2 回繰り返します (メッセージ受信 API 呼び出しは合計 3 回) 

3 回処理を試みると、メッセージはキューから消えます。

➜  ~ aws sqs receive-message \
             --queue-url  https://sqs.us-east-2.amazonaws.com/012345678900/awsnewsblog
{
    "Messages": []
}

メッセージはデッドレターキューに移動されました。DLQ を確認して確認します (キュー URL が -dlqで終わっていることに注意してください)。

➜  ~ aws sqs receive-message \
             --queue-url  https://sqs.us-east-2.amazonaws.com/012345678900/awsnewsblog-dlq
{
    "Messages": [
        {
            "MessageId": "fdc26778-ce9a-4782-9e33-ae73877cfcb2",
            "ReceiptHandle": "AQEBCLtBMoZYVMMq7fUGNHeCliqE3mFXnkuJ+nOXLK1++uoXWBG31nDejCpxElmiBZWfbcfGJrEdKj4P9HJdrQMYDbeSqB+u1ZlB7CYzQBiQps4SEG0biEoubwqjQbmDZlPrmkFsnYgLD98D1XYWk/Ik6Z2n/wxDo9ko9rbZ15izK5RFnbwveNy8dfc6ireqVB1EGbeGkHcweHGuoeKWXEab1ynZWhNqZsQgCR6pWRkgtn59lJcLv4cJ4UMewNzvt7tMHH69GvVjXdYDYvJJI2vj+6RHvcvSHWWhTNT+CuPEXguVNuNrSya8gho1fCnKpVwQre6HhMlLPjY4wvn/tXY7+5rmte9eXagCqLQXaENB2R7qWNVPiWRIJy8/cTf37NLYVzBom030DNJlH9EeceRhCQ==",
            "MD5OfBody": "b10a8db164e0754105b7a99be72e3fe5",
            "Body": "Hello World"
        }
    ]
}

セットアップの準備ができたので、メッセージを元のキューにプログラムでリドライブしてみましょう。コンシューマーがメッセージを正しく処理しなかった理由がわかり、コンシューマーアプリケーションのコードを修正したと仮定します。DLQ で start-message-move-task を使用して非同期リドライブを開始します。オプションのアトリビュート (MaxNumberOfMessagesPerSecond) を使用すると、リドライブの速度を制御できます。

➜ ~ aws sqs start-message-move-task \
            --source-arn arn:aws:sqs:us-east-2:012345678900:awsnewsblog-dlq
{
    "TaskHandle": "eyJ0YXNrSWQiOiI4ZGJmNjBiMy00MmUwLTQzYTYtYjg4Zi1iMTZjYWRjY2FkNmEiLCJzb3VyY2VBcm4iOiJhcm46YXdzOnNxczp1cy1lYXN0LTI6NDg2NjUyMDY2NjkzOmF3c25ld3NibG9nLWRscSJ9"
}

list-message-move-tasks で開始した移動タスクを一覧表示してステータスを確認したり、cancel-message-move-task API を呼び出して実行中のタスクをキャンセルしたりできます。

➜ ~ aws sqs list-message-move-tasks \
            --source-arn arn:aws:sqs:us-east-2:012345678900:awsnewsblog-dlq
{
    "Results": [
        {
            "Status": "COMPLETED",
            "SourceArn": "arn:aws:sqs:us-east-2:012345678900:awsnewsblog-dlq",
            "ApproximateNumberOfMessagesMoved": 1,
            "ApproximateNumberOfMessagesToMove": 1,
            "StartedTimestamp": 1684135792239
        }
    ]
}

これで、私のアプリケーションはアプリケーションキューからメッセージを再び処理できます。

➜  ~ aws sqs receive-message \
             --queue-url  https://sqs.us-east-2.amazonaws.com/012345678900/awsnewsblog                                   
{
    "Messages": [
        {
            "MessageId": "a7ae83ca-cde4-48bf-b822-3d4bc1f4dcae",
            "ReceiptHandle": "AQEB9a+Dm2nvb3VUn9+46j9UsDidU/W6qFwJtXtNWTyfoSDOKT7h73e6ctT9RVZysEw3qqzJOx1cxblTTOSrYwwwoBA2qoJMGsqsrsRGGYojBvf9X8hqi8B8MHn9rTm8diJ2wT2b7WC+TDrx3zIvUeiSEkP+EhqyYOvOs7Q9aETR+Uz02kQxZ/cUJWsN4MMSXBejwW+c5ivv5uQtpfUrfZuCWa9B9O67Kj/q52clriPHpcqCCfJwFBSZkGTXYwTpnjxD4QM7DPS+xVeVfTyM7DsKCAOtpvFBmX5m4UNKT6TROgCnGxTRglUSMWQp8ufVxXiaUyM1dwqxYekM9uX/RCb01gEyCZHas4jeNRV5nUJlhBkkqPlw3i6w9Uuc2y9nH0Df8nH3g7KTXo4lv5Bl3ayh9w==",
            "MD5OfBody": "b10a8db164e0754105b7a99be72e3fe5",
            "Body": "Hello World"
        }
    ]
}

可用性
DLQ リドライブ API は、現在 Amazon SQS が利用可能なすべての商用リージョンでご利用いただけます

デッドレターキューからソースキューまたはカスタム宛先キューにメッセージをリドライブすると、既存の料金に基づいて請求される追加の API 呼び出しが生成されます (毎月無料、最初の 100 万回の API 呼び出しを差し引き、100 万回の API 呼び出しあたり 0.40 USD から開始)。Amazon SQS は、メッセージをあるキューから別のキューにリドライブしながらメッセージをバッチ処理します。これにより、メッセージをあるキューから別のキューに移動するのが簡単で低コストのオプションになります。

DLQ と DLQ リドライブの詳細については、ドキュメントをご覧ください

私たちは非同期の世界に住んでいることを忘れないでください。アプリケーションもそうすべきです。今日から始めて、最初のリドライブアプリケーションを作成してください

— seb

原文はこちらです。