7月20日、Graziano Casto(Akamas)が「Why goodput matters more than throughput for LLM serving」と題した記事を公開した。この記事では、LLMサービングにおいてスループットよりも「goodput」を最適化指標にすべき理由と、その実測データについて詳しく紹介されている。
「スループットを上げたのにサービスが悪化した」問題の正体
LLMの推論サーバーをチューニングするとき、多くのエンジニアがまず手を伸ばす指標はスループット(requests per second)だ。測定が簡単で、コストあたりのリクエスト数という形でビジネス側にも説明しやすい。
だが、この指標だけを追いかけると落とし穴にはまる。Castoはvを単一GPUでチューニングする中でその落とし穴を実際に踏んだと述べている。スループットを上げていくと、ある地点でレイテンシが静かに悪化し始める。リクエストは「完了」するが、ユーザー体験は劣化している。
この問題を捉えるのがgoodputという指標だ。定義はシンプルで、「レイテンシのSLOを満たしながら完了したリクエストの毎秒数」である。LLMサービングの文脈では、SLOの対象は通常2つになる:
- TTFT(Time To First Token):最初のトークンが返るまでの待ち時間
- TPOT(Time Per Output Token):その後のトークンが1個ずつ生成されるペース
SLOを外れたリクエストはスループットには計上されるが、goodputには含まれない。レストランの厨房に例えるなら、スループットは「1時間に出した皿の数」、goodputは「温かいうちに正しいテーブルに届いた皿の数」だ。
なお、goodputという概念自体はLLMサービング以前から存在するが、LLM推論の文脈ではOrcaやSarathi-Serveといった先行研究がバッチスケジューリングとレイテンシ制約の両立を論じる中で注目を集めるようになった。単純なスループット最大化では捉えられない「SLOを満たした有効処理量」をどう測るかという問いに対する実践的な答えが、goodputという指標に集約されている。
実測:設定2つで50%の差、p95 TPOTは10倍の差
環境は以下の通りだ:
- モデル:Qwen2.5-7B(vLLMで提供)
- GPU:NVIDIA A10G(24GB)、EKSクラスター上
- 負荷ツール:GuideLLM
- 監視:Prometheus + Grafana + NVIDIA DCGM exporter
- 再現用コード:github.com/graz-dev/vllm-benchmark
調整したvLLMのパラメーターは3つのみ——gpu_memory_utilization、max_num_batched_tokens(バッチあたりのトークン上限)、max_num_seqs(同時処理シーケンス数の上限)——だ。これらはモデルやハードウェアを変えずにオペレーターが安全に変更できる設定で、KVキャッシュのメモリ量・バッチのサイズ・同時並走数を支配する。
チャットボットワークロード(プロンプト約485トークン、出力約121トークン)での実験結果が特に鮮明だった。制約として「平均TTFTを1.5秒以下に保ちながら、プリフィルとデコードの合計トークンスループットを最大化する」という目標を設定した。
| 設定 | gpu_memory_utilization | max_num_batched_tokens | max_num_seqs | TTFT平均 | プリフィルtput | デコードtput |
|---|---|---|---|---|---|---|
| Exp 1 | 0.89 | 4160 | 212 | 1395 ms | 1925 tok/s | 478 tok/s |
| Exp 20 | 0.87 | 2150 | 271 | 1403 ms | 2934 tok/s | 690 tok/s |
2つの設定はどちらも平均TTFTが約1.4秒でほぼ同じだ。TTFTという制約条件を揃えた状態で比較すると、合計トークンスループット(プリフィル+デコード)はExp 20がExp 1を約50%上回る。この差はgoodputの観点でも有効な改善であり、単に生スループット数値を比べているわけではない。
問題はその裏側にある。Exp 1のp95 TPOTは約50ミリ秒。Exp 20のp95 TPOTは約494ミリ秒と、約10倍の開きがある。TTFTだけを制約として与えたため、パラメーター探索がTPOTを犠牲にして帯域を使い切った。チャットのストリームを画面で読んでいるユーザーにとって、トークン間の0.5秒の間隔は明確に「止まって見える」体験になる。



なぜTTFTとTPOTが逆方向に動くのか
この現象はvLLMの処理構造から来ている。リクエストの処理は2段階に分かれる。
- プリフィルステージ:モデルがプロンプトを読む段階。TTFTはここで決まる。
- デコードステージ:vLLMがアクティブな全リクエストに対して同時に1トークンずつ生成するループ。
同時処理するリクエストが増えると、デコードの1ステップあたりの仕事量が増え、1ステップの実行時間が延びる。全リクエストが次のトークンを受け取るまでの待ち時間が長くなる。「TTFTを制約する」ことで着席と最初の一皿を速くしても、その後の料理が各テーブルに届くペースが落ちる——という構造だ。
ワークロード別の傾向と3つの教訓
記事ではチャットボット以外に、リーズニングワークロード(プロンプト約400トークン、出力約4000トークン)とエージェンティックワークロード(約512/128トークン、複数の連続呼び出し)でも検証している。
エージェンティックの実験では、requests per secondがほぼ同じ2設定(6.20対6.11)でp95 TPOTが682ミリ秒対902ミリ秒と約220ミリ秒の差が出た。スループットが同じでも、連鎖する個々の呼び出しの中でストリームの体感は異なる。リーズニングでは、生のスループット最大設定が、レイテンシ制約を加えると最適解から外れた。
Castoはここから3つの教訓を導いている。
第一に、SLOのないスループット数値はマーケティングであってエンジニアリングではない。 正直な指標はgoodputだ。
第二に、goodputが最大になる設定は直感では選べない。 パラメーター空間には小さな崖が多く、最初に「良さそうな数字」に見えた設定が最良とは限らない。実際の目標に対して多くの設定を試す自動探索が必要だ。
第三に、最適解は固定ではない。 トラフィック、プロンプト、モデルが変われば最適設定も変わるため、探索を継続的に実施する必要がある。
さらにCastoは、今回はvLLMの3パラメーターしか変えていないにもかかわらずこれだけの差が出たと指摘する。GPU設定、ランタイム、スケジューリングを含むスタック全体を同時に調整すれば、さらに大きな差が生まれる可能性がある。
実務上の手順はシンプルだ。まずTTFTとTPOTの目標値を決め、それを満たしながらスループットを最大化する設定を探す。スループット単体の数字より小さくなることはあっても、ユーザーが体感するサービス品質は上がる。検証環境はgithub.com/graz-dev/vllm-benchmarkで公開されており、自分のモデルとトラフィックで同様の探索を実行できる。
詳細はWhy goodput matters more than throughput for LLM servingを参照していただきたい。