SQS FIFO キューへ同じ内容のメッセージを連続して送る方法を教えてください
困っていた内容
SQS FIFO キューを使っている環境で、同じ内容のメッセージを連続して送信できません。
しばらく待つと送信できるようになるのですが、意図して同様のメッセージを送信したい場合はどう対応したらいいでしょうか?
現在のメッセージ送信方法は以下です。
同様のメッセージが送信できない例
readonly QUEUE_URL=<キューの URL> for i in {0..2}; do aws sqs send-message \ --queue-url ${QUEUE_URL} \ --message-body '{"message": "fifo-queue-duplicate-test"}' \ --message-group-id Group1 done
出力結果
{ "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "30555aba-16a2-453a-8e8e-2197dbc01d99", "SequenceNumber": "18865450273486831616" } { "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "30555aba-16a2-453a-8e8e-2197dbc01d99", "SequenceNumber": "18865450273486831616" } { "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "30555aba-16a2-453a-8e8e-2197dbc01d99", "SequenceNumber": "18865450273486831616" }
何度メッセージを送信しても MessageId がしばらく同じ値になります。
どう対応すればいいの?
以下のいずれかの対応をすれば、同様のメッセージが連続で送信できます。
- メッセージ送信時の重複排除 ID(MessageDeduplicationId)を分ける
- メッセージの本文をコンシューマーに影響のない範囲で一部変える
- 新たなキーと値を追加した場合はメッセージのサイズが大きくなる
- 重複排除スコープをデフォルトの「キュー」から「メッセージグループ」にし、メッセージグループ ID(MessageGroupId)を分ける
- メッセージはメッセージグループ毎に 1 つずつ処理されるので順序性に注意
重複排除 ID を分ける例
for i in {0..2}; do aws sqs send-message \ --queue-url ${QUEUE_URL} \ --message-body '{"message": "fifo-queue-duplicate-test"}' \ --message-group-id Group1 \ --message-deduplication-id "Deduplication${i}" done
出力結果
{ "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "5930ed9c-87fe-411d-9a22-2a409048d705", "SequenceNumber": "18865450250396913408" } { "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "c2313537-e276-4631-9e57-fa2cade69a3d", "SequenceNumber": "18865450250637040640" } { "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "bd464df3-0755-4cdf-ac0f-e64a7e3ab862", "SequenceNumber": "18865450250856945152" }
メッセージの本文を変える例
for i in {0..2}; do aws sqs send-message \ --queue-url ${QUEUE_URL} \ --message-body "{\"uuid\": $(uuidgen), \"message\": \"fifo-queue-duplicate-test\"}" \ --message-group-id Group1 done
出力結果
{ "MD5OfMessageBody": "272e249ab0b5f90e8d88135682d94760", "MessageId": "dda73899-6505-49c1-8254-bc5c42d414af", "SequenceNumber": "18865450558375920128" } { "MD5OfMessageBody": "af64cb408086d9b0cdc50ea87888c249", "MessageId": "d90abfcb-bb34-4b67-8c9b-a2fd4d05e22d", "SequenceNumber": "18865450558585584896" } { "MD5OfMessageBody": "bcd526c7a8fca87ab049bcbf130a3d5e", "MessageId": "1a339f14-9d8e-45fb-9be9-b58b57840bf6", "SequenceNumber": "18865450558797807616" }
メッセージグループ ID を分ける例
for i in {0..2}; do aws sqs send-message \ --queue-url ${QUEUE_URL} \ --message-body '{"message": "fifo-queue-duplicate-test"}' \ --message-group-id "Group${i}" done
出力結果
{ "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "dd26dafd-dafe-49c4-b0ae-a257826d4f86", "SequenceNumber": "18865450926135280896" } { "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "d544c8e9-0db1-41af-8236-6a648403ecce", "SequenceNumber": "18865450926342128128" } { "MD5OfMessageBody": "a14eb7d0681d6dd4a8332f5636a0d84c", "MessageId": "da6a6526-a59f-4996-b468-5dee06265651", "SequenceNumber": "18865450926566383616" }
いずれの方法でもメッセージ ID が重複せず、コンシューマーでは別のメッセージとして取得可能です。
どんな仕組みなの?
SQS FIFO キューは設定でコンテンツの重複が排除できます。
重複排除期間は 5 分間です。
SQS コンソールの設定画面
この「コンテンツ」とはメッセージの本文(メッセージの属性ではなく)を SHA-256 でハッシュ化したものを指します。
「コンテンツに基づく重複排除」設定をオフにすると、重複排除 ID(MessageDeduplicationId)の指定が必須になります。
重複排除 ID を指定しない場合、メッセージ送信時に以下のエラーメッセージが出力されます。
An error occurred (InvalidParameterValue) when calling the SendMessage operation: The queue should either have ContentBasedDeduplication enabled or MessageDeduplicationId provided explicitly
FIFO キューを使うとコンシューマー側で重複排除、順序保証などを含むメッセージの同期処理の実装コストが下がります。
また、プロデューサー側も重複を意識せずにメッセージを送信できますが、意図して同じ内容のメッセージを送信したい場合は今回のような対応が必要になります。
FIFO キューは元来、プロデューサー・コンシューマー側で実装していた処理を SQS サービス側で担うため、標準キューよりオーバーヘッドが生じることを意識し、計画的に利用してください。