この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
困っていた内容
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 サービス側で担うため、標準キューよりオーバーヘッドが生じることを意識し、計画的に利用してください。