Tech カテゴリのイメージ

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を完了させてから終了する。

必要な処理は次である。

  1. load balancerから新規trafficを外す
  2. running requestとstreamを追跡する
  3. grace period内で完了を待つ
  4. deadlineを超えるrequestを安全にcancelまたは再queueする
  5. checkpointや冪等性情報を保存する
  6. 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へ到達した」で終わらせない。

負荷試験で確かめる

  1. 短文requestを急増させ、scale upがSLO違反前に間に合うか確認する
  2. QPSを変えず長文へ切り替え、token metricが混雑を検知するか確認する
  3. model loadを意図的に遅らせ、起動中replicaをcapacityとして誤算しないか確認する
  4. hot keyまたは一つのordering keyへ集中させ、平均metricが偏りを隠さないか確認する
  5. maximum replicaへ到達させ、load sheddingと優先度制御が働くか確認する
  6. scale down中に長いstreamを流し、drainしてから終了するか確認する
  7. autoscaling metricを欠落させ、誤ったdownscaleをしないか確認する
  8. 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を両立できる。

参考資料