Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Benchmarking Disaggregated Serving on vLLM + Dy...

Benchmarking Disaggregated Serving on vLLM + Dynamo with a Real Coding-Agent Workload

2026年10月9の第4回 vLLM Community Meetup Tokyoで発表した「Benchmarking Disaggregated Serving on vLLM + Dynamo with a Real Coding-Agent Workload」の講演資料です。
講演詳細についてはこちらを御覧ください(https://ossbyredhat.connpass.com/event/406652/)

Avatar for NTT docomo Business

NTT docomo Business

October 13, 2026

More Decks by NTT docomo Business

Other Decks in Technology

Transcript

  1. Benchmarking Disaggregated Serving on vLLM + Dynamo with a Real

    Coding-Agent Workload vLLM Meetup Tokyo #4 · 2026年10月9日 Kota Tsuyuzaki NTT DOCOMO BUSINESS, Inc. © NTT DOCOMO BUSINESS, Inc. All Rights Reserved.
  2. 自己紹介 導入 Kota Tsuyuzaki NTT DOCOMO BUSINESS, Inc. 普段の仕事: AI

    / GPU インフラ · データプラットフォーム · AI agent 開発 関連する以前の発表 Trace-Based Evaluation of Open-Weight Coding Agents Why Agent Cost Needs Observability AGNTCon + MCPCon Japan 2026 Tokenomics Meetup #1 © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 2
  3. 推論基盤で考えたいこと 導入 推論基盤をつくる・運用するときに決めたいこと どんな GPU が要るか GPU は何枚要るか メモリと serving

    の容量は serving 構成はどうするか それを決めるには、まず何を載せるのか(Workload)を理解する必要がある Workload で決まるもの: 計算量 · 保持する KV Cache · 同時に処理できる数 · 安定した運用 · cost この発表では、Coding Agent を題材に考える © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 3
  4. Serving Software Stack 導入 推論 engine に vLLM、distributed serving /

    orchestration に NVIDIA Dynamo を利用 NVIDIA Dynamo 1.5.0 OSS の分散推論 serving framework requests vllm bench serve 負荷をかける client vLLM 0.28.0 に付属 latency・throughput を測る Frontend: request を受け、KV-aware router で送り先の Worker を選ぶ vLLM Worker の並べ方(どちらかで起動) aggregated disaggregated P+D P+D P+D P+D Prefill vLLM vLLM vLLM vLLM vLLM 同じ Worker が Prefill も Decode も 各 Worker = vLLM 0.28.0 © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. github.com/ai-dynamo/dynamo KV Decode Decode Decode vLLM vLLM vLLM Prefill と Decode は別の Worker。KV を転送 OSS の LLM 推論 / serving engine · GPU 1 枚 github.com/vllm-project/vllm 4
  5. Coding Agent のやりとり Coding Agent の再現 Coding Agent は毎 turn、それまでの会話全体に新しい部分を足して送り直す

    最初の request turn 1 応答は text か tool call · tool を実行して結果を返す LLM 応答 turn 2 tool 結果 LLM 応答 tool 結果 turn 3 私の Claude Code: 53 coding Sessions · 6,101 requests · main agent · p50 再送する context ≈ 213K tokens 新しい部分 ≈ 1K tokens (前の応答 + tool 結果) © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 6
  6. Replaying the Workload Coding Agent の再現 vllm bench serve の

    trace データ(--dataset-name timed_trace, --dataset-path)では、 request の内容と送信時刻を定義できる timed_trace 用 JSONL ── benchmark user が作成 {"timestamp": 16, "hash_ids": [1,2,3,4,5], ...} 実際の Coding Agent Workload 送った時刻 最初の request 0s vllm bench serve / timed_trace での再現 timestamp(秒) hash_ids 送れる条件(◦ trace にある / × ない) 0 1 2 3 LLM 応答 ◦ 0 秒になったら 応答のあとで次の request 16 s LLM 応答 16 1 2 3 4 5 ◦ 16 秒になったら × 前の応答が終わったら 共有 prefix 41 1 2 3 4 5 6 7 41 s LLM 応答 新しい input ◦ 41 秒になったら × 前の応答が終わったら LLM 応答 + 新しい input 相当 ただし、前の応答の完了を待たずに送信する © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 7
  7. Coding Agent Workload の再現性検証 Coding Agent の再現 自作の turn-dependent replay

    と比較すると、 通常の timed_trace では必要量に対して再計算*が 200% 以上増加することがわかった vllm bench serve / timed_trace timed_trace + --max-concurrency turn-dependent replay timestamp で送る × turn 依存 同時実行数を制限(実行待ちは TTFT / E2E に含まない) × turn 依存 前 turn 完了後に送る ◦ turn 依存 vllm bench serve のオプションで、Session 数と同等の --max-concurrency を設定すると、 TTFT と Prefill 再計算が turn-dependent replay に近づいた 以降の実験では、この vllm bench serve + --max-concurrency の結果を取り扱う Qwen3.8-27B-FP8 · H100 · Prefill 1 + Decode 3 で計測 * 再計算 = Prefill の計算量の必要量に対する増加分。Prometheus(vllm:prompt_tokens_by_source_total)の、計測期間の差分で集計 参照: vLLM v0.28.0 metrics: https://github.com/vllm-project/vllm/blob /v0.28.0/vllm/v1/metrics/loggers.py#L679-L692 © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 8
  8. LLM の GPU の使い方 KV Cache / Capacity GPU メモリには、モデルの重みと、Session

    ごとに増える KV Cache が載る 1 GPU(H100 80 GB)のメモリ 固定 可変: Session 数 × context の token 数 モデルの重み モデルの大きさと精度で決まる KV Cache pool runtime(CUDA context など + activation のピーク + CUDA graph) gpu_memory_utilization 0.92(既定値)× 79.22 (GPU メモリ) = 72.88 GiB モデルの重み = 24.3B × 1 byte (FP8) + 3.0B × 2 byte (BF16) = 28.3 GiB 未確保(6.34 GiB) (起動 log: 28.88 GiB) runtime = 1.01 (CUDA context など) + 2.10 (activation) + 0.96 (CUDA graph) = 4.07 GiB (起動 log) KV Cache pool = 72.88 (gpu_memory_utilization) − 28.88 (モデルの重み) − 4.07 (runtime) = 39.93 GiB (起動 log) モデルの重みの詳細な計算は Appendix(モデルの重みの計算) 参照: vLLM v0.28.0(KV Cache の確保): © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. https://github.com/vllm-project/vllm/blob/v0.28.0/vllm/v1/worker/gpu_worker.py#L559-L563 10
  9. Workload に合わせた KV Cache の計算 KV Cache / Capacity Coding

    Agent の context を当てはめると、1 GPU に載る Session は約 6 本 1 GPU(H100 80 GB)のメモリ 固定 モデルの重み 可変: Session 数 × context の token 数 1 Session KV Cache pool(Prefill Worker): 約 130 万 tokens 超えると 追い出し → 再計算 ① 1 Session の KV Cache = context の token 数 × 32 KiB(FP8 KV / token)+ SSM state 74.8 MiB ② Coding Agent の context(中央値 213K token)を当てはめる: 213K × 32 KiB + 74.8 MiB ≈ 6.6 GiB ③ KV Cache pool 39.9 GiB ÷ 6.6 GiB ≈ 6 Session KV Cache が溢れて再計算になったときの Dynamo / vLLM の挙動を確認し、 Multi ノードと KV Cache Offload で緩和できるかを試した © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 11
  10. Multi ノードと KV Cache Offload が性能に与える影響 KV Cache / Capacity

    KV Cache Offload なしでは、TTFT p50 が 1 ノード 8 Session で 77 s、 2 ノード 12 Session で 29 s に増加する KV Cache Offload を行うと、1 ノードでも 20 Session まで TTFT p50 は 約 2.5 s 以下 計測条件: H100 × 4 / ノード · 2 ノード · ノード間 100 Gbps · Qwen3.8-27B(FP8 KV Cache · BF16 SSM state) KV Cache Offload: Prefill Worker あたり 256 GiB · 1M context(static YaRN) vllm bench serve --max-concurrency で計測 · TTFT は request の送信から計測 © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 12
  11. Aggregation vs. Disaggregation Serving Performance 同じ GPU 数・同じ host RAM

    で、Worker の構成のみを変更して比較 1 ノード 2 ノード aggregated disaggregated そろえた資源 agg4 P+D × 4 1P3D Prefill 1 + Decode 3 GPU 4 host RAM 計 256 GiB KV Cache Offload: Worker ごとに 64 GiB KV Cache Offload: Prefill Worker に 256 GiB agg8 P+D × 8 2P6D Prefill 2 + Decode 6 KV Cache Offload: Worker ごとに 64 GiB KV Cache Offload: Prefill Worker ごとに 256 GiB GPU 8 host RAM 計 512 GiB KV Cache Offload の host RAM は、GPU 数 × 64 GiB に設定 PD 分離では、host RAM は Prefill を実施する Worker で均等に分割 Multi ノードの PD 分離では、Prefill Worker を 1 ノードに 2 つ配置 計測条件: H100 × 4 / ノード · 2 ノード · ノード間 100 Gbps · Qwen3.8-27B(FP8 KV Cache · BF16 SSM state) 1M context(static YaRN) © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 13
  12. Aggregation vs. Disaggregation — TTFT / E2E Serving Performance TTFT

    p50 は agg と disagg で 0.1〜0.4 s 差。24 Session 以上で disagg は 10 s 以上に増加する E2E p50 は 24 Session 以上で、1 ノードは 60 s 以上、2 ノードは 40 s 以上に増加する 計測条件: H100 × 4 / ノード · 2 ノード · ノード間 100 Gbps · Qwen3.8-27B(FP8 KV Cache · BF16 SSM state) KV Cache Offload: agg は Worker あたり 64 GiB · disagg は Prefill Worker あたり 256 GiB · 1M context(static YaRN) vllm bench serve --max-concurrency で計測 · TTFT / E2E は request の送信から計測 TTFT の差が大きいのは 2 ノード 20 Session のみ(1.9 s) © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 14
  13. Aggregation vs. Disaggregation — ITL Serving Performance ITL p50 の

    agg と disagg の差は、1 ノードで 1.4〜6.8 ms、2 ノードで ±1.5 ms 以内 ITL p99.9 は disagg が 0.08〜0.22 s なのに対し、 agg は 1 ノード 8 Session、2 ノード 12 Session から約 3 s に増加する 計測条件: H100 × 4 / ノード · 2 ノード · ノード間 100 Gbps · Qwen3.8-27B(FP8 KV Cache · BF16 SSM state) KV Cache Offload: agg は Worker あたり 64 GiB · disagg は Prefill Worker あたり 256 GiB · 1M context(static YaRN) vllm bench serve --max-concurrency で計測 · agg は最大 5.1 s · disagg 1 ノード 24 Session のみ 2.9 s © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 15
  14. Aggregation vs. Disaggregation — Prefill Recomputation Internal Behavior 12〜28 Session(max-concurrency)では、agg8

    の Prefill 再計算*は 2P6D の 2.7〜3.7 倍 計測条件: H100 × 4 / ノード · 2 ノード · ノード間 100 Gbps · Qwen3.8-27B(FP8 KV Cache · BF16 SSM state) KV Cache Offload: agg は Worker あたり 64 GiB · disagg は Prefill Worker あたり 256 GiB · 1M context(static YaRN) vllm bench serve --max-concurrency で計測 * 再計算 = Prefill の計算量の必要量に対する増加分。Prometheus(vllm:prompt_tokens_by_source_total)の、計測期間の差分で集計 参照: vLLM v0.28.0 metrics: https://github.com/vllm-project/vllm/blob /v0.28.0/vllm/v1/metrics/loggers.py#L679-L692 © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 16
  15. Dynamo KV-aware Routing Internal Behavior Dynamo の KV Router は、request

    ごとに Worker のコストを計算し、一番低い Worker に送る ④ request を送る Worker A Dynamo KV Router request ② block のハッシュ値で cache との一致 (overlap)を調べる ① KV event: cache block(ハッ シュ値)の追加・削除を随時知らせる ③ コストが一番低い Worker を選ぶ Worker B ① KV event: cache block(ハッ シュ値)の追加・削除を随時知らせる © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 17
  16. Dynamo KV-aware Routing — Cost Calculation Internal Behavior 計算式(Dynamo 1.5.0)

    既存の負荷に関わる変数 この request に関わる変数 cost = prefill_load_scale * max(0, active_prefill_blocks + incoming_prompt_blocks - overlap_credit_blocks) + active_decode_blocks + incoming_active_blocks + decode_active_request_weight * active_requests prefill_load_scale = 1.0、decode_active_request_weight = 0 は既定値。この例は aggregated。PD 分離では、Prefill Worker は Prefill の項、Decode Worker は Decode の項で決まる Worker コスト計算例 Worker A Worker B すでに割り当てられている分(既存の負荷) Prefill の作業 active_prefill_blocks 20 0 Decode の KV block active_decode_blocks 15 8 + この request の prompt incoming_prompt_blocks 100 100 − cache に一致して省ける分 overlap_credit_blocks 70 20 + Decode で増える見込みの block incoming_active_blocks 5 2 cost 70 この request で増える分(増分) = cost(既存 + 増分) 参照: Dynamo 1.5.0 Routing Concepts: ← 選ばれる 90 https://github.com/ai-dynamo/dynamo/blob/v1.5.0/docs/fern/pages/developer-guide/knowledge-base/modular-components /router/routing-concepts.md © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 18
  17. Aggregation vs. Disaggregation — Cache Locality Internal Behavior agg8(Worker 8

    台)は 1 つの Session の Prefill を、平均 4.2〜5.2 か所で計算していた 2P6D(Prefill Worker 2 台)は 1 つの Session の Prefill を、2 か所で計算していた 計測条件: H100 × 4 / ノード · 2 ノード · ノード間 100 Gbps · Qwen3.8-27B(FP8 KV Cache · BF16 SSM state) KV Cache Offload: agg は Worker あたり 64 GiB · disagg は Prefill Worker あたり 256 GiB · 1M context(static YaRN) vllm bench serve --max-concurrency で計測 · Worker 数: Dynamo KV Router のログから集計 · 図は 24 Session の run の 1 Session © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 19
  18. What We Learned まとめ Coding Agent を載せる serving 構成を考えるうえで、3 つの観点が重要だった

    Replay Coding Agent は、短い input / output の繰り返しと、巨大な KV Cache の保持が特徴 turn の依存をどう再現するかで、serving にかかる負荷が変わる Capacity Qwen3.8-27B + H100 80GB で、重みと Workload から GPU メモリを計算し、実機で確認した 計算した Session 数(約 6 / GPU)の付近で、Offload なしでは TTFT が増加した KV Cache Offload を使うと、20 Session まで安定した TTFT でスケールすることが確認できた Placement / Locality KV Cache のない Worker に request が routing されると、Prefill 全体の再計算が入り、性能が悪化する KV Router は overlap と load の両方を考慮して routing するため、再計算は平常時にも起こりうる この挙動の把握には、Prometheus のメトリクスと KV Router のログが重要 Coding Agent 向けの Inference serving では、KV Cache の容量と、再利用できる Worker への配置が、TTFT と Prefill 再計算に影響した © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 20
  19. Appendix — 実験の構成 1 ノードの比較 1P3D 対 agg4(GPU 4、host RAM

    計 256 GiB、どちらも GPU KV + KV Cache Offload) 2 ノードの比較 2P6D 対 agg8(GPU 8、host RAM 計 512 GiB、どちらも GPU KV + KV Cache Offload) KV Cache Offload vLLM 0.28.0 の CPU KV offload(OffloadingConnector)。agg は Worker ごとに 64 GiB、disagg は Prefill Worker ごとに 256 GiB。この環境では 1 回で 2 GiB を超える cudaHostRegister が失敗したため、offload 領域を 1 GiB ずつに分けて pin する vLLM の patch を作成し対応(pin の分割のみで、offload の動作は変えない) KV Cache / Capacity の条件 1P3D、2P6D それぞれ GPU KV のみ / GPU KV + KV Cache Offload Hardware H100 × 4 / ノード、ノード間 RoCE 100 Gbps Model Qwen3.8-27B-FP8(hybrid: attention + SSM)· 1M context (static YaRN) · KV FP8 · SSM state BF16 Runtime vLLM 0.28.0、Dynamo 1.5.0(Frontend · --router-mode kv、その他はデフォルト)· block size 800 · cache pool 1,635 block 負荷 max-concurrency の計測: x = 同時 Session 数(vllm bench serve --max-concurrency)、1 run = N Session × 20 request、 Session は入れ子の集合。turn-dependent replay は自作(前の turn の完了を待って次を送る) 計測の境界 max-concurrency の TTFT・E2E は request の送信から計測。client の concurrency 上限(semaphore)による待ちは含まない 負荷特性の評価。出力品質は対象外 © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 22
  20. Appendix — モデルの重みの計算 1B = 10 億パラメータ。括弧内は model card /

    config.json の該当項目 MLP = 3 × 5,120 (hidden) × 17,408 (intermediate) × 64 (layers) = 17.1B full attention = 5,120 (hidden) × 256 (head dim) × ( 24 (Q heads) × 3 + 4 (KV heads) × 2 ) × 16 (layers) = 1.68B linear attention = 5,120 (hidden) × 128 (head dim) × ( 16 (QK heads) × 2 + 48 (V heads) × 3 ) × 48 (layers) = 5.54B embedding + lm_head = 2 × 248,320 (vocab) × 5,120 (hidden) = 2.54B vision tower ≈ 0.5B(config.json の vision_config からの概算) モデルの重み = ( 17.1B + 1.68B + 5.54B ) × 1 byte (FP8) + ( 2.54B + 0.5B ) × 2 byte (BF16) = 28.3 GiB (起動 log: 28.88 GiB) 参照: Qwen3.8-27B-FP8 model card: config.json: https://huggingface.co/Qwen/Qwen3.8-27B-FP8 https://huggingface.co/Qwen/Qwen3.8-27B-FP8/blob/main/config.json © NTT DOCOMO BUSINESS, Inc. All Rights Reserved. 23