woshidan's blog

そんなことよりコードにダイブ。

AWS SQSのvisibility timeoutとdelay queueのdelayの違いについて

今週の復習です。

consumerがキューからメッセージを受信するリクエストを送った後、

  • 通信の問題で結局受け取れなかった
  • consumer側で処理中にエラーになって結局最後まで処理できなかった

などの事態に備えるため、SQSのキューにあるメッセージはconsumerが受け取った時点では消えない。

consumerはメッセージを受信して処理した後、キューに対してメッセージ削除のリクエストを送る必要がある。

また、

  • SQSのキューにある1つのメッセージを複数のconsumerが受信してもおかしくない

ので、

  • SQSのキューの仕組みとして: キュー上のあるメッセージに受信リクエストが来た後、指定の秒数の間は他のconsumerにそのキューを見せない visiblity timeout を設定する*1
  • 実装側として: 複数のconsumerが同じメッセージを処理しても問題ない実装にしておく

ということを考える必要がある。 visiblity timeout はデフォルトだと 30秒の設定となっている*2

visiblity timeout を利用している場合、SQSのキューに溜まっているメッセージの数は

  • ApproximateNumberOfMessagesNotVisible (あるconsumerがそのメッセージを処理しているかも)
  • ApproximateNumberOfMessagesVisible (どのconsumerもまだそのメッセージを処理していないかも *3 )

の合計となる。

上記がSQSのふつうのキューを使った場合で、キューを使った非同期で動くシステムの中には、キューにメッセージを送った直後はそのメッセージを消費して欲しくない、という場合がある*4。その場合は、delay queueを利用する。

SQS delay queueを利用した場合、

  • standard queueでキューから取り出そうとしたメッセージに対して visiblity timeout の設定を利用した場合: あるconsumerが受信リクエストを送った後、指定の秒数他のconsumerからメッセージが取得できなくなる

のに対し

  • delay queue に追加されたメッセージの場合: producer からメッセージをキューに追加された後、delayで指定した秒数consumerからメッセージが取得できなくなる

の違いがある。また、

  • visiblity timeout の設定はキューに詰めるメッセージに個別に指定
  • delay queueのdelayの設定はキューに対して指定(=>キューに入るメッセージ全体に適用)

される。

delay queueにおいて、全体に適用されるdelayの設定は固定ではなく、メッセージによってはdelayの値を変えたい、といった場合は message timer の delay seconds の指定で上書きが可能*5

delay queueのユースケースがわからないので、もやりとしていますが、現場からは以上です。

*1:というより、デフォルトで30秒に設定されている

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

*3:これはconsumerがメッセージを処理するのに必要な時間に応じたvisibility_timeoutを設定している想定で、この辺が適切でなかった場合はその限りではない

*4:このケースについて自分では調べててよくわからなかったんですが、sidekiqなどジョブ管理システムのキューにSQSを利用していて、デフォルトではリトライの時にちょっと時間をおいて欲しいとか、短時間のうちにキャンセルのリクエストがくる可能性があるジョブのリクエストを待つとか...? でも、キャンセルのメッセージがリクエストのメッセージと同じconsumerで処理されなければ意味がなくない...?

*5:https://www.slideshare.net/AmazonWebServicesJapan/aws-31275003 の27ページ目