Tech カテゴリのイメージ

Scale to Zeroとは?LLM推論のGPU費用と初回待ち時間をどう両立する

夜間にほとんど使われない社内LLMでも、GPU workerを1台動かし続ければ費用は発生する。そこで、requestがない間はreplicaを0まで減らし、次のrequestが来たときだけ起動するScale to Zeroが候補になる。

ただし、0からの復帰は単なるcontainer起動ではない。nodeの確保、image取得、model weightの読み込み、GPU memoryへの配置、runtimeの初期化が終わるまで、最初の利用者は待つ。Scale to Zeroは無料の節約機能ではなく、待ち時間と計算資源の固定費を交換する設計である。

Scale to Zeroは何を0にするのか

Scale to Zeroは、需要がないworkloadの実行replicaを0にする仕組みである。Kubernetes上の推論serviceなら、通常はmodel serverを実行するPodが0になる。

ここで、PodとGPU nodeは分けて考える必要がある。Podを0にしても、GPU nodeがcluster内で起動したままならnode料金は残る。GPU費用まで止めるには、対象Podがなくなった後にcluster autoscalerがnodeも0へ減らせる構成が必要である。KServeのnode scheduling資料も、推論PodのScale to Zeroと専用nodeへの配置を組み合わせ、空になったnodeを縮退させる流れを説明している。

逆に、managed APIを呼ぶapplicationだけを運用している場合、自分の環境にmodel weightやGPUはない。そこでScale to Zeroの対象になるのは、APIを呼ぶweb serviceやworkerであり、model serverのGPU cold startとは別問題である。

0から復帰するときに何を待つのか

LLM推論のcold startは、一つの時間ではない。少なくとも次の段階に分かれる。

  1. requestまたはqueue backlogを検知する
  2. schedulerがPodを作成する
  3. 空きGPUがなければnodeを起動する
  4. container imageを取得してprocessを起動する
  5. model weightをobject storageや共有volumeから読む
  6. weightをCPU memory、続いてGPU memoryへ配置する
  7. runtimeを初期化し、必要ならcompileやwarm-upを行う
  8. serviceをReadyにして、待機中requestを渡す

小さな分類modelなら数秒で済んでも、大きなLLMではmodel weightの転送とGPUへの配置が支配的になりやすい。KServeの公式例でも、Pod生成とmodel downloadによる約10秒のcold startがrequest latencyに現れている。実際のLLMではmodel size、storage帯域、image cache、GPU nodeの確保時間によってさらに長くなる可能性がある。

したがって、監視すべきなのはPodの起動時間だけではない。request到着からReadyまでのactivation latencyを、node provisioning、image pull、weight download、model load、warm-upに分けて測る必要がある。

最初のrequestをどこで待たせるか

replicaが0のとき、requestを直接存在しないPodへ送ることはできない。0の状態でもrequestを受け、起動を開始し、serviceがReadyになるまで保持する入口が必要である。

KServeのServerless modeではKnative Activatorがscaled-to-zeroのPodを復帰させ、requestを転送する。非同期jobなら、queueにmessageを保持し、queue lengthや最古messageの待ち時間を外部metricとしてworkerを起動できる。

この待機場所には上限が必要である。起動に2分かかるのにrequestのdeadlineが30秒なら、復帰後に処理しても利用者はすでに離脱している。待ち続けるのではなく、次のいずれかを選ぶ。

  • 起動完了まで待てる非同期jobとして受け付ける
  • 起動中であることと目安を返し、pollingまたは通知へ切り替える
  • 短いdeadlineのrequestは、起動済みの小型modelや外部APIへ縮退する
  • queueとdeadlineの上限を超えたrequestは早く拒否する

Scale to Zeroを有効にする前に、最初のrequestの待機場所と期限切れ後の扱いを決める。

minimum replicaを0にすれば終わりではない

KnativeではScale to Zeroが有効なら、minimum replicaの既定値は0である。Knativeのscale boundsでは、revisionごとのmin-scale、0から一度に起動するactivation-scale、縮退を遅らせるscale-down-delayを設定できる。

metadata:
annotations:
autoscaling.knative.dev/min-scale: "0"
autoscaling.knative.dev/activation-scale: "2"
autoscaling.knative.dev/scale-down-delay: "15m"

この例は、無通信が続けば最終的に0になる一方、0からは2 replicaで復帰し、短いtraffic低下では15分間すぐに縮退しない構成である。値そのものを流用するのではなく、実測した起動時間、request到着間隔、同時実行数、費用から決める。

また、scale-to-zero-grace-periodは「最後のPodを何分温存するか」を決める設定ではない。Knativeの公式資料では、0へ移るための内部network準備を待つ上限として説明されている。役割の違う設定をcold start対策として変更すると、意図した効果を得られない。

0、1、warm poolをどう使い分けるか

すべてのmodelを0にする必要はない。需要とSLOで分ける。

運用向くworkload主な代償
minimum replica 0開発環境、夜間停止できるbatch、低頻度の専用model最初のrequestがcold startを受ける
minimum replica 1以上対話service、短い応答SLO、常時一定のtrafficidle時にもGPU費用が発生する
warm pooltrafficは疎だがcold startを許容できない複数model待機資源とmodel切替の設計が必要
小型modelへ縮退主modelの起動中にも最低限の応答が必要品質差と利用者への明示が必要

複数の低頻度modelをそれぞれ専用GPUで待機させるより、少数の起動済みworkerへ必要なmodelを読み替える方が資源効率を上げられる場合もある。ただし、modelの入れ替えが頻発すれば、weight転送とGPU memory解放が新たなbottleneckになる。人気modelの常駐、modelごとのmemory量、切替頻度を一緒に測る。

費用だけで判断しない

Scale to Zeroの節約額は、概念的には次で考えられる。

節約額=停止できたGPU時間の費用−復帰処理と待機系の追加費用\text{節約額} = \text{停止できたGPU時間の費用} - \text{復帰処理と待機系の追加費用}

しかし、実際の判断ではcold startによる離脱、SLO違反、timeout後の再試行も費用に含める必要がある。1日に何度も0と1を往復すると、weightの再読込でstorageとnetworkを消費し、最初のrequestを何度も遅らせる。短いidle時間で0にするほど得とは限らない。

少なくとも次をmodel、version、GPU種別ごとに記録する。

  • 0でいた時間とGPU nodeが実際に停止していた時間
  • request到着からPod作成開始まで
  • node確保、image pull、weight download、model load、warm-upの各時間
  • scale-from-zero時のqueue lengthと最古requestの待ち時間
  • cold requestとwarm requestのTTFT、完了時間、timeout率
  • 0から起動した回数と、起動直後に再び0へ戻った回数
  • minimum replicaを維持した場合との費用差

本番投入前の試験

通常時の負荷試験だけではScale to Zeroを検証できない。明示的にreplicaと必要ならGPU nodeを0へ落とし、最初のrequestから測る。

  1. 0から単発requestを送り、deadline内に完了するか確認する
  2. 0の状態へburstを送り、Activatorやqueueがrequestを失わないか確認する
  3. 起動途中でrequestをcancelし、不要な生成を続けないか確認する
  4. weight storageを遅くし、queue上限とtimeoutが機能するか確認する
  5. GPU不足でnodeを確保できない場合、無期限に待たないか確認する
  6. 生成中にscale downせず、requestをdrainしてから終了するか確認する
  7. 新versionへの切替時に旧versionと新versionが同時にcoldにならないか確認する

Scale to ZeroはSLOに合わせて選ぶ

Scale to Zeroは、使われていないGPUを止める強力な手段である。一方、最初の利用者へmodel起動時間を転嫁する。対話serviceで常に数秒以内の応答が必要なら、minimum replicaを残す方が合理的である。低頻度のbatchや開発環境なら、0まで落として非同期queueから復帰させる価値が高い。

重要なのは、minReplicas: 0という設定ではない。Podだけでなくnodeも停止したか、最初のrequestをどこで待たせるか、cold startがdeadlineを超えたらどう縮退するかまでを一つの運用として設計することである。

参考資料