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 isolation | computeの扱い | 主な注意 |
|---|---|---|---|---|
| MPS | 複数CUDA processを並行実行 | client address spaceは分離 | 利用上限を設定可能、専有予約ではない | 同じGPU上で性能と一部障害が波及 |
| MIG | hardware profileへpartition | instance単位で分離 | computeとmemory pathをpartition | 定義済みprofile、geometry変更が必要 |
| time-slicing | processを時間共有 | 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を対応付ける。
負荷試験
- clientを一つずつ増やし、総throughputとp99 latencyを測る
- 長文Prefillと短いDecodeを同居させる
- active thread percentageを変え、専有予約ではないことを確認する
- memory limit直前と超過時の挙動を確認する
- 一つのclientを終了し、ほかのclientが継続するか確認する
- fatal faultを安全な検証環境で模擬し、影響範囲とserver復帰を確認する
- MPS serverが
FAULT中の新規接続失敗を処理できるか確認する - deployment drainと強制終了の差を確認する
- MPS、MIG、単一engineのContinuous Batchingを同じSLOで比較する
- 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、障害範囲で決める。