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対多へ、そしてスケールを分けるです
- キューはバッファであり、外部障害の間も受付を続けられます
- 処理の追加で送信側を改修しないで済むのが、イベント駆動の実利です
- 台数を増やして殴る選択肢は、費用の制約が付いた設問でほぼ落ちます
復習ミニクイズ
ある写真共有サービスでは、Web サーバーがアップロード受付と同じリクエスト内でサムネイル生成を実行し、生成物をインスタンスのローカルディスクに保存しています。アクセス増加時に応答が悪化し、Auto Scaling で縮退すると一部のサムネイルが失われます。アプリの改修を伴ってよいものとして、この2つの問題を同時に解消する構成はどれですか。