Dev Study
AWSサービスの内部原理 コース

46. SQSは1台のキューではない — 冗長格納が生む at-least-once とベストエフォート順序

SQSの「キュー」の正体は複数AZにまたがるサーバー群への冗長格納です。この物理的な事実から、なぜ同じメッセージが2回届き、なぜ順序が保証されず、なぜ1回のReceiveで全部が返ってこないのかまでを、上から下へ図で追っていきます。

① SendMessageのACKは「複数AZに書き終えた」の合図

Producer
複数AZへの格納が完了してから
AZ-a サーバーコピーを格納
AZ-b サーバーコピーを格納
AZ-c サーバーコピーを格納
横並び=同じメッセージのコピーを並列に格納(1つの論理キュー)
ACK(成功応答)Producerへ返す
  • 公式の言い回し:「When you send a message using SendMessage, Amazon SQS redundantly stores the message in multiple availability zones (AZs) before acknowledging it.」
  • この冗長性の目的:「no single computer, network, or AZ failure can render the messages inaccessible」(単一のコンピュータ・ネットワーク・AZ障害でメッセージが失われない)。

ACKが返った時点で、メッセージは1台のサーバーではなく複数AZの複数サーバーにコピーされています。SQSの「キュー」とは、この分散した格納の集合体に付いた論理的な名前にすぎません。

② 「複数コピー」がそのまま at-least-once とベストエフォート順序になる

複数AZのコピー同一メッセージが分散して存在
だから
重複配信同じメッセージが2回以上届きうる
= at-least-once。削除の伝播前に別コピーが配信される可能性
順序入れ替わり到着順が乱れうる
= ベストエフォート順序。どのサーバーから取り出すかは分散配置に依存
受信側は冪等に重複は例外ではなく仕様
  • 公式:「Standard queues ensure at-least-once message delivery, but due to the highly distributed architecture, more than one copy of a message might be delivered, and messages may occasionally arrive out of order.」
  • ただしSQSは無秩序ではなく「best-effort attempt to maintain the order in which messages are sent」(送信順を保とうとはする)。あくまで保証ではない。
  • 重複の具体的メカニズム(削除伝播ラグ)は公式が明言していないため「可能性」として提示。公式が断定しているのは「highly distributed architecture の帰結として複数コピーが配信されうる」ことまで。

at-least-once も順序の乱れも、SQS特有の欠陥ではなく「複数の場所に冗長に置いた」ことの直接の帰結です。DynamoDB編・Lambda編で見た「分散させると可用性は上がるが、代わりに一貫性(ここでは重複ゼロ・厳密順序)を諦める」という同じトレードオフが、ここでも効いています。だから受信側は冪等に作る(Lambda編で既習)——重複は例外ではなく仕様です。

③ ショートポーリング — サーバーの「一部」しか見ないから取りこぼす

ReceiveMessageWaitTimeSeconds=0(既定)
即座に応答(メッセージ無しでも即返す)
srv1[A] 照会✓
srv2見ない
srv3[C][D] 照会✓
srv4見ない
srv5[B] 照会✓
次のReceiveで
返る: A,C,D,B
返らない: E別サーバーに居た
E も返る叩き続ければ全部揃う
  • 公式:「Amazon SQS samples a subset of its servers (based on a weighted random distribution) and returns messages from only those servers. Thus, a particular ReceiveMessage request might not return all of your messages.」
  • 「if you keep consuming from your queues, Amazon SQS samples all of its servers, and you receive all of your messages.」(叩き続ければ全サーバーが対象になり、いずれ全部届く)
  • キュー内が1,000件未満なら次のリクエストで返る、とも明記。
  • ショートポーリングになる条件は2通り:ReceiveMessage呼び出しで WaitTimeSeconds=0 を指定するか、指定なしでキュー属性 ReceiveMessageWaitTimeSeconds が0(既定)の場合。

①で冗長格納した結果、メッセージは多数のサーバーに散らばっています。ショートポーリングはそのうち一部をランダムに覗くだけなので、1回のReceiveで全メッセージが返らないのは当然です。「取りこぼし」は分散格納の証拠そのものです。

④ ロングポーリング — 「全サーバー」を照会して空応答を減らす

ReceiveMessageWaitTimeSeconds>0(最大20秒)
結果で分岐
srv1〜srv5全部を見る ✓✓✓✓✓
待っている間に
1件でもあれば即応答
無ければ最大20秒待つ
届いたらその時点で返す
20秒経過空応答を返す
  • 公式:「Long polling ... queries all servers for messages」「Reduce false empty responses by querying all—rather than a subset of—Amazon SQS servers.」
  • 「The maximum long polling wait time is 20 seconds.」
  • 2つの空応答を区別する:empty response(本当に無い)と false empty response(有るのにサブセットに入らず返らなかった)。ロングポーリングは後者を大幅に減らす。
  • ただし公式は「稀に、特にWaitTimeSecondsを小さくした場合、メッセージが残っていても空応答が返ることがある」とも注記しており、ゼロになる保証ではない。

ショートポーリングが「サブセットしか見ない」ことの裏返しで、ロングポーリングは「全サーバーを見る+少し待つ」ことで空応答(特に false empty response)を減らします。③と④を並べると、ポーリング設計そのものが「メッセージは複数サーバーに分散している」という前提の上に立っていることが読み取れます。これはLambda編のイベントソースマッピングでポーラーがSQSを叩くとき、内部で起きていることそのものです(既習のポーリングvsプッシュの、ポーリング側の内部)。

⑤ キューは一時保管庫 — 保持期間とサイズ上限という「境界」

冗長格納される
期間内か・過ぎたか
最小 60秒1分
既定 4日
最大 14日1,209,600秒
同時に、1メッセージのサイズにも境界
受信・削除正常に処理
期間超過SQSが自動で破棄(消える)
超える場合
最小 1 byte1文字
最大 1 MiB1,048,576 bytes
本体はS3へSQSには参照だけ送る
Extended Client Library / 最大ペイロード2GB
  • 保持:「By default, a message is retained for 4 days. The minimum is 60 seconds (1 minute). The maximum is 1,209,600 seconds (14 days).」
  • サイズ:「The minimum message size is 1 byte (1 character). The maximum is 1,048,576 bytes (1 MiB).」— 2025年8月に旧256KiBから1MiBに引き上げ済み(AWS What's New「Amazon SQS increases maximum message payload size to 1 MiB」)。古い教材の「256KB」は現在は誤り。
  • 1MiB超は Amazon SQS Extended Client Library(Java/Python)で本体をS3に格納し参照を送る。最大ペイロード2GB。同期クライアントのみ対応。

SQSは永続ストアではなく一時保管庫です。保持期間(既定4日)は「取り出されなければいつか消える」という有効期限であり、サイズ上限(1MiB)は「本文の運搬役であって巨大データの倉庫ではない」という設計思想の表れです。大きなペイロードはS3に置いて参照だけ流す——S3編で見た「オブジェクトストアに本体、キューにはポインタ」という役割分担がそのまま当てはまります。

公式ドキュメントで詳しく ↗