SJ blog
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の根本的な違い

特徴StandardFIFO
順序保証ベストエフォート厳密な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への移行を検討する必要がある。