オートスケールを「CPUが上がれば増やす」で設定したまま本番に出すと、台数の振動・ウォームアップ不足・障害時の無限増設という三つの落とし穴にはまる。設計の核心は「どのメトリクスで発動させるか」「スケールアウトとスケールインの閾値をどこに置くか」「上限と停止条件をどう設定するか」の三点にあり、最初の判断が運用の安定性をほぼ決定する。
CPU使用率だけで増減させて台数が振動する構造
閾値が近すぎることで起きる増減の連鎖
CPU使用率が70%を超えたらスケールアウト、50%を下回ったらスケールインという設定は多くのドキュメントに例として登場するが、本番トラフィックの前では台数が10〜15分周期で行き来する「振動」を引き起こしやすい。新しいインスタンスが起動すると全体の平均CPU使用率が下がり、スケールインの条件を満たして台数が減り、今度はまたCPU使用率が上昇してスケールアウトが発動する。このサイクルは自動化されているため誰も止めず、コストだけが上下し続ける。
シングルメトリクス依存が生む死角
振動の根本にあるのは、閾値の差が20ポイントしかないことよりも「CPUというシングルメトリクスが処理の実態を反映しない場面がある」という構造的な問題だ。I/O待ちが多いワークロード、DBへの接続待ちが支配的なケース、あるいはGCが頻繁に発生しているJavaアプリケーションでは、CPU使用率が低いまま処理が詰まり、レスポンスタイムだけが劣化し続ける。CPUだけを見ていると「スケールアウト不要」と判断され続け、エンドユーザーへの影響が広がってから初めて問題に気づくことになる。
振動しない設計へのアプローチ
振動を設計段階で防ぐには、スケールアウト閾値とスケールイン閾値の間に最低30ポイント以上の差を設けることが出発点になる。CPU70%でアウト、40%以下でインという非対称な設定がその一例だ。さらに重要なのはクールダウン期間の確保で、スケールアクション直後に次のアクションを一定時間抑制することにより、新しいインスタンスが評価対象に含まれる前に再判定されることを物理的に防ぐ。クールダウンの具体的な設定については後の節で詳述する。
自動増減が効く負荷と効かない負荷の見分け方
水平スケールが線形に効くパターン
オートスケールが本質的に有効なのは「ステートレスな処理の量的な増減」に限られる。HTTPリクエストを独立して処理するAPIサーバー、SQSやRabbitMQのキューを消費するワーカー、静的コンテンツを配信するオリジンサーバーなどがその典型だ。これらは台数を倍にすることで処理能力がほぼ倍になる線形性を持ち、スケールアウトが設計に素直に効く。逆に言えば、この線形性がない部分に自動増減を適用してもコストが増えるだけで性能は改善しない。
台数を増やしても改善しない負荷の特徴
DBの接続数上限に縛られた処理、セッションをアプリサーバーのローカルメモリで管理しているアプリケーション、N+1クエリが根本にあるパフォーマンス問題には、スケールアウトはほとんど効かない。ある構築現場では、セッション管理をアプリサーバー内メモリで行っていたため、スケールアウト後に別のインスタンスへリクエストが振り分けられるたびにセッション切れが発生した。台数が増えるほど問題の発生頻度が上がるという本末転倒な状態が本番で顕在化した例として、現場では語り継がれている。
スケールアウト対応かどうかを事前に判断する基準
設計段階で行うべき問いは「このコンポーネントはステートを持っているか」という一点に絞られる。アーキテクチャ図にステートの場所を明示し、ステートを持つコンポーネントはスケールアウト対象から外すか、ステートを外部のKVSやDBに切り出してからスケール設計に進む。外出しが完了していない状態でオートスケールを有効にするのは、設計上の欠陥を自動化で覆い隠そうとする行為であり、後から修正するコストは設計段階の数倍に膨らむ。
比較表: 固定台数/スケジュール増減/メトリクス連動の選び方
スケール戦略は大別して三種類あり、ワークロードの特性によって使い分けるか組み合わせる。以下は選定の判断材料として整理した比較表だ。
| 戦略 | 向いているワークロード | 設定の複雑さ | コスト効率 | 主なリスク |
|---|---|---|---|---|
| 固定台数 | 常時高負荷・予測困難な急増・DBコネクション数が固定上限に近いシステム | 低(設定箇所が少ない) | 低〜中(オーバープロビジョニング前提) | ピーク時の容量不足、リソースの無駄 |
| スケジュール増減 | 業務時間帯と夜間で負荷が明確に変わるシステム・週次バッチ処理がある構成 | 中(スケジュール管理が必要) | 中〜高(予測可能な増減には最適) | 想定外のトラフィック増加への対応不足 |
| メトリクス連動(動的スケール) | トラフィックが不規則・イベント駆動で急増するAPIサーバー・キューワーカー | 高(閾値・クールダウン・上限の設計が必要) | 高(負荷に応じた最小台数での運用が可能) | 振動・起動時間の遅延・障害時の増設連鎖 |
実際の本番環境では、スケジュール増減とメトリクス連動を組み合わせる構成が多く採用されている。例えば平日9時に最小台数を4台から8台に引き上げ、その上でCPU使用率やキュー長に応じた動的スケールを動かすといった設計が代表的だ。この組み合わせにより、業務開始時の起動待ち問題を解消しながら、想定外のスパイクにもメトリクス連動で対応できる。
増やす閾値・減らす閾値とクールダウンの決め方
閾値はキャパシティプランニングから逆算する
スケールアウト閾値の出発点は、インスタンス1台が安定して処理できる最大スループットを負荷試験で計測することだ。その70〜80%を閾値に設定する逆算が基本で、例えば1台あたり500QPSまで健全に処理できる場合、350〜400QPSに達した時点でスケールアウトを発動させる。この余裕により、新しいインスタンスが起動・ウォームアップして実際に処理を受け取れるようになるまでの時間を確保できる。閾値をキャパシティの95%近くに設定すると、ウォームアップ完了前に既存インスタンスが過負荷になるため、余裕は必ず残す設計にする。
スケールアウトは積極的に・スケールインは保守的に
スケールアウトはレスポンス劣化を防ぐために早めに発動させ、スケールインはコスト最適化のために遅めに発動させるのが実践的なバランスだ。スケールイン後に再びスケールアウトが必要になる「バウンシング」を防ぐため、スケールインの閾値はスケールアウト閾値の50〜60%以下を目安にする。CPU70%でアウトならスケールインは35%以下という設計がその例だ。この非対称な設定は一見リソースを遊ばせているように見えるが、バウンシングが繰り返される場合の無駄なスケールアクションと比較するとトータルコストは下がる傾向にある。
クールダウンはインスタンスの起動完了時間を基準に設定する
クールダウンとはスケールアクション後に次のスケールアクションを抑制する時間のことで、この設計がなければ振動は構造的に防げない。設定の下限はインスタンスの起動時間(AMIから起動するなら平均2〜5分、コンテナなら30秒〜2分)にアプリケーションのウォームアップ時間を加えた値になる。JVMを使うJavaアプリケーションでウォームアップに3分かかるなら、起動時間との合算で最低7〜8分以上のクールダウンを設定するのが基本だ。クールダウンを短く設定しすぎると、ウォームアップ中のインスタンスが評価対象に入り閾値判定がずれるため、短ければよいわけではない。
起動時間とウォームアップを織り込んだ余裕の取り方
起動時間は実測の最大値を基準にする
起動時間は理論値と実測値で大きく乖離することがある。AMIの構成、ユーザーデータスクリプトの処理量、ヘルスチェックが通過するまでの時間を合計すると、「平均2分」のインスタンスでも最大6〜7分かかるケースは珍しくない。ネットワークの状況やAZの混雑により起動時間がばらつくことも考慮が必要だ。スケール設計の前に検証環境でスケールアウトを10回以上トリガーして平均と最大値を記録し、最大値に基づいて余裕を取るやり方が現場では定着している。
ウォームアップ中インスタンスの処理能力を過信しない
ウォームアップ中のインスタンスは「起動してはいるが低パフォーマンス状態」にある。Javaアプリケーションでは、JITコンパイルが進む前の段階で定常スループットの30〜50%しか処理できないケースが報告されている。これを無視してスケールアウトを「台数が増えた時点で即戦力」と見なすと、ピーク時のキャパシティ計算が外れてキャパシティ不足が長引く。現場での対策としては、ウォームアップリクエストを自動で送信する仕組みを起動シーケンスに組み込み、ヘルスチェックの通過条件をウォームアップ完了後に設定する方法が確実だ。
事前スケールアウトで起動待ちを設計上ゼロにする
毎朝9時の業務開始、週次バッチの実行時刻、セールイベントの開始時刻など、トラフィック増加が予測できる場面では、メトリクスを待たずに時刻ベースで事前にスケールアウトを発動させる設計が合理的だ。この「予測スケール」により、ピーク到来時の起動時間とウォームアップ時間を実質ゼロにできる。スケジュール増減とメトリクス連動を組み合わせてベースラインを先に確保し、想定外の急増にはメトリクス連動が自動で対応する構成が、安定性とコスト効率の両立という点で支持を集めている。
自動化を効かせすぎて障害時に増え続ける境界
障害がスケールアウトを誘発するメカニズム
アプリケーションの障害(DBの応答遅延、依存する外部APIのタイムアウトなど)が発生すると、処理待ちのキューが積み上がりCPU使用率やキュー長が上昇する。オートスケールはこれを「負荷増大のシグナル」と判定し、スケールアウトを発動させる。しかし増えたインスタンスも同じ障害の影響を受けるため処理を消化できず、メトリクスは改善しないまま次のスケールアウトが発動する。この連鎖は最大台数のキャップに達するまで自動で続く。上限を設定していなかった構成では、障害発生から30分で台数が通常の10倍に達し、コスト面での緊急対応が必要になったという事例が報告されている。
上限設計を隔離壁として機能させる
オートスケールの最大台数(MaxCount)は単なるコスト上限ではなく、障害時の連鎖増設を止める「隔離壁」として設計する視点が必要だ。上限を「通常ピーク時の2倍程度」に抑えることで、障害由来の異常なスケールアウトを一定の範囲内に収められる。さらに重要なのは、上限に達したことをアラートに連携させることで、異常な増設を人間が検知して手動介入できる設計にすることだ。上限到達イコール障害の可能性が高いという仮説を持ち、アラートを「台数の警告」ではなく「障害の一次検知」として運用設計に組み込む。
スケールアウトを停止する条件を設計に持つ
障害時の増設連鎖を設計で遮断するには、「スケールアウトしても改善しないメトリクスの組み合わせ」を事前に定義し、そのパターンが検出されたときにスケールアウトを一時停止する条件を組み込む方法がある。例えば「DBのエラー率が5%を超えているときはスケールアウトを保留する」という判断ルールをポリシーに追加することで、障害増幅ループを設計段階で断ち切れる。CloudWatchのコンポジットアラームやDatadog Monitorsでこの条件を実装することは技術的に可能だが、まず設計上の判断として「停止条件を持つ」という方針を明文化することが先決であり、具体的な実装手順はプラットフォームごとに異なるためここでは設計判断の骨格にとどめる。
オートスケール設計チェックリスト
以下は本番投入前に確認すべき設計判断の項目だ。すべての項目に「判断済み」の答えが出ていることを確認してから本番へ進む。
- スケールアウト対象コンポーネントのステートレス性を確認した——セッション・ローカルキャッシュ・ファイルIOなどのステートが外部に切り出されているか。
- スケールアウト閾値をキャパシティの70〜80%に設定した——負荷試験で1台あたりの最大スループットを実測した上で逆算しているか。
- スケールアウト閾値とスケールイン閾値に30ポイント以上の差を設けた——バウンシング防止のための非対称設定になっているか。
- クールダウンをインスタンス起動時間+ウォームアップ時間以上に設定した——実測の最大値を基準に設定しているか。
- メトリクスをCPU以外に少なくとも1つ組み合わせている——キュー長・レスポンスタイム・接続数など処理実態を反映するメトリクスを使っているか。
- 最大台数(MaxCount)を通常ピークの2倍以内に設定した——上限到達時のアラートを設定しているか。
- 起動時間とウォームアップ時間を実測し設計に織り込んだ——検証環境で10回以上スケールアウトをトリガーして計測したか。
- 予測可能なトラフィック増加には事前スケールアウト(スケジュール設定)を組み込んだ——業務開始時刻・バッチ実行時刻などを確認したか。
- 障害時にスケールアウトが連鎖しない条件を設計に持っている——DBエラー率・外部API障害などをスケールアウト抑制条件として定義しているか。
- スケールイン後に残る最小台数でも通常負荷を処理できることを確認した——深夜帯などのスケールイン後の台数で最低限のスループットを捌けるか。
▶ 手を動かして本番まで到達する
設計の型は掴めても、本番でTerraformを通しきる経験は別物です
ここまでの設計判断は、読めば腹に落ちます。ですが「自分の手で本番まで通しきる自信」は、それとは別の話になります。
2日間の集中ハンズオンで、AWS上にIaCで構築しきる経験を持ち帰れます。設計判断を、動くコードと本番環境の手応えに変える場です。
オートスケール設定をTerraformで実装するハンズオンへ →
Terraformマスターセミナー|2日間ハンズオンでAWS上にIaCで本番構築