✉️

AWS SQSのまとめ

6 min read

AWS SQSを初めて使った際、意外と重要な概念や検討することがありました。
それらをまとめた備忘録です。
メッセージキューイングサービスとは何か、から始めます。

メッセージキューイングサービス

メッセージキューイングとは、異なるソフトウェア間でデータを送受信する手法の一つで、直接データを渡すのではなく一旦第三者のソフトウェアに預けることで、送信側も受信側も好きなタイミングで送受信処理をおこなうことができるようにする方式。
https://e-words.jp/w/メッセージキューイング.html

とのことです。

通常、データの送受信は送信側と受信側が同期的にやり取りする必要がありますが、メッセージキューイングサービスを間に置くことで非同期に行うことが可能になります。

キューに送信する側をプロデューサ(Producer)受信側をコンシューマ(Consumer) と呼びます。

利用ケース

以下のようなケースでは、送信側の処理を早く完了できるようになるため、メッセージキューイングサービスを利用する価値があります。

  • 送信側は受信側の処理結果を必要としないケース
  • 受信側で長時間の処理がかかるケース

モデル

大別して以下の2種類があります。

Peer To Peerモデル

1つのメッセージは1つのコンシューマのみが受信するモデルです。
通常のオンライン処理の間にキューが挟まるイメージです。
AWSのSQSはこちらに該当します。

Pub-Subモデル

1つのメッセージをコピーし複数のコンシューマが受信するモデルです。
複数のユーザに一斉に同じ内容の通知メッセージを送る、などの用途で使われるイメージです。
AWSのSNSなどがこちらに該当します。

Amazon Simple Queue Service (SQS)

公式ページの説明によると、以下の特徴があります。

SQSは、フルマネージド型のメッセージキューイングサービス
切り離しとスケーリングが可能

すなわち以下のメリットがあります。

  • キューのインフラなどはAWS側で管理してくれる
  • サービスを疎結合にでき、高いスループットを得られる

https://aws.amazon.com/jp/sqs/

メッセージのライフサイクル

SQSを利用したメッセージの送受信は以下のライフサイクルになります。

  1. プロデューサがSQSにメッセージを書き込むリクエストを送信する
  2. コンシューマがSQSからメッセージを読み取るリクエストを送信する[1]
  3. コンシューマが読み取ったメッセージを用いて何らかの処理する。
  4. コンシューマがSQSにメッセージ削除のリクエストを送信する[2]

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-basic-architecture.html

種類

SQSのキューは以下の「標準キュー」と「FIFOキュー」の2種類があります

メッセージの扱い 標準キュー FIFOキュー
スループット 無制限 300TPS[3]
配信回数 1回以上[4] 1回を保証
配信順序 送信順(未保証)[5] 送信順を保証
コスト(百万件毎) 0.4$ 0.5$
サイズ 256KB 同左
保存期間 1分~14日(デフォルト4日) 同左

https://aws.amazon.com/jp/sqs/features/

基本的にFIFOキューを利用し、回数や順序は多少不安定でも良いので非常に高いスループットが欲しい場合や、できる限りコストを抑えたい場合は標準キューを利用すれば良さそうです。

以降はFIFOキューを前提にまとめます。

確認すべき概念・機能

SQSの重要な機能として以下のものは確認しておきたいです。

  • ロングポーリング
  • メッセージグループID
  • 可視性タイムアウト
  • デッドレターキュー
  • 重複排除機能

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

コンシューマがキューに対してメッセージを読み出すリクエストを送信した際に、キューが空だった場合、「メッセージ受信待機時間」というパラメータの設定値によってレスポンスの振る舞いが変わります。

0秒を設定した場合:
SQSは即座に空のレスポンスを返します。
この設定状態をショートポーリングと呼びます。

n秒(0<n)に設定した場合:
SQSはn秒後までレスポンスを返さず、その間にメッセージが追加されたらすぐにそれを返します。
n秒後までメッセージが追加されなかった場合は空のレスポンスを返します。
この設定状態をロングポーリングと呼びます。

ReceiveMessageWaitTimeSeconds:デフォルト0秒、最小0秒、最大20秒

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html

コンシューマのリクエスト回数を減らせるため、基本的には最大値の20秒を設定して ロングポーリングにすることが推奨されます。

メッセージグループID

プロデューサはメッセージ送信時に「メッセージグループID」を設定する必要があります。
グループIDが同一のメッセージは順序が保証されますが、
グループIDが異なるメッセージは順序が保証されません。

コンシューマがあるグループIDのメッセージを読みだした場合、そのメッセージの削除リクエストを送るまで、他のプロセスはそのグループIDのメッセージを読み出せません。

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues-understanding-logic.html

処理順序を保証する必要がないメッセージはユニークな値を設定し、
処理順序を保証する必要があるメッセージは固定の値を設定&順序を保証する処理が完了した後にメッセージの削除リクエストを送ることが良さそうです。

可視性タイムアウト

コンシューマがあるメッセージをSQSから読み出したあと、「可視性タイムアウト」で設定した時間以内にそのメッセージの削除リクエストを送らないと、SQSにそのメッセージが復活してFIFOキューであっても2回以上読み出されるようになります。

VisibilityTimeout:デフォルト30秒、最小0秒、最大12時間

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html

基本的にはコンシューマ側でメッセージを処理する最大時間+αを設定することが良さそうです。

デッドレターキュー

デッドレターキューは正常に処理されなかったメッセージを隔離するキューです。

可視性タイムアウトを超えたメッセージはキューに復活し再びコンシューマから読み出されるようになりますが、「最大受信回数」で設定した回数を超えて再び読み出そうとした場合、デッドレターキューに移動し、後続のメッセージが読み出せるようになります。

デッドレターキューは元のキューと同じ種類(標準/FIFO)に設定にしておく必要があります。
デッドレータキューに移動してもメッセージの保存期間はリセットされないため、元のキュー以上の期間を設定しておかないと即座に消滅します。

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html

デッドレターキューへのメッセージ移動を検知するアラームを設定しておくことが良さそうです。
最大受信回数は受信側が冪等に設計されていないなど、コンシューマで同じメッセージを複数回処理をさせたくない場合は1回に設定しておくことが良さそうです。

重複排除機能

各メッセージには、「重複排除用ID」を設定する必要があります。
同一の重複排除用IDのメッセージが5分以内に送信された場合、特にエラーにもならず送信に成功しますが、キューに保存されず消滅します。

重複排除用IDは以下の2種類があります

  • コンテンツベースの設定

    • キューの設定``を有効にしているとメッセージのコンテンツのハッシュ値を元に自動で設定します。
  • メッセージごとの設定

    • プロデューサがメッセージを送信する際に都度ユニークな値を設定します。

重複排除はキュー全体で適用される(グループID単位ではない)
送信から5分以内であれば、既にそのメッセージが受信・削除されていても適用される。

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues-exactly-once-processing.html

メッセージにuuidや日付などユニークな値が含まれるならコンテンツベースの設定で十分そうです。
全く同じ内容のメッセージを複数回送信する必要がある際は、プロデューサがメッセージ毎にする必要があります。

その他

注意点や気になるポイントを挙げます。

インフライトメッセージ

コンシューマがキューから読み出してから削除リクエストが送られるまでの状態にあるメッセージをインフライトメッセージを呼びます。
インフライトメッセージが20000件を超えるとコンシューマは新たにメッセージを読み出せなくなります。

※読み出し時、20000件を超えていても特にエラーは発生せず、空のレスポンスが返ります。
※読み出される前の状態のメッセージの保持数は無制限です。

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html#inflight-messages

高スループットモード

FIFOキューのスループットは通常300TPSですが、2021年初夏に追加された「高スループットモード」の設定を有効化すると10倍の3000TPSになります。料金が高くなるなどのデメリットがありそうですが、今のところドキュメントには特に記載がない…?

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/high-throughput-fifo.html

検討するパラメータまとめ

SQSの設定

パラメータ 英語 設定値
FIFOキュー fifo_queue FIFOキューにする場合はONに設定
キュー名 name FIFOキュー名は.fifoで終わる必要あり
メッセージ保持期間 message_retention_seconds 0~14日(任意)
メッセージ受信待機時間 ReceiveMessageWaitTimeSeconds 0~20秒(20秒推奨)
可視性タイムアウト visibility_timeout_seconds 0~12時間(コンシューマ処理時間+α推奨)
コンテンツベースの重複排除 content_based_deduplication メッセージに必ずユニークな値が含まれるならONに設定

※同等の設定のデッドレターキューを作成しておくこと。

プロデューサのメッセージ送信時の設定

パラメータ 英語 設定値
メッセージグループID message-group-id 順序保証が必要なら固定値
メッセージ重複排除用ID message-deduplication-id 設定した場合、キュー側の設定より優先

コンシューマのメッセージ受信時の設定

パラメータ 英語 設定値
メッセージ最大数 max-number-of-messages 1度に読み出すメッセージの数(最小1, 最大10)
可視性タイムアウト visibility-timeout 設定した場合、キュー側の設定より優先
脚注
  1. つまり受信側はhttpサーバではなくキューをポーリングするhttpクライアントです。 ↩︎

  2. メッセージ削除リクエストは、基本的にはコンシューマは処理の最後に実施します(後述)。データベースで言うところのコミットに相当するイメージです。 ↩︎

  3. コンシューマは1回のリクエストで同時に10件までメッセージを読み出せるため、その場合のスループットは3000TPSになります。 ↩︎

  4. だいたい1回配信ですがたまに2回になってしまうこともある、という意味 ↩︎

  5. だいたい送信順ですが保証はできない、という意味 ↩︎

Discussion

ログインするとコメントできます