Tech カテゴリのイメージ

CUDA MPSとは?複数のLLM推論processでGPUを共有する仕組み

一枚のGPUへ小さなmodel serverを二つ載せたのに、片方が忙しくなるともう片方のlatencyまで不安定になることがある。複数processが別々のCUDA contextを持ち、GPUを交互に使うだけでは、小さなkernelや断続的な処理の隙間を十分に埋められない場合がある。

CUDA Multi-Process Service、MPSは、複数CUDA processからの仕事を同じGPU上で同時に進めやすくする仕組みである。もともとMPI workloadでGPUを共有するために使われてきたが、独立した小型推論processを一枚へ集約する場面でも検討対象になる。

ただし、MPSはGPUを安全な小型GPUへ分割するMIGとは違う。computeの利用上限は設定できても専有を保証せず、memoryやfatal faultの影響も設計しなければならない。

MPSが解決する空き時間

一つのCUDA processが常にGPU全体を使い切るとは限らない。小さなbatch、短いkernel、CPU前処理待ち、network待ちがあれば、SMやmemory bandwidthに空きが生じる。

MPSは複数clientのCUDA workloadをMPS serverを介して同じGPUへ送り、kernelを並行実行しやすくする。NVIDIAの資料では、Volta世代以降のMPS clientは多くのresourceを各contextで管理し、hardwareへ直接仕事をsubmitする。MPS serverは、同時schedulingに必要な共有resourceを調停する。

効果が出やすいのは、一つのprocessだけではGPUを埋めにくく、複数processの仕事を重ねられる場合である。すでに大きなcontinuous batchでGPUを飽和させるLLM serverへMPSを足しても、余っていないcomputeやmemory bandwidthは増えない。

LLM推論で候補になる場面

  • 小型modelを別process、別endpointで動かす
  • embedding、reranker、guardrailを同じGPUへ載せる
  • tenantごとにprocessを分けたまま空きcomputeを共有する
  • batchを大きくできない低latency requestを集約する
  • MPIやmulti-process構成で各rankのGPU利用が疎である

一方、大modelのPrefillがGPUを長時間占有する構成や、memory bandwidthがすでに飽和している構成では、別clientが待たされやすい。平均throughputが増えてもp99 TTFTやITLが悪化する可能性がある。

独立processとMPS client

MPSを有効にしても、application codeから見えるCUDA APIは基本的に変わらない。client processは自身のCUDA contextを持ち、driverがMPSへ接続する。

Volta以降ではclientごとにGPU address spaceが分かれる。ただし、同じphysical GPUのSM、cache、memory bandwidth、power、coolingを共有する。address spaceが分離されていることと、性能や障害が完全に独立していることは別である。

運用ではMPS control daemon、MPS server、client processの三つを区別する。model serverだけを監視していても、MPS serverがFAULT状態なら新しいclientは接続できない。

active thread percentageは予約ではない

MPSはCUDA_MPS_ACTIVE_THREAD_PERCENTAGEなどで、client contextが使えるthread resourceの割合を制限できる。重いclientがGPU全体へ広がるのを抑え、ほかのclientが進む余地を作るために使える。

ただし、NVIDIAの公式資料が明記する通り、この設定はclient専用のresourceを予約しない。異なるclientのkernelが同じSMで動く場合もある。50%を二つ設定したから、二つのclientが常にGPU性能の半分ずつを得るわけではない。

割合はhardwareが対応するthread数へ丸められる。client数だけで均等割りせず、実際のkernel特性とlatencyで調整する。

memory limitはcapacity planningに使える

MPSではclientが確保できるdevice memoryへ上限を設定できる。上限を超えるallocationはOOMになるため、一つのclientがmemoryを使い切る事故を抑え、schedulerが配置判断に使える。

memory limitにはCUDA内部allocationも含まれる。model weightのfile sizeだけを上限にせず、KV Cache、workspace、CUDA graph、communication buffer、fragmentationの余白を見積もる。

一方、memory上限を設けてもmemory bandwidthの専有量は保証されない。二つのclientが同時に帯域を使えばlatencyは干渉する。memory容量とmemory性能を別に測る。

MPS、MIG、time-slicingの違い

方式主な分け方memory isolationcomputeの扱い主な注意
MPS複数CUDA processを並行実行client address spaceは分離利用上限を設定可能、専有予約ではない同じGPU上で性能と一部障害が波及
MIGhardware profileへpartitioninstance単位で分離computeとmemory pathをpartition定義済みprofile、geometry変更が必要
time-slicingprocessを時間共有MIG相当の分離なし同じGPUを順番に利用resource数とcompute量が比例しない

MIGは分離境界を作り、MPSは複数processの同時実行効率を上げる。目的が違うため、MIG instanceの内部でMPSを使う構成もありうる。その場合は、MIG profileの上限内でMPS clientがさらにresourceを共有する。

一つの推論engine内のbatchingとは違う

Continuous Batchingは、一つのmodel serverが複数requestをtoken iteration単位でまとめる。model weightとKV Cache管理を共有しやすく、LLM servingではまず検討すべき方法である。

MPSは複数processの境界を残したままGPU実行を重ねる。同じmodelを複数processで動かすとweightもprocessごとに保持し、memory効率が悪くなる場合がある。

同じmodel、同じversion、同じ信頼境界なら、一つのengineへrequestを集約する方が単純なことが多い。MPSはprocessを分ける理由があり、各processだけではGPUを使い切れないときに価値が出る。

fatal faultの影響範囲

Volta以降のMPSは限定的なerror containmentを持つ。あるclientがfatal GPU faultを起こすと、そのGPUを共有するclientへfaultが通知される。MPS serverはFAULT状態になり、影響を受けたclientが終了するまで新しい接続を拒否する。

つまり、address spaceが分かれていても、一つのclientのfatal faultが同じGPU上の別serviceへ波及しうる。複数GPUをまたぐclientがある場合は、共有関係によって影響範囲が広がる。

NVIDIA資料では、影響を受けたclientが終了した後にserverがGPU contextを再作成し、ACTIVEへ戻る。application側はfatal errorを受けたら終了する責任がある。無限retryで同じprocessを居残らせない。

pre-VoltaのMPSはerror containmentがさらに弱く、fatal faultでMPS serverと全clientが停止しうる。hardware世代を確認せず、現行資料の挙動を古いGPUへ当てはめない。

強制終了にも注意する

NVIDIAは、outstanding GPU workと同期しないままMPS clientをsignalやsegmentation faultで終了すると、MPS serverやほかのclientがundefined stateになり、hangやunexpected failureを起こす可能性を説明している。

deployment更新では新規requestを止め、生成中requestをdrainし、CUDA workの完了後にprocessを終了する。強制killは最後の手段とし、実行後はMPS server状態と同居clientを確認する。

利用者境界をまたがない

通常のMPS serverは同じUIDのclientを扱う。multiuser server modeでは複数Linux userが一つのroot MPS serverへ接続できるが、NVIDIAはuser間のisolationを無視できることを確認してから使うよう注意している。

外部tenantや信頼度の違うcodeを同じMPS serverへ載せる設計には向かない。tenant isolationが要件なら、MIG、別GPU、別nodeなど、より強い境界を優先する。

connection数とcontext数にも上限がある

MPS serverが一つのdeviceで扱えるclient CUDA context数には上限があり、設定やhardwareで変わる。client processが複数contextを作れば、その分だけ枠を消費する。

NVIDIAは、processごとにprimary device contextを一つ使うことを推奨している。model serverのworker数を増やしたのに起動時のcontext作成が失敗する場合は、GPU memoryだけでなくMPS connection limitとCUDA_DEVICE_MAX_CONNECTIONSを確認する。

運用で見るmetric

  • MPS serverのINITIALIZING、ACTIVE、FAULT状態
  • client PID、UID、接続・切断時刻
  • client別のGPU memoryと上限超過OOM
  • active thread percentageと実際のSM利用率
  • client別のTTFT、ITL、throughput、error率
  • 同居client数とp50・p99 latencyの関係
  • GPU全体のmemory bandwidth、power、temperature、clock
  • CUDA error、Xid、MPS server log
  • forced termination後のhangと復旧時間
  • MPSあり・なしのGPU当たりtoken throughput

GPU全体の利用率だけでは、どのclientがほかを遅らせたか分からない。client PID、container、model、endpointを対応付ける。

負荷試験

  1. clientを一つずつ増やし、総throughputとp99 latencyを測る
  2. 長文Prefillと短いDecodeを同居させる
  3. active thread percentageを変え、専有予約ではないことを確認する
  4. memory limit直前と超過時の挙動を確認する
  5. 一つのclientを終了し、ほかのclientが継続するか確認する
  6. fatal faultを安全な検証環境で模擬し、影響範囲とserver復帰を確認する
  7. MPS serverがFAULT中の新規接続失敗を処理できるか確認する
  8. deployment drainと強制終了の差を確認する
  9. MPS、MIG、単一engineのContinuous Batchingを同じSLOで比較する
  10. GPU世代、driver、CUDA更新後に回帰試験する

processを分ける理由があるときに使う

CUDA MPSは、複数CUDA processのkernelを同じGPUで並行実行し、各processだけでは使い切れないresourceを活かす仕組みである。LLM推論では、小型modelや周辺serviceをprocess境界のまま集約する場面で役立つ。

一方、active thread percentageは専有resourceの予約ではなく、memory limitもbandwidthを分離しない。fatal faultや乱暴なclient終了は同じGPU上のserviceへ波及しうる。

同じmodelのrequestをまとめられるなら、まず一つのengineでContinuous Batchingを検討する。process分離が必要ならMPS、hardware levelのmemoryとfault isolationが必要ならMIGや別GPUを選び、実際のTTFT、ITL、throughput、障害範囲で決める。

参考資料