9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SQSのFIFOはFIFOに処理し終わることを保証する

Last updated at Posted at 2021-04-09

TL;DR

SQSのFIFOは、「メッセージの先頭から順番にconsumerにわたるよ」くらいの認識でいると痛い目にあう。

正確には

メッセージの先頭から順番にconsumerが処理し終わる(諦めてDeadletterQueueに移動することも含む)

ことを保証している。

ドキュメント

https://dev.classmethod.jp/articles/sqs-new-fifo/ をなんとなく読んでいて以下の記述が気になった。

グループの先頭しかメッセージを取れませんので、100万件のメッセージが入っていても、グループが1つであれば、ワーカは2つ以上あっても意味がありません。例えば、メッセージの重複だけを排除したいだけで、順序は必要なく、高いスループットでワーカーによる処理を行いたい場合は、メッセージ毎にユニークなUUID等でグループIDを付ければOKです。

「ワーカは2つ以上あっても意味がありません」とは?
AWSの主張をみてみると、

Messages that belong to the same message group are always processed one by one, in a strict order relative to the message group (however, messages that belong to different message groups might be processed out of order).

とあり、processed one by oneとある。
さらに、

When messages that belong to a particular message group ID are invisible, no other consumer can process messages with the same message group ID.

とある。

つまり、「メッセージの先頭から順番にconsumerが処理し終わる」ことを保証していると理解した。

検証

とても簡単にできる。
前提として、

  • FIFO
  • DeadletterQueueが設定され、最大受信数10
  • 可視性タイムアウト 1分

のキューを想定する。consumerがlong pollingでずっとメッセージをpollingしている状況を想定する。

Invalidなメッセージでconsumerがエラーをはいて処理をしない(キューから削除しない)メッセージAと正常なメッセージB/C/Dを用意する。

AWSのコンソール画面にて、

  • 00:00にメッセージグループIDxxx、メッセージ重複排除 ID1にてメッセージAを配信
  • 直後に以下の順で配信
    • メッセージグループIDxxx、メッセージ重複排除 ID2にてメッセージBを配信
    • メッセージグループIDxxx、メッセージ重複排除 ID3にてメッセージCを配信
    • メッセージグループIDyyy、メッセージ重複排除 ID4にてメッセージDを配信

メッセージ重複排除 IDは今回の検証では重複させたくないので全て異なる値にしている。

この場合、consumerはどのように処理をするのか想像してみよう!

正解は

  • メッセージAは00:00,00:01,00:02,00:03,00:04,00:05,00:06,00:07,00:08,00:09と10回consumeしてどれもエラーを吐いておわる
  • メッセージDは00:00にすぐに処理終了
  • メッセージB -> メッセージCの順に00:10に処理される。00:10まではconsumerからはメッセージは見えない。

ドキュメントを注意深く読めば予想通りの結果になるかと思う。

対策

メッセージグループIDを適切に設計しましょうにつきる。
ほとんどの場合でユーザーID(ユーザを特定するキー)を指定するか、乱数を指定してしまえば要件を満たせるのでは。

後者の場合はFIFOキューによってメッセージが重複して配信されないという恩恵のみうけることになる。前者の場合は「入金イベント」「出金イベント」の二つのイベントに対して、1ユーザに対しては順番が保証されているので期待する挙動となる。

一方、誤って「入金イベント」を意味するUserChargedみたいなイベント名をメッセージグループIDにしてしまうと、ある処理が詰まると全ての「入金イベント」が処理できなくなり地獄を見るだろう。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?