backend
A
信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
SQS Standard vs FIFO — 順序・重複・スループット・設計パターン
SQSのStandardキューとFIFOキューの違い、at-least-once配信と exactly-once処理、メッセージグループID、重複排除ID、スループット制限、デッドレターキューの設計を解説。
一言結論
SQS Standardは高スループットで重複前提の冪等処理に向き、FIFOはメッセージグループIDによる順序保証と5分以内の重複排除が必要な注文・金融処理に向くが、FIFOのスループット上限(300/秒)がボトルネックになる場合は設計の見直しが必要だ。
StandardとFIFOの根本的な違い
| 特徴 | Standard | FIFO |
|---|---|---|
| 順序保証 | ベストエフォート | 厳密なFIFO(グループ内) |
| 重複配信 | あり得る(at-least-once) | 5分以内の重複を防止 |
| スループット | 無制限 | 300メッセージ/秒(バッチで3,000/秒) |
| コスト | 安価 | Standardより約2倍高い |
| ユースケース | 大量の非順序処理 | 注文処理、金融取引 |
Standardキューの特性
at-least-once(少なくとも1回)配信:
→ 同じメッセージが複数回配信される可能性がある
→ 受信側で冪等な処理が必要
Best-effort ordering(ベストエフォート順序):
→ 一般的にはFIFOに近い動作だが保証されない
→ 高スループット時は順序が逆転することがある
高スループット:
→ ほぼ無制限のメッセージ/秒
→ 大量のバッチ処理、ログ収集等に最適
FIFOキューの特性
Exactly-once processing(正確に1回の処理):
送信側で MessageDeduplicationId を設定することで
5分以内の同一IDの送信は重複を排除
Strict ordering(厳密な順序):
MessageGroupId 内でFIFOが保証
異なるMessageGroupId間の順序は保証されない
# FIFOキューへのメッセージ送信
import boto3
import uuid
sqs = boto3.client('sqs')
# 注文処理(ユーザーIDをグループIDとして順序保証)
response = sqs.send_message(
QueueUrl='https://sqs.ap-northeast-1.amazonaws.com/123456789012/orders.fifo',
MessageBody='{"orderId": "order-001", "userId": "user-123", "amount": 5000}',
MessageGroupId='user-123', # このユーザーの注文は順番に処理
MessageDeduplicationId=str(uuid.uuid4()) # 重複防止ID
)
メッセージグループIDの活用
ユースケース: 複数ユーザーの注文を独立して順序処理
ユーザーA の注文 → GroupId: userA → 順番処理: A1→A2→A3
ユーザーB の注文 → GroupId: userB → 順番処理: B1→B2→B3
ユーザーA とユーザーB は並列処理される
(異なるグループIDは独立して処理)
可視性タイムアウトの設計
# メッセージ受信(可視性タイムアウト: 処理時間より長く設定)
response = sqs.receive_message(
QueueUrl=queue_url,
MaxNumberOfMessages=10,
VisibilityTimeout=300, # 5分(処理予想時間より長く設定)
WaitTimeSeconds=20 # ロングポーリング(空振りを減らす)
)
for message in response.get('Messages', []):
try:
process_message(json.loads(message['Body']))
# 処理成功後はキューから削除
sqs.delete_message(
QueueUrl=queue_url,
ReceiptHandle=message['ReceiptHandle']
)
except Exception as e:
# エラー時は削除しない → タイムアウト後に再表示
# 指定回数以上失敗したらDLQに移動(maxReceiveCountで制御)
log.error(f"処理失敗: {e}")
デッドレターキュー(DLQ)の設定
# DLQの作成
aws sqs create-queue --queue-name orders-dlq
# メインキューにDLQを設定(5回失敗でDLQへ)
aws sqs set-queue-attributes \
--queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/orders \
--attributes '{
"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:ap-northeast-1:123456789012:orders-dlq\",\"maxReceiveCount\":\"5\"}"
}'
バッチ処理の最適化
# 最大10メッセージを一括送信(コスト削減)
response = sqs.send_message_batch(
QueueUrl=queue_url,
Entries=[
{
'Id': f'msg-{i}',
'MessageBody': json.dumps({'event': i}),
'MessageGroupId': 'batch-group', # FIFOの場合
'MessageDeduplicationId': str(uuid.uuid4())
}
for i in range(10)
]
)
# 最大10メッセージを一括削除
sqs.delete_message_batch(
QueueUrl=queue_url,
Entries=[
{'Id': str(i), 'ReceiptHandle': message['ReceiptHandle']}
for i, message in enumerate(messages)
]
)
ロングポーリング vs ショートポーリング
ショートポーリング(デフォルト):
→ メッセージがなくてもすぐに空のレスポンスを返す
→ API呼び出し料金が増加(空振りが多い)
ロングポーリング(推奨):
→ メッセージが来るまで最大20秒待機
→ API呼び出し数とコストを削減
→ 設定: WaitTimeSeconds=20(キューまたはリクエストで指定)
試験頻出ポイント
| シナリオ | 回答 |
|---|---|
| 注文処理で同一ユーザーの順序保証 | FIFO + MessageGroupId |
| ログ収集などの大量処理 | Standard(高スループット) |
| メッセージの重複処理を防ぐ | FIFO(重複排除)+ 冪等な処理ロジック |
| 処理失敗したメッセージを別管理 | DLQ(deadLetterTargetArn) |
| SQS呼び出しコストを削減 | ロングポーリング(WaitTimeSeconds=20) |
| FIFOのスループット制限 | 300msg/秒(バッチ時3,000/秒) |
まとめ
Standardは高スループットで冪等な処理に向き、FIFOは順序と重複排除が必要な金融・注文系処理に向く。FIFOのスループット制限(300/秒)を超える場合はメッセージグループIDを多様化するか、Standardへの移行を検討する必要がある。