「メッセージが少なくとも 1 回配信されること」にまつわる SQS 使う上での注意点
この記事は Willgate Advent Calendar 2018 - Qiita の 9 日目の記事です。
以前弊社のブログで、 Amazon Simple Queue Service (以下 SQS と呼ぶ) を導入した例についての記事を書きました。
当時は「メッセージが少なくとも 1 回配信されることしか保証されていない」ということがイマイチピンときていなかったため、調べながら導入・実装に当たっていました。
今回は「メッセージが少なくとも 1 回配信されることしか保証されていない」ことで、実装時に何を気をつけなければいけないか分かったことをまとめます。
保証されていることは「メッセージが少なくとも 1 回配信されること」のみ
まず前提として、SQSは「メッセージが少なくとも 1 回配信されること」しか保証されていません。そのため以下のようなことが起こります。
- 同じメッセージを重複して取得した
- 別のシステムからA, B, C, Dという順番でメッセージを送信したが、受信するときにはB, D, A, Cという順番で取得した。
- SQSにメッセージが存在してるにも関わらず、空のレスポンスが返ってきた
- 削除済みのメッセージを取得した
一つずつ見ていきましょう。
同じメッセージを重複して取得した
「少なくとも 1 回配信」ということなので、同じメッセージを複数取得することがあります。
対処法としては、「メッセージ ID を見て、重複していた時には重複を消す」といった処理の追加が挙げられます。
別のシステムからA, B, C, Dという順番でメッセージを送信したが、受信するときにはB, D, A, Cという順番で取得した
SQS にはスタンダードキューと FIFO キューというものが存在します。この現象は SQS のスタンダートキューで起きる現象です。
「キューは普通、先入先出し(FIFO)じゃないの?」というツッコミが来そうですが…残念ながら、スタンダートキューではメッセージ送信の順番は保証されていません。もし、メッセージ送信の順番を保持してほしいならば、 FIFO キューを使いましょう。
2018/12/25 現在、東京リージョンでも FIFO キューを使用することができます。 aws.amazon.com
FIFO キューを使用しないならば、パッと思いつく限りだと「メッセージに送信時間を含ませ、メッセージをキューから受け取った後に送信時間でソートする」でしょうか?
確実にできる保証はないので、出来れば FIFO キューを使う方が良いかなと思います。
SQS にメッセージが存在してるにも関わらず、空のレスポンスが返ってくる
こちらバグではなく、どうやら仕様のようです。
Amazon SQS は分散システムであるため、キューにあるメッセージが非常に少ない場合は、受信したリクエストに対して空のレスポンスを表示する場合があります。
対策としては ReceiveMessageWaitTimeSeconds を1秒以上に設定する、いわゆるロングポーリングを設定することが挙げられます。
例えば、ReceiveMessageWaitTimeSeconds を10秒に設定すると、メッセージを取得するまで最大10秒待つことになります。10秒の間にメッセージを取得できなかった時は空のレスポンスが帰ってきます。
詳しくはこちらに書いてあります。
削除済みのメッセージを取得した
こちらもバグではなく、仕様だそうです。
この場合、使用できないサーバーではメッセージのコピーが削除されず、メッセージの受信時に、そのメッセージコピーをもう一度受け取る場合があります。
どういった目的で SQS を使用するかによりますが、既にそのメッセージを使った処理が行われているか判定するロジックが必要になります。
例えば、メッセージに DB へ登録するための ID が挿入されているとします。その時は「保存先の DB を参照し、既に ID が登録されていた時にはメッセージを削除する」といった処理が必要になってきます。
まとめ
最初は SQS 特有の注意点が多くて、戸惑うことや面倒だと思うことも多いと思います。 それでも享受できるメリットの方がはるかに大きいサービスだと思いますので、是非プロダクトにてご活用ください!