LLM Autoscalingとは?CPU使用率だけでGPU workerを増減しない
LLM APIの待ち時間が伸びたとき、CPU使用率だけを見てworkerを増やしても改善しないことがある。GPU memoryが埋まっている、KV Cacheが足りない、長文requestがschedulerで待っている、model起動に数分かかるなど、bottleneckがCPU以外にあるためだ。
LLM Autoscalingは、trafficと処理能力に合わせてinference replica、GPU node、queue consumerを自動で増減する仕組みである。重要なのは、現在のresource使用量だけでなく、待っている仕事、期限、token量、起動時間、下流上限から必要capacityを判断することである。
autoscalingは過負荷対策の一部であり、無限に増やせる魔法ではない。新replicaがReadyになるまでの間はConcurrency Limit、backpressure、load sheddingが必要であり、GPU quotaや予算を超える前に上限を持たせる。
CPUが低くてもLLMは詰まる
一般的なweb applicationでは、CPU utilizationが需要の近似になる場合がある。しかしLLM inferenceでは、次の理由でCPUと利用者待ち時間が一致しにくい。
- model計算の中心がGPUにある
- GPU memoryとKV Cacheが同時処理数を制限する
- prompt長とoutput長で一件の処理量が大きく変わる
- continuous batchingでGPU utilizationを高く保てる
- token生成は逐次的で、長い出力がslotを長く占有する
- CPUは前処理だけで低く、GPU schedulerには待ちがある
- requestは外部providerのRate Limitで止まっている
CPUが30%でも、GPU memoryが限界でwaiting requestが増えていればscale outが必要かもしれない。反対にGPU utilizationが高くても、batchingによって高throughputと低いqueue waitを維持できているなら、直ちに増やす必要はない。
resource metricだけでなく、利用者が待っている状態を直接測る。
online inferenceで見るmetric
対話APIやcompletion APIでは、次を組み合わせる。
- waiting request数
- requestがqueueで待った時間
- running request数
- time to first token
- inter-token latency
- input tokenとoutput tokenのrate
- GPU utilizationとmemory
- KV Cache使用率
- batch sizeとschedulerの待機
- 429、timeout、deadline超過
vLLMはproduction metricとして、GPU上でrunning中のrequest数、waiting中のrequest数、GPU KV Cache使用率などを公開している。これらはCPUよりLLM servingの混雑を直接表しやすい。
一つのmetricだけで決めると誤る。waiting requestが増えても、数秒後に短いbatchが完了して解消することがある。KV Cache使用率が高くても、TTFTとdeadlineが正常なら効率よく使えている可能性がある。
scale up条件は、waiting数とqueue waitが一定時間続き、SLOに近づいていることを基本にする。GPUとKV Cacheは原因確認とcapacity限界のsignalとして加える。
async jobではqueueの長さと年齢を見る
embedding、batch要約、評価、画像生成などの非同期処理は、message queueへjobを置くことが多い。この場合はCPUよりbacklogが重要である。
- 未処理job数
- 最古jobの待ち時間
- 到着率
- 完了率
- retryとDLQへ移った件数
- deadlineまでの残り時間
- jobごとの推定tokenまたは計算量
job数だけでは、一件30秒の短い処理と一件30分の長い処理を同じ一件として数える。可能ならtoken、画像size、model、max output、過去の処理時間からwork量を見積もる。
KEDAはqueueやKafkaなどのevent sourceを監視し、そのmetricをKubernetes HPAへ渡してDeploymentやStatefulSetをscaleできる。messageがないときに0へ下げ、到着時に起動する構成も可能である。
ただし、queue長が同じでもpartition数やordering keyが並列上限になる。Kafkaではconsumer数がpartition数を超えるとidle consumerが増える。順序を守るkeyが一つに集中していれば、replicaを増やしてもhot partitionは速くならない。
token量でworkloadを測る
LLM requestは件数が同じでも処理量が違う。1件100 tokenのclassificationと、1件10,000 tokenの文書要約を同じQPSとして扱うとcapacity予測が崩れる。
少なくとも次を分ける。
- input token
- output token
- cached token
- reasoning tokenを提供するmodelならその使用量
- image、audio、videoなどmodality別の計算量
- modelごとのthroughput
到着token rateが完了token rateを上回り続ければ、backlogは増える。request数が横ばいでも、長文trafficへ変わればscale upが必要になる。
ただし、まだ生成していないoutput token数は正確に分からない。max outputをそのまま使うと過大評価し、過去平均だけでは長いtailを見落とす。intent、endpoint、tenantごとの分布と高percentileを使い、deadlineと組み合わせる。
起動時間をcontrol loopへ入れる
autoscalerがscale upを決めても、GPU workerがすぐ処理できるとは限らない。
- node provisioning
- container image取得
- model weightのdownload
- GPU memoryへのload
- graph compileやkernel warm up
- health check
- cache warming
需要急増からReadyまで5分かかるなら、現在のqueueだけを見たreactive scalingでは間に合わない。起動中replicaをcapacityとして数えすぎても、実際にはjobを処理できない。
readinessはprocess起動ではなく、modelをloadし、代表的な小requestを処理できる状態で判定する。Kubernetes HPAも、起動直後でReadyではないPodやmetric欠落を保守的に扱う。startup probeとreadiness probeを実際のmodel起動時間へ合わせる。
対策は次の組み合わせになる。
- minimum replicaまたはwarm poolを維持する
- 既知の時間帯は予測して事前scaleする
- model weightをnode近くへ配置する
- imageとmodel artifactを小さくする
- trafficを新replicaへ段階的に流す
- 起動中はqueue、Rate Limit、load sheddingで待ちを制御する
scale-to-zeroは費用を下げるが、最初のrequestがcold startを受ける。対話SLOが短いmodelでは0にしない判断も必要である。
HPAの平均値が偏りを隠す
Kubernetes HPAは、CPU、memory、custom metric、external metricを使い、現在値とtargetの比からreplica数を調整する。複数metricでは、それぞれが提案したreplica数のうち最大を選ぶ。
平均metricには注意する。8 replicaのうち一台へhot keyが集中していても、平均waiting数は低く見える。modelやGPU typeが混在していれば、一replicaあたりのcapacityも同じではない。
次を分離する。
- modelとmodel version
- GPU typeとmemory
- input length class
- tenantやpriority class
- regionとavailability zone
- streamingとnon-streaming
- speculative decodingなどserving構成
異なるcapacityのreplicaを単純に一台として数えず、処理可能token rateやweightで換算する。同じDeploymentへ異なるGPUを混ぜるより、capacity classごとにpoolを分けてrouterで配分する方が管理しやすい。
scale upとscale downを非対称にする
需要増加には早く反応し、需要減少には慎重にする。短いtraffic低下ですぐreplicaを消すと、次の波でまたcold startが起きる。
Kubernetes HPAはscale behaviorで増減rateとstabilization windowを設定できる。scale downでは過去の推奨値を一定時間考慮し、replica数のflappingを抑える。
LLM workloadでは次を考える。
- scale upはqueue waitとSLO riskへ早く反応する
- 起動中replicaが多い間は追加scaleを抑えすぎない
- scale downはtraffic周期とmodel起動時間より長いwindowを持つ
- 一度に削除するreplica数を制限する
- GPU quota回収とcostの上限を別に持つ
metricがtarget付近で揺れると増減を繰り返す。toleranceとstabilizationを使い、小さな変化を無視する。scale decision、起動完了、traffic反映の遅延を合わせてtuningする。
scale down前にrequestをdrainする
replicaを削除するとき、生成中requestを途中で切れば利用者は回答を失い、retryで負荷が増える。新規requestを受け付けないdraining状態へ移し、running requestを完了させてから終了する。
必要な処理は次である。
- load balancerから新規trafficを外す
- running requestとstreamを追跡する
- grace period内で完了を待つ
- deadlineを超えるrequestを安全にcancelまたは再queueする
- checkpointや冪等性情報を保存する
- GPU memoryとconnectionを解放する
長い生成があるとtermination grace periodを超える。最大実行時間を制限し、async jobへ移せるものは分ける。preStop hookだけを書いても、routerが新規trafficを送り続ければdrainにならない。
queue consumerはmessageをackする前に終了しない。Visibility Timeoutとheartbeat、冪等性を組み合わせ、途中jobが別consumerへ戻っても二重副作用を起こさないようにする。
下流とquotaを無視して増やさない
inference replicaを増やすと、RAG database、object storage、model provider、logging、moderation APIへのcallも増える。autoscalingで一つのbottleneckを解消し、別の依存先を落とすことがある。
scale上限は次から決める。
- 利用できるGPU quota
- model licenseとprovider Rate Limit
- database connectionとQPS
- vector search capacity
- network bandwidth
- token予算と日次費用
- tenant別契約上限
- operatorが対応できる障害規模
maximum replicaへ達してもbacklogが増える場合は、さらに増やすのではなく受付制限、優先度、縮退を発動する。SLOを守れない状態で全requestを受け続けると、queue内でdeadline切れになるだけである。
autoscalerが使うmetric sourceが失敗した場合の挙動も決める。Kubernetes HPAは複数metricの一部で計算に失敗し、取得できたmetricがscale downを示す場合はdownscaleをskipする。metric欠落時に誤って0へ下げないfail-safeが必要である。
provider API利用でもautoscalingは必要である
managed LLM APIではGPU replicaを自分で増やさない。それでもapplication worker、queue consumer、RAG、tool executorのscale設計は残る。
provider Rate Limitが固定なら、workerを増やしても429が増えるだけである。providerへ送れるtoken rateとconcurrencyを共有limitとして持ち、その範囲でworkerをscaleする。
複数providerやmodelへrouteする場合、capacityと品質を別に管理する。
- primaryの残りquota
- fallbackの品質と費用
- region別availability
- modelごとのcontext length
- cached inputへの割引とlatency
- data residency
fallbackへ一斉に切り替えると、そちらも過負荷になる。Circuit Breaker、Token Bucket、段階的traffic shiftを使う。
予測scaleとreactive scaleを組み合わせる
毎日9時に社内assistant利用が増える、月末に帳票要約が集中するなど、既知の周期は事前にscaleできる。reactive metricだけでcold startを待つ必要はない。
予測scaleでは、過去traffic、calendar、release、campaign、batch scheduleを使う。ただし予測を外して過剰capacityを維持するriskがある。
基本構成は次である。
- 既知event前にminimum capacityを上げる
- 実trafficはwaitingとqueue ageで追加scaleする
- event後もstabilization windowで急減させない
- 予測が外れたらbudget上限内で戻す
scheduled batchと対話trafficが同じGPU poolを使うなら、batch開始時刻をずらすかpriority queueを分ける。autoscalingだけで競合を解決しない。
観測する指標
replica数だけでなく、scale decisionから利用者効果まで追う。
- current、desired、Ready、starting replica数
- scale up検知からReadyまでの時間
- Readyから実trafficを処理するまでの時間
- waiting requestとqueue age
- TTFT、inter-token latency、deadline超過
- input/output token rate
- GPU utilization、memory、KV Cache使用率
- batch sizeとrunning request
- node provisioningとmodel load時間
- scale event、抑制理由、metric欠落
- draining中requestと強制終了数
- maximum replica到達時間
- replica・GPU時間あたりthroughputと費用
- tenant、model、priority別のSLO
scale out後にreplica数だけ増え、token throughputが増えていないなら、GPU不足、router、shared storage、model load、partition制約を調べる。autoscalerの成功を「desired replicaへ到達した」で終わらせない。
負荷試験で確かめる
- 短文requestを急増させ、scale upがSLO違反前に間に合うか確認する
- QPSを変えず長文へ切り替え、token metricが混雑を検知するか確認する
- model loadを意図的に遅らせ、起動中replicaをcapacityとして誤算しないか確認する
- hot keyまたは一つのordering keyへ集中させ、平均metricが偏りを隠さないか確認する
- maximum replicaへ到達させ、load sheddingと優先度制御が働くか確認する
- scale down中に長いstreamを流し、drainしてから終了するか確認する
- autoscaling metricを欠落させ、誤ったdownscaleをしないか確認する
- providerへ429を返させ、worker増加ではなくbackoffとRate Limitへ移るか確認する
traffic replayはrequest数だけでなく、prompt長、output長、model、tenant、arrival burstを本番分布へ近づける。平均的な短文だけの試験ではGPU memoryとtail latencyの限界が見えない。
まとめ
LLM Autoscalingは、CPU使用率ではなく、waiting request、queue age、token rate、TTFT、GPU memory、KV Cacheなど、仕事と待ち時間を表すmetricで動かす。online inferenceとasync jobではsignalが異なり、job数だけでなく処理量も見る。
model起動には時間がかかるため、scale upが決まってからReadyになるまでqueueとload sheddingで守る。scale downは慎重にし、生成中requestをdrainする。minimum replica、warm pool、予測scaleはcold startがSLOを超える場合に使う。
replicaを増やせる上限は、GPU quotaだけではない。provider Rate Limit、RAG、database、network、予算を含める。maximum capacityを超えたら受付を制限し、autoscalingを下流保護の代わりにしない。scale eventが実際にqueue waitと利用者latencyを改善したかまで測ることで、費用とSLOを両立できる。