AWS SAA(Solutions Architect - Associate)対策

疎結合の総合設計

このレッスンを終えると、密結合な構成図を見て「どこが最初に壊れるか」を指摘し、キューと通知を挟んで直す手順を自分で組み立てられるようになります。SAA のシナリオ問題は、まさにこの指摘と修正の力を測っています。

まず壊れる構成を1つ見ます

あるチケット販売サイトの現在の構成です。

  • ALB の背後に Web サーバーの EC2 が4台
  • Web サーバーは、購入リクエストを受けると同じリクエストの中で在庫の引き当て、決済 API の呼び出し、PDF のチケット生成、確認メールの送信を順に実行する
  • 決済 API とメール送信は外部サービスを直接呼んでいる
  • 生成した PDF は Web サーバーのローカルディスクに保存し、後からその1台だけが配信する

人気公演の発売開始で、この構成は次のように壊れました。

1つ目は、遅い処理に全体が引きずられる点です。 PDF 生成は1件あたり数秒かかります。リクエストの中で同期実行しているので、Web サーバーのスレッドがそこで塞がり、在庫確認だけしたい利用者まで待たされます。

2つ目は、外部サービスの障害がそのまま自分の障害になる点です。 メール送信の外部サービスが応答しなくなると、購入処理そのものがエラーになります。決済は成功しているのにメールで落ちて、利用者には失敗と見える、という最悪の状態も起きます。

3つ目は、スケールの単位が1つしかない点です。 重いのは PDF 生成なのに、増やせるのは Web サーバーだけです。Web サーバーを増やすと外部の決済 API への同時接続も一緒に増え、そちらで先に詰まります。

4つ目は、状態をローカルに持っている点です。 PDF を持っている1台が落ちるとチケットが取り出せません。Auto Scaling で縮退したときにも消えます。

直す手順

手順1 状態をインスタンスの外へ出す

疎結合の前提は、どのインスタンスに当たっても同じ結果になることです。PDF は S3 に、セッションは ElastiCache か DynamoDB に移します。ここができていないと、この後どれだけキューを挟んでもスケールできません。

手順2 同期でなくてよい処理を切り出す

利用者が待つ必要があるのは「席が取れたか」までです。PDF 生成とメール送信は後で構いません。ここを SQS に投げ、Web サーバーは購入番号だけ返して即座に応答します。応答時間が数秒から数十ミリ秒になります。

手順3 1つの出来事から複数の処理へ広げる

購入が確定したという出来事に対して、PDF 生成、メール送信、売上集計の更新、不正検知の3つ4つがぶら下がります。ここで SNS のトピックに1回発行し、それぞれの SQS が購読する形にします。処理を追加するとき、購入側のコードを触らずに済みます。

手順4 処理側を独立にスケールさせる

PDF 生成のワーカーは、キューの深さをメトリクスにした Auto Scaling で増減させます。Web サーバーの台数とは無関係に伸びます。重い処理だけを増やせるので、費用の効率も上がります。

手順5 失敗に備える

各キューにデッドレターキューを付け、何度も失敗するメッセージを隔離します。外部サービスが落ちている間、メッセージはキューに残り、復旧後に処理されます。これが「外部の障害が自分の障害にならない」という状態です。

変わったことの対比

観点直す前直した後
応答時間一番遅い処理に引きずられる席の確保だけで返す
外部障害の影響購入処理ごと失敗するキューに溜まり、復旧後に処理される
スケールの単位Web サーバーだけ処理ごとに独立して増減する
処理の追加購入処理のコードを改修するトピックに購読を追加するだけ
インスタンス障害ローカルの PDF を失うどのワーカーが落ちても再処理される

要件語から構成への対応

要件の言い回し選ぶもの
送信側と処理側を独立にスケールさせたい間に SQS を挟む
1つの出来事から複数の処理を走らせたいSNS のファンアウト
外部サービスの停止中も注文を受け付けたいキューにバッファし、復旧後に処理する
処理の追加でアプリを改修したくないイベント駆動にして購読を足す
どのインスタンスに当たっても同じ結果にしたいステートレス化して S3 や DynamoDB に状態を置く
順序を保ったまま疎結合にしたいSNS FIFO と SQS FIFO
処理の順序と分岐、リトライを管理したいStep Functions

よくある引っ掛け

1つ目は、「応答が遅い」に対して「EC2 のインスタンスタイプを大きくする」「Web サーバーの台数を増やす」という選択肢です。一時的には効きますが、詰まっているのが外部 API や重い同期処理なら根本は変わらず、費用だけ増えます。設問に「スケールの単位を分けたい」「アーキテクチャを見直したい」という語があれば、キューを挟む案が正解です。

2つ目は、ステートレス化を飛ばしてキューだけ挟む選択肢です。ローカルディスクに成果物を置いたままだと、ワーカーを増やしても取り出せる場所がばらつきます。疎結合の第一歩は状態を外に出すことで、この順序は試験でも問われます。

まとめ

  • 密結合の症状は、遅延の伝播、障害の伝播、スケール単位の固定、状態の局在の4つです
  • 直す順序は、状態を外へ、同期を非同期へ、1対1を1対多へ、そしてスケールを分けるです
  • キューはバッファであり、外部障害の間も受付を続けられます
  • 処理の追加で送信側を改修しないで済むのが、イベント駆動の実利です
  • 台数を増やして殴る選択肢は、費用の制約が付いた設問でほぼ落ちます
生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部

復習ミニクイズ

ある写真共有サービスでは、Web サーバーがアップロード受付と同じリクエスト内でサムネイル生成を実行し、生成物をインスタンスのローカルディスクに保存しています。アクセス増加時に応答が悪化し、Auto Scaling で縮退すると一部のサムネイルが失われます。アプリの改修を伴ってよいものとして、この2つの問題を同時に解消する構成はどれですか。