SJ blog
backend
A

信頼度ランク

S 公式ソース確認済み
A 成功実績多数・失敗例少数
B 賛否両論
C 動作未確認・セキュリティリスク高
Z 個人所感

SQSポーリング — ロングポーリング vs ショートポーリングとコスト最適化

SQSのショートポーリングとロングポーリングの違い、WaitTimeSecondsの設定、ReceiveMessageWaitTimeSecondsによるキュー設定、Lambdaとの統合時のポーリング動作、コスト削減効果を解説。

一言結論

SQSはロングポーリング(WaitTimeSeconds=20)を設定するだけで空ポーリングを95%削減できるため常に有効化すべきで、LambdaトリガーとしてSQSを使う場合はAWS側が自動でロングポーリングを実施するためアプリ側での実装は不要だ。

ショートポーリング vs ロングポーリング

ショートポーリング(デフォルト):
  → SQSは即座にレスポンスを返す
  → メッセージがなければ空レスポンス
  → 毎回APIリクエストが発生 → コスト高
  → WaitTimeSeconds = 0

ロングポーリング(推奨):
  → SQSはメッセージが来るまで最大20秒待つ
  → メッセージがなければ20秒後に空レスポンス
  → APIリクエスト数を大幅削減 → コスト低
  → WaitTimeSeconds = 1〜20

ロングポーリングの設定方法

# キューのデフォルトをロングポーリングに設定
aws sqs set-queue-attributes \
  --queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/my-queue \
  --attributes '{"ReceiveMessageWaitTimeSeconds": "20"}'

# または個別のReceiveMessageリクエストで指定
aws sqs receive-message \
  --queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/my-queue \
  --max-number-of-messages 10 \
  --wait-time-seconds 20

コスト削減効果

例: メッセージ頻度 10メッセージ/分のキュー、1秒ごとのポーリング

ショートポーリング(1秒間隔):
  1分間のAPIリクエスト: 60回
  1ヶ月: 60 × 60 × 24 × 30 = 2,592,000 リクエスト
  料金: 約$1.04/月(最初の100万件は無料)
  
ロングポーリング(20秒待機):
  1分間のAPIリクエスト: 3回(20秒に1回 = 3回)
  1ヶ月: 3 × 60 × 24 × 30 = 129,600 リクエスト
  料金: 無料(100万件以内)
  
→ ロングポーリングで95%のAPIリクエスト削減
→ 誤検知(空レスポンス)も95%削減

Python でのロングポーリング実装

import boto3
import time

sqs = boto3.client('sqs')
QUEUE_URL = 'https://sqs.ap-northeast-1.amazonaws.com/123456789012/my-queue'

def poll_messages():
    """ロングポーリングでメッセージを継続処理"""
    while True:
        response = sqs.receive_message(
            QueueUrl=QUEUE_URL,
            MaxNumberOfMessages=10,     # 最大10件
            WaitTimeSeconds=20,          # 最大20秒待機
            VisibilityTimeout=120        # 処理中の再可視化防止
        )
        
        messages = response.get('Messages', [])
        
        if not messages:
            # 20秒間メッセージなし → 再度ポーリング
            continue
        
        for message in messages:
            try:
                process_message(message)
                # 処理成功後に削除
                sqs.delete_message(
                    QueueUrl=QUEUE_URL,
                    ReceiptHandle=message['ReceiptHandle']
                )
            except Exception as e:
                print(f"Error processing message: {e}")
                # 削除しなければVisibilityTimeout後に再処理

def process_message(message):
    import json
    body = json.loads(message['Body'])
    print(f"Processing: {body}")
    # 実際の処理ロジック

Lambda + SQS のポーリング動作

Lambdaがトリガーとして設定された場合:
  → Lambda サービス(AWS側)が自動的にロングポーリングを実施
  → ユーザーコードでポーリングを実装する必要なし
  → バッチサイズに応じてメッセージを取得してLambdaに渡す

Lambda + SQS の設定:
  BatchSize: 1〜10,000(FIFOは最大10)
  MaximumBatchingWindowInSeconds: メッセージを集めてバッチ化する待機時間(0〜300秒)
# SQS を Lambda のトリガーとして設定
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:sqs:ap-northeast-1:123456789012:my-queue \
  --function-name my-function \
  --batch-size 10 \
  --maximum-batching-window-in-seconds 5  # 5秒間バッチを集める

FIFO キューでの注意点

FIFO キューの特性:
  → MessageGroupId ごとに順序が保証
  → ロングポーリングは FIFO キューでも使用可能
  
FIFO キューの制限:
  → スループット: デフォルト300 TPS(スループット高速化を有効にすると3,000 TPS)
  → バッチサイズ: 最大10メッセージ
  → DeduplicationId: 重複排除ID(5分間有効)

バッチウィンドウの効果

MaximumBatchingWindowInSeconds(バッチウィンドウ):
  
  0秒(デフォルト):
  → メッセージが1件でも来たらすぐにLambdaを起動
  → 低レイテンシー、コスト高め
  
  5秒:
  → 5秒間またはBatchSize個メッセージが溜まるまで待機
  → 一度に多くのメッセージをバッチ処理
  → Lambda起動回数削減 → コスト削減
  
  使い所:
    リアルタイム処理が必要: 0秒
    バッチ処理可能・コスト削減: 5〜300秒

試験頻出ポイント

シナリオ回答
SQSの空ポーリングを削減ロングポーリング(WaitTimeSeconds: 1〜20)
Lambdaのポーリング実装Lambda側が自動でロングポーリング
SQSのコスト最適化ロングポーリング + バッチウィンドウ
FIFO キューの最大TPS(デフォルト)300 TPS(高速化で3,000 TPS)
バッチウィンドウ最大値300秒(5分)

まとめ

SQSロングポーリングはWaitTimeSecondsを設定するだけで空ポーリングによるAPIリクエスト数を大幅に削減できる。LambdaとSQSの組み合わせではAWS側が自動的にロングポーリングを実施するため実装不要。バッチウィンドウでさらにLambda起動回数を削減できる。