前回の記事でAWS SNSをゼロから触ってみたので、その流れで今回はSNSの相棒とよく言われるAWS SQSを試してみました。
名前がよく似ているのでSNSと混同されがちですが、役割はまったく違います。SNSが「配るハブ」だとすると、SQSは「ためる受け皿」です。
この記事ではAWS SQSの仕組みをやさしく解説したうえで、AWS CLIだけで完結する最小構成のハンズオンで実際にキューを作って、メッセージを送って受信して削除するところまでを一通り試します。
実際に触ってみると、ドキュメントを読むだけではピンと来なかった「可視性タイムアウト」や「標準キューの順不同」がスッと腑に落ちます。SNSの次に学ぶAWSサービスとして、ぜひ手を動かしながら読んでみてください。
記事の目次
AWS SQSとは?「メッセージをためる待機列」をイメージするとわかりやすい
AWS SQS(Amazon Simple Queue Service)は、ひとことで言うと「メッセージを一時的にためておいて、受信者が後からまとめて処理するためのサービス」です。
イメージとしては「受付カウンターの整理券」が近いです。
お客さんが来るたびに整理券を発行してキューに並べておき、担当者は自分のペースで1件ずつ呼び出して処理する。
処理能力を超えてお客さんが一気に来ても、整理券があふれることはあっても対応自体は崩れない、という仕組みです。
SNSと並べて比較するとわかりやすいです。
| サービス | 配信方式 | イメージ | 向いている用途 |
| SNS | Push型(即時配信) | 拡声器 | 通知・アラート |
| SQS | Pull型(受信者が取りに行く) | 整理券・待機列 | 確実に処理したい業務タスク |
SNSは「1回叫べば全員に届く」サービスで、届けたらそこで役目は終了です。
対してSQSは「受信者が能動的に取りに行くまでメッセージがキューに残り続ける」ので、処理漏れを防ぎたい業務処理に向いています。
SQSを理解する3つのキーワード
SQSを触るうえで避けて通れない概念が3つあります。
ここを押さえておくと、この後のハンズオンがスッと頭に入ります。
①可視性タイムアウト ― 「取り出し≠処理完了」がSQSの肝
SQSのもっとも独特な仕組みが可視性タイムアウトです。
普通のキューのイメージだと「取り出したら消える」と思うかもしれませんが、SQSは違います。
受信者がメッセージを取り出しても、処理が完了したことを明示的に伝える「削除リクエスト」を送るまで、メッセージはキューに残り続けます。
ただし取り出し中は他の受信者から見えなくなるように一時的に不可視になる、というのが可視性タイムアウトの役割です。
デフォルトは30秒で、この時間内に削除リクエストが来なければ、メッセージは再びキューに戻り、別の受信者が取り出せる状態になります。
なぜこんなややこしい仕組みになっているのか?
理由はシンプルで、処理中に受信者がクラッシュしてもメッセージを失わないためです。
取り出した瞬間に消してしまうと、処理途中でエラーが起きたときにメッセージが消失してしまいます。
「受け取った人がちゃんと処理し終えたら消す」という流れにすることで、メッセージの確実性を担保しているわけです。
この仕組みのおかげで、標準キューでは同じメッセージが複数回配信される可能性があります(Pull型なのに重複するのはこれが理由)。
処理側では同じメッセージを複数回受け取っても問題ないように設計しておくのが基本です。
②標準キューとFIFOキュー ― 順序と重複の扱いが違う
SQSには2種類のキューがあります。
| キュー種類 | 順序保証 | 重複排除 | スループット |
| 標準キュー | なし(ベストエフォート) | なし | 事実上無制限 |
| FIFOキュー | あり(先入れ先出し) | あり | 1秒あたり3,000件など上限あり |
「順序保証がない」というのがなかなかクセ者で、送った順に取り出せるとは限りません。
今回のハンズオンでも実際にこの挙動を体感します。
ほとんどのユースケースでは標準キューで十分です。
決済処理のように「順序が命」「二重実行は絶対NG」といった厳密な要件がある場合にFIFOキューを検討する、くらいの使い分けで問題ありません。
③デッドレターキュー(DLQ) ― 失敗し続けたメッセージの避難先
何度処理してもエラーになるメッセージというのは存在します。
例えばJSONが壊れていたり、参照先のレコードが存在しなかったりするケースです。
こういうメッセージを放置すると、受信者が無限に取り出してはエラーで削除せず戻す、という無駄な処理を繰り返してしまいます(標準キューは順不同なので「キューが詰まる」というより、むしろ受信者のリソースが浪費されるのが問題)。
これを防ぐのがDLQ(デッドレターキュー)です。
「受信回数が◯回を超えたらこちらに隔離する」という設定をしておくと、問題のあるメッセージが自動的に別のキューに移されます。
隔離されたメッセージは原因を調査して、修正したうえで再投入することもできます。
SNS vs SQSの使い分け ― 共通点は「非同期」、違いは「確実性」
「SNSもSQSも非同期処理で使うんでしょ?」と思うかもしれません。
これは半分正解です。
どちらも「処理を同期的に待たない」という意味では非同期ですが、実務での使い分けのキモはメッセージの確実性にあります。
- SNS: 配信時点で受信者が処理に失敗しても、メッセージは基本的に消える
- SQS: 受信者が「処理完了」と明示するまでメッセージは残り続ける
たとえば「エラー通知をSlackに投げる」ならSNSで十分です。
万が一1件届かなくても、致命的な問題にはなりにくい。
一方「注文データを後続の処理に引き渡す」ならSQSです。
1件でも消えたら売上が消えることになるので、確実にキューに残しておいて確実に処理したい。
実務でよく使う「SNS→SQS」のFan-outパターン
SNSとSQSは対立するサービスではなく、組み合わせて使うのが王道です。代表例がFan-outパターンです。
注文完了 ↓ SNSトピックに1回パブリッシュ ├─ SQSキューA → 管理DBへの登録処理 ├─ SQSキューB → ユーザーへの通知処理 └─ SQSキューC → Slack通知処理
SNSで1回パブリッシュすれば、登録されている複数のSQSキューに同時にメッセージが入ります。
各処理はそれぞれのキューから自分のペースで取り出して処理できるので、確実性・独立性・負荷分散がまとめて手に入るわけです。
今回の記事ではSQS単体の動きに絞りますが、この先に「SNSと組み合わせた構成」が待っているとイメージしておくと、SQSの位置づけがわかりやすくなります。
AWS SQSの料金は?検証レベルなら無料枠で余裕
AWS SQSにも無料枠があります。
| 項目 | 無料枠 |
| リクエスト | 月100万件 |
超過後も100万件あたり$0.40〜と安価です。
今回のように「キューを1つ作って数件送受信する」検証レベルなら、無料枠を気にする必要はまったくありません。
AWS CLIだけでSQSを試してみる【最小構成ハンズオン】
ここからは実際に手を動かします。
今回使うのはAWS CLIのみです。
コンソールには動作確認のために寄り道しますが、メインの操作はすべてターミナルから実行します。
最小構成の流れはこうです。
キュー作成 → メッセージ送信 → 受信 → 削除 → キュー削除
この間に可視性タイムアウトや「標準キューの順不同」といった挙動も体感していきます。
事前準備 ― ここで詰まる人が多いので最初に片付ける
AWS CLIを使うにあたって、「CLIがインストールされている」だけでは不十分です。
どのAWSアカウントのどのユーザーとして接続するかを確認しておく必要があります。
自分もここで一度ハマりました。
まずは現在のプロファイル設定を確認します。
aws configure list
`profile` や `region` が空だったり想定と違うようなら、プロファイルを指定して切り替えます。
コマンドごとに `–profile xxx` を付けるのも手ですが、セッション全体で切り替えるほうが楽です。
export AWS_PROFILE=tsukarooohi
この状態で `aws configure list` を再度実行すると、プロファイルが切り替わっているのが確認できます。
実行するIAMユーザーにはSQS操作の権限(`AmazonSQSFullAccess` など)が必要です。
権限がないと後のコマンドで `AccessDenied` が返ってきます。
ステップ1:キューを作る
準備が整ったらキューを作成します。`create-queue` にキュー名を指定するだけです。
aws sqs create-queue --queue-name test-queue
実行すると、以下のようにQueueURLが返ってきます。
このURL、この後のほぼすべてのコマンドで使う重要な値なのでメモしておきます。
{
"QueueUrl": "https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/test-queue"
}
AWSコンソールのSQS画面を開くと、ちゃんとキューが作成されているのが確認できます。
ステップ2:メッセージを送る
キューにメッセージを送信します。`send-message` にQueueURLとメッセージ本文を指定します。
aws sqs send-message \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/test-queue \ --message-body "テストメッセージ1件目"
返ってきた `MD5OfMessageBody` や `MessageId` はメッセージの識別子ですが、後続の操作で直接使うことはほぼありません。
「送信が受理された」ことの証拠くらいに思っておけばOKです。
コンソール側でキューを確認すると、「メッセージ利用可能」列が1になっています。
補足ですが、コンソールで「メッセージの送受信」ボタンを押してポーリングする必要はありません。
件数を見るだけなら一覧の「メッセージ利用可能」列で十分確認できます(「メッセージをポーリング」ボタンは受信操作と同じなので、確認目的で押すとメッセージを取り出してしまいます)。
続けて2件目も送ってみます。
aws sqs send-message \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/test-queue \ --message-body "テストメッセージ2件目"
コンソールで再確認すると、件数が2になっています。
ステップ3:メッセージを受信する ― ここで「順不同」と「件数保証なし」に遭遇する
いよいよメッセージを受信します。
`receive-message` にQueueURLを指定するだけです。
aws sqs receive-message \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/test-queue
ちなみに `–queue-url` には`send-message` で使ったのと同じURLをそのまま指定します。
`send-message` の返り値である `MessageId` ではないので注意してください(自分はここで一瞬迷いました)。
返ってきたメッセージを見ると、1件目か2件目のどちらか一方だけが返ってきます。
これが**標準キューの順不同**の正体です。
送信した順に取り出せるとは限らず、どちらが返るかはSQS側の都合次第です。
「2件入ってるなら2件まとめて取れるのでは?」と思って `–max-number-of-messages 2` を付けてみます。
aws sqs receive-message \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/test-queue \ --max-number-of-messages 2
ところが、2件指定しても1件しか返ってこないということがあります。
これは不具合ではなくSQSの仕様です。
`–max-number-of-messages` は「最大◯件まで」という上限の指定にすぎず、必ずその件数が返ることを保証するものではありません。
標準キューは分散アーキテクチャで動いているため、1回のリクエストで到達できたサーバーに入っていた分だけが返ってくる、という挙動になります。
全件取りたい場合は何度かリクエストを繰り返すか、そもそも「1回で全件取得できる前提」で設計しないのが正解です。
ステップ4:可視性タイムアウトを体感する
受信できたメッセージをあえて削除せずに30秒ほど放置してみます。
まずは現在のキューの可視性タイムアウト設定を確認しておきます。
aws sqs get-queue-attributes \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/test-queue \ --attribute-names VisibilityTimeout
デフォルトは30秒です。
受信直後にコンソールを確認すると、「メッセージ利用可能」が減っている(取り出したメッセージは不可視になるため)のが見えます。
受信済みでまだタイムアウト中のメッセージは、他の受信者からは見えません。
そして30秒が経過すると、削除リクエストを送っていないのでメッセージがキューに戻ってきます。
件数がまた元に戻るのを目視すると、「取り出し≠処理完了」という設計思想が体感としてわかります。
ステップ5:メッセージを削除する
処理が終わったことをSQSに伝えるのが `delete-message` です。
受信時に返ってきた `ReceiptHandle`(一時的な受信トークン)を使って削除します。
aws sqs delete-message \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/test-queue \ --receipt-handle "AQEB...(受信時に返ってきた長い文字列)"
削除後にキューの件数を確認すると、ちゃんと減っているのが確認できます。
`ReceiptHandle` は取り出すたびに変わる一時トークンなので、`MessageId` と混同しないように注意です。
ステップ6:後片付けにキューを削除する
検証が終わったらキューごと削除しておきます。
aws sqs delete-queue \ --queue-url https://sqs.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/test-queue
コンソールを確認すると、キューが一覧から消えているのがわかります。
ちなみに `delete-queue` は即座には反映されないことがあり、AWSドキュメント上は「削除には最大60秒かかる場合がある」とされています。
すぐ再作成する場合は少し待つと安心です。
実際に触ってわかった3つの落とし穴
一通り試してみて、ドキュメントを読んだだけではハマったであろうポイントが3つありました。
①「CLIが入っている」≠「すぐ使える」
CLIのインストールとは別に、プロファイル設定とIAM権限が整っていないとコマンドは動きません。
最初に `aws configure list` で接続先を確認する癖をつけておくと、無駄な `AccessDenied` で時間を溶かさずに済みます。
②標準キューは「件数保証」も「順序保証」もない
`–max-number-of-messages 10` は上限であって、10件返ることを約束するものではありません。
また送信順に届くとも限りません。ここを理解していないと「バグってない?」と首をかしげることになります。
③DLQの存在意義は「詰まり解消」ではなく「リソース浪費の回避」
標準キューは順不同なので「失敗メッセージが後続をブロックする」という性質は本来ありません。
DLQの本当の役割は、無限リトライでConsumer側のリソースを浪費するのを防ぐことです。
ここを正しく理解しておくと、DLQを設計する判断がブレなくなります。
SQSを実際に試してみて感じたこと
SNSのときは「結局ただのメーラーじゃない?」という感想が出るまで少し時間がかかりましたが、SQSはむしろ逆で、手を動かした瞬間に「これは便利だ」と腹落ちするサービスでした。
特に「取り出しても削除リクエストを送らないとメッセージが戻ってくる」という挙動は、実際にキューに入れて体感するのが一番早いです。
ドキュメントで「可視性タイムアウト」と書かれていてもピンと来ない概念が、30秒待つだけで一気に理解できます。
SQSで押さえておくべきキーワードはこの3つだけです。
- 可視性タイムアウト:取り出しても削除するまでメッセージは残る
- 標準キュー vs FIFOキュー:順序と重複の扱いが違う
- DLQ:失敗し続けたメッセージの避難先
今回はSQS単体の動きに絞りましたが、次はSNS→SQSのFan-outパターンを組んで、イベントを複数のキューに配信する構成を試してみようと思います。
そちらも記事にする予定なので、興味があれば続けて読んでもらえると嬉しいです。
「AWSのメッセージング系サービスって難しそう」と感じている方こそ、まずはCLIだけで最小構成で触ってみるのがおすすめです。
思った以上にシンプルに動くことが体感できるはずです。

















