LoginSignup
4
6

More than 1 year has passed since last update.

Amazon SQS とよくある非同期処理設計

Last updated at Posted at 2023-03-02

はじめに

非同期処理って難しいですよね。
私の開発現場では Shoryuken gem (Ruby) を使って、Amazon SQS を用いた非同期処理を実現しています。

本記事では Amazon SQS 世間一般でのよくある仕組みを解説してみようと思います。

よくある SQS を使った非同期処理

下図の様な、AWS 上に構築された Web アプリケーション (シングルページアプリケーション) を想定します。

  1. ユーザーがブラウザで操作 (時間のかかる機能の実行指示) をする
  2. Web サーバーは Amazon SQS にメッセージを投下し、(重い処理はここではせずに) 即座にレスポンスを返す
  3. Worker サーバーは Amazon SQS 上のメッセージを受信し、処理を開始する

7a2e4575-1106-87d3-1a64-b32e9f46c98f.png

以降、Amazon SQS の説明では上記サーバーをそれぞれ以下の様に表記します。

  • Web サーバー →Client
  • Worker サーバー → Worker

Amazon SQS

Amazon SQS を利用する際は AWS SDK や Ruby アプリケーションの場合は Shoryuken の様なライブラリを用いる事が多いと思います。

基本的に次の3つの操作が主になります。

  1. メッセージを投入する
  2. メッセージを受信する
  3. メッセージを削除する

Pasted_Image_2023_03_03_9_24.png

キューにメッセージを投入

Client は非同期処理を Worker に依頼する為に、Amazon SQS にメッセージを投入します。

df96bdba-a50c-63fb-64d6-eac71b62d421.png

一般的に Amazon SQS を FIFO で構築した場合は、次に投入するメッセージは後ろに積まれます。
つまり 先に投入されたメッセージから順に処理 されます。

6900b845-724d-cb85-1d82-8d1862e30ea1.png

Worker サーバーがメッセージを受け取る

Worker は FIFO の場合は最も古い (先に入れた) メッセージを受信します。

この時、Amazon SQS では 可視性タイムアウト という仕組みがあり、受信したメッセージは (Default では30秒間) 見えなくなります。

c1093d99-9532-7d7b-f5f5-4ba1ebc37097.png

下図では、別の Worker (2) が Amazon SQS からメッセージを受信していますが、 message 1 は見えない為、message 2 が受信されます。

0854f5e2-62cc-7245-af6e-025f984cb901.png

一見すると 「メッセージ受信する際に削除してくれればいいじゃん!」 と思うのですが、その理由は後述する「リトライ」にあります。

非同期処理を正常終了する

無事 Worker (1) は、非同期処理を終えました。

その際に Worker は必ず 受信したメッセージを削除 しなければいけません。

a2f33db9-2a96-9848-c398-00d7e1034d23.png

その理由は...

リトライ

前述の通り、Amazon SQS には 可視性タイムアウト という仕組みがあり、メッセージが削除されずに一定時間が立つと、また見える様になります。

例えば下図の例では、Worker (1) は message 1 を受信した筈ですが、 処理中 (プログラムコード) に例外が発生して完了しなかった と想定しましょう。

処理に失敗した場合は、メッセージを削除してはいけません。

この場合は 可視性タイムアウト により、メッセージがまた見える様になる事で Worker が再度メッセージを受信してくれる為、結果的に 処理のリトライ が行われる事になります。

4e81c9f0-7224-e7f1-6796-8b60fd86eca8.png

コード中で try-catch してリトライ、等はすべきではありません。
コード上でのリトライは、そのサーバーがフリーズした場合等に実施が保証されない為です。

問題 (多重参照)

ここで一つ 可視性タイムアウト のよくある注意点があります。

タイムアウト時間が、想定する処理にかかる時間 (※最大時間) より小さい場合、まだ処理が終わっていないのに、別の Worker によるリトライが発生 してしまいます!

4175a879-92c5-86c1-e691-a2f29506b9a1.png

タイムアウトの延長 (Heartbeat)

一般的に Amazon SQS では、アプリケーションの非同期処理の最大時間を計測し、それを超える 可視性タイムアウト を設定する運用が望ましいです。

ただし、処理時間がどの位になるか想定できないケースも多々あるかと思います。
その場合は、受信したメッセージの 可視性タイムアウト を延長 (※正確にはリセット) する方法もあります。

ハートビートという機能を使うと、まだ処理中のメッセージの 可視性タイムアウト を延長できます。
Shoryuken 等では auto_visibility_timeout という Worker option もあります。

e42a95a3-54e3-b1ac-8c22-577f244e568e.png

4
6
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
4
6