AWS SAA(Solutions Architect - Associate)対策

SQSの設計

このレッスンを終えると、要件の文にある「順序」「重複」「急な増加」「詰まる」という言葉から、標準キューか FIFO キューか、そしてデッドレターキューを足すかどうかを、その場で決められるようになります。

要件の文から入ります

ある EC 事業者が、注文を受け付ける Web サーバーと、在庫を引き当てて出荷指示を作るバックエンドを直接つないで動かしています。ここで2つの事故が起きました。

1つ目は、セール開始の直後に注文が平常時の数十倍になり、バックエンドが処理しきれず、Web 側までエラーを返すようになったことです。2つ目は、ある1件の壊れた注文データで処理が必ず失敗し、それが再試行され続けて、後ろに並んだ注文がまったく進まなくなったことです。

SAA ではこの2つが別々の設問として出ます。前者は「スパイクを吸収する」話で、後者は「毒メッセージを隔離する」話です。同じ SQS でも答えが違います。

標準キューと FIFO キューの線引き

Web とバックエンドの間に SQS を挟むと、Web は注文をキューに入れた時点で応答を返せます。バックエンドは自分の処理できる速さで取り出せばよく、あふれた分はキューに溜まって待ちます。これがバッファとしての使い方です。

では標準と FIFO のどちらかという話になります。要件語で切り分けます。

見る観点標準キューFIFO キュー
順序ベストエフォート。前後が入れ替わりうる送った順に取り出せる
重複同じメッセージが複数回届きうる重複排除 ID により1回だけ処理される
スループット実質的に上限を意識しなくてよい標準より低い。上限がある
向く要件大量のスパイク吸収、画像変換など順序が無関係な処理会計の仕訳、口座の入出金、在庫の増減など

判断は単純です。「順序が保証される必要がある」「重複して処理されてはならない」という文が要件にあれば FIFO「急激な増加を受け止めたい」「できるだけ多くさばきたい」なら標準です。両方書いてあるときは FIFO を選び、スループットの上限が問題になるならメッセージグループ ID を分けて並列度を上げる、という順で考えます。

注意したいのは、標準キューを選んだ場合はアプリ側が同じメッセージを2回受け取っても壊れないように作る必要がある、という点です。受信のたびに残高を足すような処理は、標準キューでは必ず事故ります。試験ではこの「アプリを冪等に作る」という選択肢が正解になることもあります。

可視性タイムアウトは処理時間から決めます

コンシューマーがメッセージを受け取ると、そのメッセージは一定時間だけ他のコンシューマーから見えなくなります。これが可視性タイムアウトです。処理が終わって削除すればそこで消え、削除されないまま時間が切れると、また見えるようになって別のコンシューマーが拾います。

ここが設計判断です。可視性タイムアウトが実際の処理時間より短いと、まだ処理中なのに別のコンシューマーが同じメッセージを拾い、二重処理になります。 動画の変換に平均5分かかるのに可視性タイムアウトが既定のままだと、変換が終わる前に2本目、3本目が走り始めます。

対策は2つあります。処理時間より十分長い値を設定する方法と、処理が長引いたときにアプリから可視性タイムアウトを延長する方法です。後者は処理時間のばらつきが大きいときに向きます。逆に長すぎると、コンシューマーが落ちたときに再処理が始まるまで待たされます。

何度やっても失敗するメッセージはデッドレターキューへ

冒頭の2つ目の事故がこれです。壊れたメッセージは何回再試行しても失敗し、そのたびにキューへ戻ってきて、他の処理を圧迫します。

デッドレターキューを設定し、最大受信回数を決めておくと、その回数を超えたメッセージは自動的に別のキューへ移されます。本流のキューは詰まらなくなり、隔離された側を後から人が調べられます。「特定のメッセージが何度も失敗して処理が滞る」「失敗したメッセージを後で調査したい」という要件が出たら、答えはデッドレターキューです。

要件語から構成への対応

要件の言い回し選ぶもの
送信した順序どおりに処理したいFIFO キュー
同じ処理が二重に実行されては困るFIFO キュー、または冪等な実装
突発的なアクセス増をバックエンドに伝えたくない標準キューでバッファする
ワーカーの台数を負荷に応じて増減させたいキューの深さをメトリクスにした Auto Scaling
失敗し続けるメッセージを隔離したいデッドレターキュー
処理に時間がかかり二重処理が起きている可視性タイムアウトを処理時間より長くする

よくある引っ掛け

1つ目は、二重処理の相談に対して「デッドレターキューを設定する」という選択肢です。デッドレターキューは失敗の隔離であって、二重処理は防ぎません。処理時間と可視性タイムアウトの関係を疑うのが先です。

2つ目は、順序の要件に対して「標準キューにタイムスタンプを持たせてアプリで並べ替える」という選択肢です。動きはしますが、アプリの改修が必要で、運用の手間も増えます。「アプリを改修せずに」という制約が付いていたら確実に落ちます。

まとめ

  • 順序と重複排除が要件なら FIFO、スパイク吸収と量が要件なら標準を選びます
  • 標準キューを選んだら、アプリは同じメッセージを2回受けても壊れない作りにします
  • 可視性タイムアウトは実処理時間より長くします。短いと二重処理になります
  • 失敗し続けるメッセージはデッドレターキューへ逃がし、本流を詰まらせません
  • キューの深さでワーカーをスケールさせると、送信側と処理側が独立して伸びます
生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部

復習ミニクイズ

ある決済システムが SQS を使って取引メッセージを処理しています。ワーカーは1件あたり平均90秒かかりますが、可視性タイムアウトは既定の30秒のままです。最近、同じ取引が二重に計上される事象が発生しています。アプリを改修せずにこの問題を解消する対応はどれですか。