「PoC(概念実証)では完璧に動いていたRAGアプリが、本番環境でユーザーアクセスが増えた途端にレスポンスを返さなくなった。しかも、GPUコストだけが跳ね上がっている」
多くの開発現場において、AIプロジェクトで頻繁に直面するのがこの問題です。Kubernetes(K8s)の運用経験が豊富なエンジニアほど、従来のWebアプリケーションと同じ感覚でオートスケーリングを設定し、痛い目を見ることがあります。
なぜなら、LLM(大規模言語モデル)を扱うAIインフラの特性は、一般的なマイクロサービスとは根本的に異なるからです。
今回は、RAGシステムを本番運用に乗せるために避けては通れない「AIインフラのオートスケーリング設計」について、長年の開発現場で培った知見をベースに解説します。CPU負荷ではなく「何」を見てスケールすべきなのか。そして、それを実現するための強力なツール「KEDA」をどう使いこなすか。インフラ設計の視点を少し変えるだけで、コスト効率とユーザー体験は劇的に改善します。皆さんのプロジェクトでは、どのような指標を監視していますか?ぜひ考えながら読み進めてみてください。
なぜWebアプリと同じ設定ではRAGが破綻するのか
まず、多くのプロジェクトが陥る「失敗パターン」から見ていきましょう。Kubernetes標準のHorizontal Pod Autoscaler(HPA)を使って、CPU使用率が80%を超えたらPodを増やす。これは一般的なWebサーバーなら正解ですが、RAGシステム、特にLLM推論サーバーにおいては「悪手」になりかねません。たとえKubernetesの最新バージョン(v1.35など)を利用していたとしても、デフォルトの設定のままではこの構造的なミスマッチは解消されないのです。
CPU使用率でスケールしてはいけない理由
LLMの推論処理において、パフォーマンスのボトルネックになるのはCPUではなく、圧倒的にGPU(およびVRAM)です。しかし、推論コンテナ内のアプリケーションロジック(Pythonのコードなど)がリクエストを受け付けてGPUに命令を送る際、CPU使用率はそれほど上昇しないケースが多々あります。
例えば、ある推論リクエストがGPUで計算処理を行っている間、CPUは単にその結果を待っているだけ(I/O待ち)の状態になることがあります。この時、CPU使用率は低いままですが、GPUはフル稼働しています。この状態で次のリクエストが来たらどうなるでしょうか?
CPU負荷ベースのHPAは「まだ余裕がある」と判断し、新しいPodを追加しません。結果、既存のPodにリクエストが積み上がり、GPUの処理待ち行列(キュー)が発生します。ユーザーから見れば「いつまで経っても返答が来ない」状態、つまりレイテンシの致命的な悪化です。
さらに、最新の推論最適化技術(量子化やNVFP4などの効率化フォーマット)を導入して処理速度を上げたとしても、VRAM容量が並列処理数(バッチサイズ)の物理的な限界を決める構造は変わりません。CPU指標だけを見ていては、このVRAMの限界を検知できず、システムはサイレントに破綻していきます。
モデルロード時間という「魔の数分間」
もう一つの大きな違いは、アプリケーションの起動時間です。軽量なWebサーバーなら数秒で起動しますが、LLMを搭載したコンテナはそうはいきません。
数GBから数十GBあるモデルデータをストレージから読み込み、VRAMに展開する。このプロセスには、最適化された環境でも数十秒から数分かかります。これは現場で「魔の数分間」として恐れられています。
負荷が高まってから「さて、スケールアウトするか」と判断しても、新しいPodがリクエストを処理できるようになるのは数分後です。その間、ユーザーは待たされ続けます。従来のリアクティブ(反応的)なスケーリングでは、このタイムラグを埋めることができません。
GPUリソースの枯渇とコストの壁
そして現実的な問題として、GPUリソースは非常に高価かつ有限です。
特に2026年以降、GPUおよびVRAMの市場価格は上昇傾向にあることが報告されています。ハードウェアの性能向上に伴い導入コストやクラウドインスタンスの単価が高止まりする中、リソース効率の重要性はかつてないほど高まっています。
無計画なスケーリングは、経営的な観点から見ればクラウド破産への直行便です。「必要な時に必要な分だけ」リソースを確保し、使わない時は徹底的に縮小する。このメリハリこそが、RAGシステムの収益性を左右します。クラウドベンダーのGPUクォータ(割当枠)の制限内で、いかに効率よくリクエストを捌くかが、エンジニアの腕の見せ所と言えるでしょう。
ステップ1:正しい「スケーリング指標」を定義する
では、何をトリガー(引き金)にしてスケールすべきなのでしょうか?
答えはシンプルです。「今、どれだけの処理が待たされているか」です。
監視すべきは「並列リクエスト数」と「キュー滞留数」
AI推論サーバーにとって最も正直な指標は、アプリケーションレベルでのメトリクスです。
- アクティブなリクエスト数(In-flight Requests): 現在処理中のリクエスト数。
- キューの深さ(Queue Depth): 処理待ちのリクエスト数。
例えば、1つのGPUが同時に快適に処理できるリクエスト数(これを「目標同時実行数」やTarget Concurrencyと呼びます)が「2」だとします。現在のアクティブなリクエストが「10」なら、単純計算で5つのPodが必要です。
このように、インフラのリソース使用率(CPU/Memory/GPU使用率)ではなく、アプリケーションの負荷状況を直接見るのが、AIオートスケーリングの鉄則です。
レイテンシ許容値からの逆算アプローチ
設計段階では、SLA(サービス品質保証)として定義した「目標レイテンシ」から逆算して、スケーリングの閾値を決めます。
- 目標: 95%のリクエストを5秒以内に返したい。
- 現状: 1リクエストの推論に平均2秒かかる。
- 計算: 1つのPodで直列処理する場合、キューに2つリクエストが溜まると、3つ目のリクエストは「待ち4秒 + 処理2秒 = 6秒」となり、目標をオーバーする。
この場合、1つのPodが抱えてよい同時リクエスト数は「2」までとし、それを超えそうになったら即座にスケールアウトを開始する、というロジックが成り立ちます。
カスタムメトリクスの設計パターン
これを実装するには、アプリケーション側でPrometheus形式のメトリクスを吐き出す必要があります。FastAPIやFlaskなどで推論サーバーを構築しているなら、ミドルウェアでリクエスト数をカウントし、/metrics エンドポイントで公開するのが一般的です。
# 概念的な実装イメージ
from prometheus_client import Gauge
IN_PROGRESS = Gauge("app_inprogress_requests", "Number of requests in progress")
@app.middleware("http")
async def track_requests(request: Request, call_next):
IN_PROGRESS.inc()
try:
response = await call_next(request)
return response
finally:
IN_PROGRESS.dec()
このようにアプリケーション内部の状態を外部(Prometheusなど)に伝え、それをスケーラーが読み取る構成を作ります。
ステップ2:KEDAを用いたイベント駆動スケーリングの実装設計
ここで重要な役割を果たすのが、KEDA (Kubernetes Event-driven Autoscaling) です。Kubernetes標準のHPA(Horizontal Pod Autoscaler)はCPUやメモリ使用率に基づくスケーリングには最適ですが、RAGシステムのように外部イベントや複雑なメトリクスに基づいてスケーリングを行う場合、設定の複雑化や機能不足という課題に直面します。KEDAはこの課題を解決するデファクトスタンダードとなっています。
Kubernetes標準のHPAとKEDAの違い
KEDAは、HPAを拡張する「メトリクスサーバー」および「コントローラー」として機能します。AWS SQS、GCP Pub/Sub、Kafka、Prometheusなど、60種類以上のイベントソース(Scaler)を監視し、その情報をHPAが解釈可能な形式に変換して渡す役割を担います。
最大の特徴は、「0(ゼロ)へのスケーリング」が可能である点です。標準のHPAは通常、最小レプリカ数を「1」としてリソースを常時確保する必要がありますが、KEDAを用いれば、リクエストが全くない夜間や休日にはPod数を「0」にし、GPUインスタンスのコストを完全に削減することが可能です。
Scalerの設定:Prometheusクエリとの連携
実装においては、ScaledObject というカスタムリソース(CRD)を定義し、「どのメトリクスを」「どの閾値で」監視するかを指定します。
以下は、Prometheusのメトリクスを使用してスケーリングさせる場合の、KEDAの標準的な設定例です。
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: rag-inference-scaler
namespace: rag-production
spec:
scaleTargetRef:
name: rag-inference-deployment
minReplicaCount: 1 # 本番環境では即応性確保のため1以上を推奨
maxReplicaCount: 10 # 予算とクォータに応じた上限設定
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus-server.monitoring.svc.cluster.local
metricName: app_inprogress_requests
threshold: '2' # Podあたり2リクエストを超えたらスケールアウト
query: sum(app_inprogress_requests{app="rag-inference"})
この設定により、KEDAはPrometheusに対して定期的にクエリを実行し、システム全体の処理中リクエスト数が (現在のPod数 * 2) を超えているかを監視します。閾値を超過した場合、HPAを通じてPod数を動的に調整します。なお、apiVersion や設定項目はKEDAのバージョンによって異なる場合があるため、必ず公式ドキュメントで最新仕様を確認してください。
ゼロスケール(0→1)の挙動と注意点
KEDAの「ゼロスケール」機能はコスト削減に極めて有効ですが、RAGシステムの本番運用、特にLLMを扱う環境では慎重な設計が求められます。
リクエスト発生時にPod数が0から1へスケールする際、以下の「コールドスタート」遅延が発生します:
- ノードのプロビジョニング: クラスタに余裕がない場合、Cluster Autoscalerが新規ノード(GPUインスタンス等)を立ち上げる時間(数分)。
- イメージのプル: コンテナイメージのダウンロード時間。
- モデルのロード: LLMをGPUメモリに展開する時間(数十秒〜数分)。
この待機時間は、ユーザー体験(UX)において致命的なタイムアウトエラーを引き起こす可能性があります。特に、GKE(Google Kubernetes Engine)の最新バージョン(1.31系以降など)やAutopilotモードを利用する場合でも、インフラ側のプロビジョニング時間は依然として物理的な制約を受けます。
したがって、以下のような使い分けが推奨されます:
- 本番環境(Production):
minReplicaCount: 1以上を維持し、即応性を最優先する。 - 開発・検証環境(Development):
minReplicaCount: 0に設定し、徹底的なコスト削減を図る。
また、GKEの最新機能ではStandardクラスタとAutopilotの特性を組み合わせた運用も可能になってきており、ワークロードに応じた最適なコンピュートクラスの選択が、コストとパフォーマンスのバランスを保つ鍵となります。
ステップ3:コールドスタート対策と「予測的」な運用
オートスケーリングの仕組みができても、「魔の数分間(起動遅延)」の問題は残ります。これをどう緩和するかが、アーキテクトの腕の見せ所です。
モデルのプリロードとコンテナイメージの軽量化
起動時間を短縮するための技術的なアプローチです。
モデルをコンテナイメージに含める(Baking):
実行時にS3やGCSからモデルをダウンロードするのではなく、ビルド時にコンテナイメージ内にモデルを含めてしまう方法です。イメージサイズは巨大になりますが、起動時のネットワークI/Oを排除でき、起動時間を安定させることができます。ただし、CI/CDパイプラインの負荷やレジストリのコストには注意が必要です。高速な共有ストレージのマウント:
KubernetesのノードにSSDをアタッチし、そこをHostPathや高速なPV(Persistent Volume)としてマウントする方法です。一度ダウンロードされたモデルをキャッシュとして利用することで、2回目以降の起動を高速化します。
Over-provisioningによる「余裕」の作り方
「スパイクが来てから増やすのでは遅い」なら、「常に少し多めに用意しておく」のが確実な解決策です。
これをOver-provisioning(過剰配置)と呼びます。例えば、計算上で必要なPod数が「5」だとしたら、常に「+1」あるいは「+20%」のバッファを持たせておく戦略です。
Kubernetesには PriorityClass という機能があります。優先度の低い「プレースホルダー用Pod(何もしない軽量なPod)」をあらかじめ起動しておき、本番の推論Podが必要になったら、プレースホルダーPodを追い出して(Preemption)、即座にリソースを明け渡させるテクニックもあります。これにより、ノードの追加(Cluster Autoscaler)にかかる数分間の待ち時間を回避し、Podの起動時間だけでスケールアウトが可能になります。
スケジュールベースのスケーリング併用
AIサービスのトラフィックには、人間活動に紐づく明確なパターンがあることが多いです。例えば、B2Bサービスなら平日の9:00〜18:00にアクセスが集中し、深夜は閑散とします。
KEDAは Cron トリガーもサポートしています。これを使って、「平日の朝8:50には最小レプリカ数を5に引き上げる」「19:00には1に戻す」といったスケジュール設定を行います。
リアクティブなメトリクス監視(Prometheus)と、プロアクティブなスケジュール設定(Cron)を組み合わせることで、予測可能な負荷に対して先手を打ちつつ、突発的なスパイクにも対応できる堅牢なシステムになります。
失敗しないためのパラメータチューニングとテスト
まずは小さなプロトタイプを作り、仮説を即座に形にして検証するアプローチも有効です。設定値の妥当性は、机上の計算だけでは判断できません。本番投入前には、以下の観点で徹底的なテストを行う必要があります。ここを疎かにすると、リソースの過剰なスケーリングによるコスト超過や、不安定な挙動(フラッピング)によるパフォーマンス低下を招くことになります。
スケールアウト/インの「クールダウン期間」設定
負荷が閾値付近で細かく上下している際、Podが増減を繰り返す現象を「フラッピング」と呼びます。これはシステムを不安定にし、不要な再起動オーバーヘッドを生みます。
KEDA(およびKubernetes標準のHPA)の設定では、stabilizationWindowSeconds の調整が重要です。特にスケールイン(縮小)に関しては、慎重な設定が求められます。
- スケールアウト: ユーザー体験を守るため素早く反応させる(例: 0〜60秒)。
- スケールイン: 一時的な負荷低下の可能性があるため、遅延させる(例: 300〜600秒)。
「一度増やしたリソースは、少なくとも5〜10分は維持する」という設定にすることで、断続的なスパイクにも余裕を持って対応できます。
負荷テストとAPIライフサイクルの検証
RAG特有の負荷シナリオ:
- プロンプト長の変動: 短い質問と、長いコンテキストを含む質問を混在させ、処理時間のばらつきによるメトリクス変動を確認します。
- コールドスタート再現: リクエストを停止してPod数を最小まで減らした後、急激な負荷をかけて立ち上がり時間とエラー率を計測します。
- ツール:
Locustやk6が有用です。特にLocustはPythonでカスタムシナリオを記述でき、複雑なRAGのリクエストフローを模倣するのに適しています。
Kubernetesバージョン追従と廃止APIのチェック:
Kubernetesの進化は速く、プラットフォームの更新がオートスケーリング設定に影響を与えることがあります。- サポート期限の確認: 公式情報によると、Kubernetesのバージョンサイクルは早く、例えばバージョン1.32系は2026年3月にサポート終了を迎えるなど、定期的な更新が必須です。GKE等のマネージドサービスでは、最新の安定版(例:1.35系など)へのアップグレードが推奨されています。
- 廃止APIの検証: クラスターをアップグレードする際、HPAやKEDAのマニフェストで使用しているAPIバージョンが廃止されていないか確認してください。公式ドキュメントで「Deprecated API」情報をチェックし、テスト環境でアップグレード検証を行うことが、突然の動作停止を防ぐ鍵となります。
コスト上限(Max Replicas)の安全装置
オートスケーリングは強力ですが、設定ミスやアプリケーションのバグ(例:AIエージェントの無限ループ)によって、リソースが際限なく拡大するリスクがあります。
必ず maxReplicaCount を設定し、予算内で許容できる物理的な上限を設けてください。また、クラウドプロバイダーの予算アラート(Budget Alert)を併用し、想定外のコスト急増が発生した際に即座に検知できる体制を整えておくことは、エンジニアとしての責務です。
まとめ:AIインフラは「生き物」として管理する
RAGシステムのオートスケーリングは、一度設定して完了するものではありません。モデルの更新、ユーザーの利用パターンの変化、そしてKubernetes自体の進化に合わせて、継続的な調整が必要です。
- CPUではなく「滞留リクエスト」を見る:ユーザー体験に直結する指標を選ぶ。
- KEDAで賢くスケールする:イベント駆動型のアプローチを取り入れる。
- インフラの鮮度を保つ:廃止APIのチェックやバージョンアップ対応を運用フローに組み込む。
これらのポイントを押さえることで、あなたのRAGシステムは、コスト効率とパフォーマンスのバランスが取れた、真に「プロダクションレディ」なインフラへと進化します。
公式ドキュメントやベストプラクティスを参考に、堅牢なAI基盤を構築してください。
コメント