ステータス: ドラフト (2026-10-07)、実測記事です。 すべての数値は筆者が下記の環境で直接測定した値であり、計算によるものは「計算」、測定できなかったものは「未測定」と表記しました。ひとつの環境、ひとつのモデル、ひとたびのテストの束であるため、絶対値よりも 傾向と原理を持ち帰っていただければ幸いです。 作成ルール: 実測データを基本とし、測定できなかったものは「未測定」と表記します。
目次
- 1. 何を知りたかったのか
- 2. 環境と方法
- 3. KV キャッシュ容量は計算式と一致する
- 4. 同時リクエストを増やすと: スループットは鈍化し、KV 容量の限界でキューが爆発する
- 5. KV 8ビット: 容量が増えると長い入力の遅延が減る
- 6. プレフィックスキャッシュ: 共通のプレフィックスがあると最初のトークンが 14倍速くなる
- 7. チャンクドプリフィル: 長い入力がデコーディングを停止させる時間はチャンクサイズが決める
- 8. CUDA グラフをオフにした場合(--enforce-eager)
- 9. サーバーの初回起動にかかる時間
- 10. 運用において持ち帰るべき知見
- 11. 面接で出そうな質問
- 外部の根拠: 論文と公式資料で確認した内容
- 確認できなかったこと
- 確認したバージョンと日付
1. 何を知りたかったのか
vLLM のドキュメントにはオプションが多く、面接や運用では「このオプションを有効にすると何がどれほど変わるのか」が問われます。第 4 篇では原理(KV キャッシュの計算式、プレフィックスキャッシュ、スケジューラー)をドキュメントベースで整理し、この記事では同じ質問に数値で答えます。
- 同時リクエストが増えると、スループットとレイテンシはどこで低下するのか。
- KV キャッシュ容量は計算式による値と一致するか、そしてその容量が低下する地点とどうつながっているか。
- プレフィックスキャッシュ、KV 8ビット、CUDA グラフ、チャンクサイズ、最大同時シーケンス数はそれぞれ何を変化させるか。
2. 環境と方法
| 項目 | 値 |
|---|---|
| GPU | 8GB 級ノートPC 用 GPU 1枚(メモリ約 7.6GiB)、他の作業なし |
| サーバー | vLLM 0.31.0 公式イメージ、PyTorch 2.13(CUDA 13) |
| モデル | Qwen3-1.7B(bf16、サーバーがロードした重み 3.22GiB)、モデル設定は 28層、KV ヘッド 8、head_dim 128 |
| 共通オプション | --max-model-len 4096, --gpu-memory-utilization 0.85, --max-num-seqs 64(比較テストのみ 16) |
| クライアント | サーバーと同じコンテナ内の非同期クライアント、ストリーミングでトークンごとにタイムスタンプを記録し、TTFT(Time to First Token)と ITL(Inter-Token Latency)を計算 |
| 入力 | リクエストごとに異なるランダムな単語列(プレフィックスキャッシュが偶然ヒットしないように)、出力 128 トークン(ignore_eos)、温度 0 |
| 繰り返し | 同時実行数 c に対して 3c 個のリクエスト(長い入力のテストは 2c 個)、最初の 2つのリクエストはウォームアップとして除外 |
サーバーはテストごとに新しく起動しました(KV キャッシュ容量が初回の起動と再起動で異なるため、セクション 3 参照)。表の値は 1回のテストの束から読み取ったものであり、繰り返しの変動は別途測定しました。 同じサーバーで同じテストを 5回繰り返した場合(同時実行数 32、入力 512、出力 128)、スループットは 831、833、831、832、831 tok/s、TTFT の中央値は 666〜670ms、TTFT の p95 は 1,606〜1,608ms、ITL の p99 は 223〜224ms であり、 0.5% 以内でした。サーバーを 3回再起動しても、同時実行数 1 は 66 tok/s、同時実行数 32 は 831〜832 tok/s と同じでした。プレフィックスキャッシュ(3回)や割り込み(3回、最大 ITL 227、226、226ms)も同様でした。この環境(GPU 1枚、他の作業なし)ではテスト自体の変動は小さいという意味であり、異なるハードウェアや別の隣接プロセスがある環境に移行すると変化する可能性があります。
3. KV キャッシュ容量は計算式と一致する
トークンあたりの KV サイズは 2 × 층 수 × KV 헤드 수 × head_dim × 자료형 바이트です。このモデルは 28層、KV ヘッド 8個、head_dim 128 であり、KV を bf16(2バイト)として保持するため、以下のようになります(計算)。
2 × 28 × 8 × 128 × 2 = 114,688 바이트/토큰 (112KiB)
| 設定 | サーバーログの KV キャッシュメモリ | サーバーログのトークン数 | トークンあたりのバイト数(計算) | 計算式の値 |
|---|---|---|---|---|
| bf16 KV(デフォルト) | 2.36GiB | 22,048 | 約 114,900 | 114,688 |
fp8 KV(--kv-cache-dtype fp8) |
2.24GiB | 41,920 | 約 57,400 | 57,344 |
- 計算式がログと一致します。 ログの容量 トークン数で割った値が計算式と 0.2〜0.3% 以内で一致しました。KV キャッシュ容量は「残りメモリ ÷ トークンあたりのバイト数」であるため、どのようなモデルであっても設定から読み取った数値を用いて、サーバーを起動する前に見積もることができます。
- KV 8ビットは、同じメモリに 1.9倍のトークンを格納します。 22,048 から 41,920 トークンへと増加し、トークンあたりのバイト数が正確に半分になりました。
- 容量は初回起動と再起動で異なっていた。 同じオプションであるにもかかわらず、Pod で最初に起動したサーバーは 22,048 トークンであり、同じ Pod で再度起動した 3つのサーバーはいずれも 26,560 トークン(約 20% 多い)でした。初回起動時はコンパイルとプロファイリングに使用されたメモリが KV キャッシュの割り当てから差し引かれているように見えますが(推測であり、直接分解してはいません)、容量を比較する際はメモリではなく トークンあたりのバイト数で比較し、サーバーの起動履歴を併記する必要があります。この記事の表はすべて初回起動サーバー(22,048 トークン)から読み取った値です。
- 1つのリクエストが消費するトークン数は、入力と出力の合計です。入力 512、出力 128 であれば 640 トークンとなり、22,048 トークンのキャッシュは約 34個のリクエストを同時に保持します(計算)。後述の低下する地点はこの数値から導かれます。
4. 同時リクエストを増やすと: スループットは鈍化し、KV 容量の限界でキューが爆発する
入力 512、出力 128、 --max-num-seqs 64:
| 同時リクエスト | スループット (tok/s) | TTFT 中央値 | TTFT p95 | ITL 中央値 | ITL p99 |
|---|---|---|---|---|---|
| 1 | 66 | 73ms | 73ms | 15ms | 16ms |
| 8 | 383 | 351ms | 474ms | 17ms | 19ms |
| 32 | 831 | 666ms | 1.6s | 24ms | 223ms |
| 64 | 787 | 5.7s | 6.7s | 25ms | 228ms |
- 同時実行数 8までは比例に近い形で増加し(1から 8へ 5.8倍、効率 73%)、その後は鈍化しました(8から 32へは同時実行数が 4倍になったのに対しスループットは 2.17倍、383 から 831)。1から 32全体では 12.6倍(効率 39%)です。重みを読み込むコストを分散させる効果(第 4篇、第 21篇)は短いコンテキストにおいて同時実行数 16まで 14〜15倍とほぼ線形であったため、この表で鈍化しているのは入力 512 が蓄積されたことによる KV の読み込みと入力処理の増加が原因である可能性が高いです(推測であり、分解してはいません)。外部の研究においても、大きなバッチサイズではアテンションのメモリ読み込みが原因で、KV 容量の限界に達するはるか前にスループットが頭打ちになることが報告されています(後述の「外部の根拠」を参照)。
- 32 から 64 へはスループットがむしろ低下し、TTFT は 8.6倍(666ms から 5.7s)に跳ね上がりました(この行の値は KV が 22,048 トークンであった初回起動サーバーのものであり、サーバーを再起動して測定した繰り返しの値はこのリストの末尾にあります)。 1つのリクエストが 640 トークンを占有する場合、KV キャッシュは約 34個のリクエストまでしか保持できないため、64個を送信すると半数近くが空き容量ができるまでキューで待機することになります。 容量(KV)が限界に達した瞬間、TTFT が爆発します。 スループットはすでに飽和しているため、同時実行数をこれ以上増やしてもレイテンシが増加するだけです。
- 同じ負荷を 3つのサーバーで繰り返しテストしたところ、同時実行数 64 におけるこの値はサーバーごとに異なっていました。 スループットは 792、842、843 tok/s、TTFT 中央値は 5.7秒、2.1秒、2.2秒でした。最初に起動したサーバーのみが遅く、そのサーバーのみ KV が 22,048 トークンでした(再起動したサーバーは 26,560 トークン)。同じオプションであるにもかかわらず、KV の空き領域はサーバーを起動するたびに 22,048、22,336、26,560、27,504 トークンと異なっており(オプションが異なる 6つのサーバー間の範囲)、同時実行数 64 のリクエストが 640 トークンずつキャッシュをほぼ満杯にするこの限界点においては、容量が 20% 増加したことで TTFT が 2.7倍短縮されました。上記の「キューの爆発」はこの限界付近における現象を意味しており、限界がどこにあるかはサーバーを起動するたびに変動する可能性があります。同時実行数 8 および 32 の値は 3つのサーバーすべてで 1% 以内の一致を示しました(TTFT 349、669ms、スループット 384、831 tok/s)。
- KV の領域がサーバーの起動ごとに変動するという現象は、より大きなモデルにおいてさらに顕著に現れました。 Qwen3-4B-FP8 では、同じオプションで起動したサーバーの KV 容量が 8,880、13,232、14,448 トークンであり(LoRA を有効にしたサーバーは 6,320、10,896 トークン)、同時実行数 32 の TTFT 中央値は KV 容量 8,880 トークンの場合は 7.2秒、13,232 トークンの場合は 3.4秒でした。最初に起動したサーバーが最も小さかった点は 1.7B と同様です。サーバーログの
GPU KV cache sizeをテストの記録に一緒に残さなければ、値を正しく解釈することはできません。 - ITL 中央値は 15ms から 25ms へと緩やかに増加し、p99 は同時実行数 32 から約 220ms へと跳ね上がりました。 新しいリクエストの入力を処理するステップがデコーディングの合間に割り込むことで、特定のトークンの処理が大幅に遅延するためです(セクション 7)。
入力を 2,048 トークンに増やすと、1つのリクエストが 2,176 トークンとなるため、キャッシュが保持できるリクエスト数は約 10個になります(計算)。
| 同時リクエスト | スループット (tok/s) | TTFT 中央値 | TTFT p95 |
|---|---|---|---|
| 4 | 151 | 0.73s | 1.0s |
| 16 | 207 | 4.0s | 6.7s |
| 32 | 213 | 12.5s | 16.7s |
同時実行数を 4個から 16個へと 4倍に増やしたにもかかわらず、スループットは 37% しか増加せず、TTFT は 5.4倍になりました。長い入力においては、 スループットが低下し始める同時実行数が大幅に低くなります。 運用において同時実行数の上限を「GPU が耐えられる限界まで」ではなく、「平均入力長に対して KV が保持できるリクエスト数」に基づいて設定すべき理由がここにあります。
KV が不足する場合: 待機するだけか、それともプリエムプティブ(強制排除)されるか
サーバーのメトリクス(vllm:num_preemptions_total)からプリエムプティブ(優先度による強制排除)の発生回数を読み取りました。入力 512、同時実行数 32 のテストを 5回繰り返した間(KV が保持するリクエスト数が約 34個以内)、プリエムプティブの発生は 0件でした。入力 2,048、同時実行数 32(リクエスト 64個)を送信すると 7件となり、続いて入力 1,500、出力 256、同時実行数 64(リクエスト 128個)を送信すると累計 29件(この負荷では 22件)となりました。このときの TTFT 中央値はそれぞれ 12.5秒、35.4秒でした。KV が不足すると、リクエストがキューで待機するにとどまらず、 実行中だったリクエストが KV キャッシュを手放して強制排除され、最初から再度処理されることになります(プリエムプティブ処理は一時中断したリクエストを再計算するため、入力処理がもう一度発生します。ドキュメント準拠)。プリエムプティブの発生回数が 0ではない区間は、スループットが増加せずレイテンシが急増する区間であるため、アラートの指標として活用する価値があります。
最大同時シーケンス数(--max-num-seqs)はキューの位置を変えるだけである
同時実行数 64、入力 512:
| 設定 | スループット | TTFT 中央値 |
|---|---|---|
--max-num-seqs 64 |
787 tok/s | 5.7s(初回起動サーバー、上記の繰り返しテストにおける値は 842 tok/s、2.1〜2.2s) |
--max-num-seqs 16 |
608 tok/s | 10.3s |
上限を16に下げたところ、スループットが23%低下し、TTFTが1.8倍になりました。上限が容量(約34個)より低いと、容量が余っているにもかかわらず待ち行列が発生するため損であり、容量より高くてもKVが不足していれば利得はありません。 上限はKV容量が収容するリクエスト数付近に合わせる値です。
5. KV 8ビット:容量が増えると長い入力の遅延が減る
| テスト | bf16 KV | fp8 KV |
|---|---|---|
| 同時1、入力512(スループット、ITL) | 66 tok/s, 15ms | 66 tok/s, 15ms |
| 同時16、入力2048(スループット) | 207 tok/s | 303 tok/s (+46%) |
| 同時16、入力2048(TTFT中央値) | 4.0s | 0.94s (−76%) |
| 同時32、入力2048(スループット) | 213 tok/s | 299 tok/s (+40%) |
| 同時32、入力2048(TTFT中央値) | 12.5s | 7.0s (−44%) |
- 短いコンテキストでは速度が同じです。 同時1ではKV読み込みが重みの読み込みに比べて小さいため、8ビットの利得がありません。
- 利得は容量から生まれます。 第3節の1.9倍の容量のおかげで、長い入力において待ち行列が減り、TTFTが大きく縮小しました。つまり、KV 8ビットとは「より速く計算する」のではなく、「より多く同時に収容する」ということです。
- 精度はパープレキシティでのみ測定し、結果は直感と反対でした。 ウィキテキスト-2(テスト分割、約30万トークンのうち先頭の1,024トークン区間40個)をサーバーに送信し、プロンプトトークンの対数確率でパープレキシティを求めました(低いほど良い)。同じ設定を2回測定すると値が小数第4位まで一致し(決定的)、誤差を別途設けていません。
| KV精度 | アテンションバックエンド | パープレキシティ | bf16比 |
|---|---|---|---|
| bf16 | 自動選択 (FLASH_ATTN) | 17.7775 | 基準 |
| bf16 | FLASH_ATTN(固定、2回繰り返し) | 17.7796, 17.7796 | +0.01% |
| bf16 | FLASHINFER | 17.7750 | -0.01% |
| bf16 | TRITON_ATTN | 17.7732 | -0.02% |
| fp8 | FLASHINFER | 17.4228 | -2.0% |
| fp8 | TRITON_ATTN | 17.0340 | -4.2% |
- bf16はバックエンドが異なっても同じでした(17.773〜17.780、0.04%以内)。そのため、バックエンドの違いは測定誤差の範囲内です。
- fp8 KVがかえってパープレキシティを低下させ、2つのバックエンドの値も互いに異なっていました(17.42対17.03)。量子化は通常誤差を増加させるため、低下する理由はありません。この結果を「fp8 KVが品質を向上させる」と解釈してはなりません。同じ8ビット形式であるにもかかわらずバックエンドごとに結果が2%p分かれたのは、形式よりも カーネルの数値処理(スケールの適用、累積精度)がより大きく作用している手がかりであり、原因の分解は行っていません。サーバーログは、スケール補正なしでfp8を使用すると精度が低下する可能性があると警告しています。
- まとめると このモデルとこのテキストにおいて、fp8 KVでパープレキシティが悪化するという証拠は得られなかったものの、傾向が説明できないため品質が維持されるという証拠としても使えません。文献(外部の根拠表)によると、補正していないfp8では推論タスクの精度がモデルに応じて最大1〜2ポイント低下すると報告されているため、導入前に自社タスクの評価セットで確認する必要があります(タスク精度は未測定)。
- 最初のテスト(bf16 4.217対fp8 4.015)は異なるテキストを読み込んだ値であるため無効であり、同じテキストに修正しても傾向が同じだった(4.2173対4.0148)ため、上記のようにバックエンドを固定して再確認しました。
6. プレフィックスキャッシュ:共通のプレフィックスがあると最初のトークンが14倍速くなる
3,000トークンの共通プレフィックスに、リクエストごとに異なる32トークンのテールを付与して1つずつ順番に送信しました(出力1トークン)。
| 設定 | 初回リクエストTTFT | 以降のリクエストTTFT中央値 | プレフィックスが全くない3,032トークン |
|---|---|---|---|
| プレフィックスキャッシュ有効(デフォルト) | 394ms | 28ms | 395ms |
--no-enable-prefix-caching |
395ms | 393ms | 393ms |
- キャッシュがヒットすると、3,000トークンの入力処理をスキップします。 394msが28msに短縮されました(14倍)。システムプロンプトやドキュメントを先頭に固定するサービス(RAG、エージェント)において最もコストパフォーマンスの高い最適化です。
- 有効にしたことのオーバーヘッドは今回のテストでは確認されませんでした。 プレフィックスのない入力のTTFTが、有効時395ms、無効時393msで同じでした。プレフィックスがまったく重複しない入力中心の負荷におけるオーバーヘッドも測定しました。同時32、入力2,048トークン、出力16トークンのリクエスト96個を5回送信した際のスループットは、有効時58、無効時59 tok/s(全体時間26.3〜26.4秒対26.0〜26.1秒、約1.2%の差)であり、TTFTの中央値は有効時6.5〜6.6秒、無効時6.0〜6.2秒(約8%長かった)でした。ヒットは0件であり、クエリされたトークンは約105万でした。つまり 有効にするオーバーヘッドは、入力中心の負荷において1%強のスループットと1桁パーセントのTTFT でした(TTFTの8%は、待ち行列の前方のリクエストがハッシュ計算を余分に行う効果と推測されますが、分解はしていません)。
- 測定時に最も注意すべき罠です。 本記事の執筆中に同じ文を繰り返して入力処理速度を測定したところ、GPUが出力しえない演算量が発生し、プレフィックスキャッシュのヒットが原因でした(第21編)。 パフォーマンス測定の入力は、リクエストごとに異ならせる必要があります。 逆にキャッシュの効果を確認するには、共通のプレフィックスを意図的に作成する必要があります。
7. チャンクプリフィル:長い入力がデコーディングを一時停止する時間はチャンクサイズで決まる
デコーディング中のリクエスト1つ(300トークン)が実行されている間に、3,500トークンの入力リクエスト3つを割り込ませ、割り込ませた区間のトークン間隔を測定しました。
--max-num-batched-tokens |
割り込み区間ITL最大値 | 割り込み区間ITL中央値 | 長い入力自体のTTFT |
|---|---|---|---|
| 512 | 69ms | 53ms | 481〜494ms |
| デフォルト(確認された値2,048) | 227ms(3回繰り返し:227、226、226) | 14ms | 466〜480ms |
| 8192(入力が3,500トークンのため実効チャンクは3,500) | 445ms | 14ms | 461〜474ms |
- 1ステップで処理する入力トークン数が多いほど、デコーディングがそれだけ長く一時停止します。 このGPUの入力処理速度は約8,200 tok/s(第21編)であるため、チャンク1つあたりの時間は、512トークンであれば約62ms、2,048トークンであれば約250ms、3,500トークンであれば約430msになります(計算値)。上記の最大ITL 69、227、445msはこの計算結果と一致しています。デフォルト値はサーバー設定を読み込んで確認しました。このバージョンにおける
max_num_batched_tokensのデフォルトは2,048であり、チャンクプリフィルは有効で(enable_chunked_prefilltrue)、プレフィックスキャッシュも有効、ブロックサイズは16トークンでした。 - チャンクを小さくすると、デコーディングの途切れが減る代わりに入力処理が少し遅くなります。 長い入力のTTFTは、512の481〜494msに対し、8192では461〜474msと約3〜5%の差でした。その代わり、割り込み区間の中央値ITLは512で53msに増加しました(チャンクのステップごとにデコーディングと入力処理が混ざり合うため)。
- 用途に応じて選択します。 トークンが途切れることなく出力されるべき対話・音声サービスには小さなチャンクが、長いドキュメントをまとめて処理するバッチ処理には大きなチャンクが適しています。2つの値の間(1,024、4,096)も測定しました。割り込み区間の最大ITLは、1,024で129ms(3回測定:128〜129)、4,096で445ms(445〜446)であり、デフォルトの2,048(227ms)、512(69ms)、8,192(445ms)と合わせると、最大ITLはチャンクサイズに比例していました(入力処理速度約8,200 tok/sとして1,024トークンは約125ms)。4,096が8,192と同じ値なのは、入力が3,500トークンのため実効チャンクが3,500になるからです。長い入力自体のTTFTは、1,024で468〜493ms、4,096で461〜476msとほぼ同じでした。
8. CUDAグラフを無効にすると(--enforce-eager)
| 設定 | サーバー準備時間 | 同時1スループット | 同時32スループット | ITL中央値(同時1) |
|---|---|---|---|---|
| デフォルト(CUDAグラフあり) | 71秒(初回起動、コンパイル19秒含む)、以降の再起動は35〜55秒 | 66 tok/s | 831 tok/s | 15ms |
--enforce-eager |
30秒 | 64 tok/s | 814 tok/s | 15ms |
このサイズのモデルでは、CUDAグラフが速度にもたらす利得は約3%と小さく(同時1で66対64)、サーバーの準備は約25〜40秒早くなりました。トークンあたり14〜15msかかるモデルでは、カーネルの起動間隔が全体に占める割合が小さいためだと推測されます。より小さなモデルでは利得が大きくなると記載しましたが、Qwen3-0.6Bで同じテストを3回繰り返したところ、実際にその通りになりました。同時1においてCUDAグラフのデフォルトが168 tok/s(ITL 6ms)に対し、 --enforce-eager は108 tok/s(ITL 9ms)で、 グラフ有効時の方が55%速く, 同時32では1,557対1,503 tok/sと約3.6%でした。サーバー準備は55秒対30秒でした。モデルが小さくトークンあたりの時間が6msであれば、カーネルを起動する間隔が全体の大きな割合を占めるためだと推測されます。より高速なGPUはテストできませんでした(未測定)。さらにモデルを大きくしたQwen3-4B-FP8では、同時1においてグラフのデフォルトが49 tok/s対 --enforce-eager 47 tok/sと、利得は約4%でした(ITL 19ms対20ms)。グラフによる利得は1トークンが短い非常に小さなモデルでのみ大きく、1.7B以上では3〜4%と同程度でした。
9. サーバーの初回起動にかかる時間
サーバーログのタイムスタンプから読み取った値です。
| 段階 | 値 |
|---|---|
| プロセスの起動とモジュールの読み込み(エンジン初期化開始まで) | 約15〜17秒 |
| 重みのロード(ディスクからGPUへ) | 4〜6秒(モデルファイルがすでに存在する場合) |
| エンジンの初期化(コンパイル、プロファイリング、KVキャッシュの割り当て、CUDAグラフのキャプチャ、ウォームアップ) | 初回起動29秒(コンパイル19秒含む)、コンパイルキャッシュがある場合は7.5秒 |
| 準備完了までの合計 | 初回起動71秒、再起動35〜55秒(LoRAを有効にしたサーバーは70秒) |
モデルのダウンロード時間は上記から除外しています(別途)。オートスケーリングにおいて新しいポッドがトラフィックを受信するまでの時間は、この数値にイメージの取得とモデルのダウンロードが加算されるため、 事前温めされたレプリカと モデルキャッシュボリュームの必要性が数値として表れます。
10. 運用において採用すべき事項
- 同時実行数の上限 = KV容量 ÷ リクエストあたりのトークン数。 式は第3節、根拠は第4節にあります。上限を超えるとスループットは増加せず、TTFTのみが増加します。
- TTFT p95とITL p99を個別に確認する。 中央値が正常でも、テールが大きい(ITL p99 223ms)。
- 共通のプレフィックスを設計によって作成する。 システムプロンプトとドキュメントを先頭に置き、リクエスト別の内容を後ろに配置すると、プレフィックスキャッシュが14倍の利得をもたらします。
- KV 8ビットはスループットのオプションではなく、容量のオプションである。 長い入力において待ち行列が長い場合に効果が大きい。品質評価を先に行う。
- チャンクサイズは、途切れにくさと入力処理速度のトレードオフである。 対話サービスには小さく、バッチ処理には大きくする。
- パフォーマンス測定は毎回異なる入力を作成し、ハードウェアの限界と比較する。
11. 面接で出題されそうな質問
- vLLMサーバーの最大同時リクエスト数はどのように見積もるか? KVキャッシュのトークン数を、リクエストあたりの平均トークン数(入力+出力)で割る。トークンあたりのKVは
2 × 층 × KV 헤드 × head_dim × 바이트である。1.7Bモデルは22,048トークンであり、640トークンのリクエストであれば約34個となり、これを超えるとTTFTが8倍(666msから5.7s)に跳ね上がった。 - 同時性を上げたのにスループットが伸びない理由は? 重み読み込みを分散させるメリットはKV容量がある間だけ続き、容量が一杯になるとリクエストがキューで待機する。
- プレフィックスキャッシュはどのようなサービスで効果が大きいか? 共通のプレフィックス部分が長いサービス。3,000トークンのプレフィックスでTTFTが394msから28msに減少した。
- KV 8ビットの効果は速度か、それとも容量か? 容量である。トークン当たりのバイト数が半分になり、同じメモリに1.9倍格納できたため、長い入力のTTFTが4.0sから0.94sに減少した。短いコンテキストの速度は同じだった。
- 長い入力が来ると他のユーザーのトークン生成が途切れるのはなぜか、どうすれば減らせるか? 入力処理段階がデコードと同じバッチで実行されるため、その分遅れる。チャンクドプリフィルにより1段階あたりのトークン数を減らせば、途切れはチャンクサイズに比例して減少する(512トークンであれば最大69ms)。
- 性能テストの数値が正しいかどうかをどう疑うべきか? ハードウェアの限界(演算、帯域幅)と照らし合わせる。同じ文章を繰り返すとプレフィックスキャッシュがヒットし、実際には不可能な処理速度が出てしまう。
外部的根拠:論文と公式資料で確認した内容
この記事の数値はすべて実測値です。同じ現象を報告している外部資料を参照して数値と条件を確認し、私たちの結果との関係を記載しました。外部の数値はモデル、GPU、負荷が異なるため、 直接比較せず、傾向と構造の一致のみを判定しました。
| 主題 | 資料と確認した箇所 | 確認した内容と条件 | この記事との関係 |
|---|---|---|---|
| KVサイズの数式 | Kwon他, PagedAttention, SOSP 2023, arXiv 2309.06180, セクション3および表1 | OPT-13BのトークンあたりKVは 2(キー・バリュー) × 5,120(隠れ層サイズ) × 40(層) × 2(バイト) = 800KB。A100 40GBから重み26GBを差し引き、12GBをKVに使用すると15.7Kトークンとなり、12GiB ÷ 800KiB の計算結果と一致 | 支持。 この記事の数式(セクション3)と同じ式 |
| 既存システムのKVの無駄 | 同論文 セクション1および図2 | 実際のトークン状態で使用されるKVの割合は20.4〜38.2%。著者らが独自に実装したOrcaの3つのバリエーションの平均であり、FasterTransformerは含まれない | 関連。16トークン単位でのブロック管理(この記事で確認したデフォルト値)がこの無駄を削減する方法 |
| チャンクサイズとトークン間の遅延 | Agrawal他, Sarathi-Serve, OSDI 2024, arXiv 2403.02310, セクション4.3および図6、セクション5.4.1 | チャンク(トークン予算)が小さいほど反復時間が短くなり、トークン間遅延が減少する。演算限界領域において反復時間はトークン数に線形比例する。チャンク512では全体の入力処理時間が最大約25%増加し(Yi-34B、テンソル並列2)、2,048ではほぼ無視できるレベル | 支持。 セクション7の傾向と一致。私たちのTTFT増加(3〜5%)はモデルやGPUが異なるためサイズの比較は不可 |
| 同時性とスループットの傾向 | 同論文 セクション3.1および図3(Mistral-7B、A100 1基、入力1,024) | バッチ処理によりデコードのスループットがほぼ線形に向上し、入力処理にはほとんど影響がない | 限定的に支持。 21本の短いコンテキスト(同時実行16まで14〜15倍)と同じ傾向。セクション4の入力512の表はより早い段階で頭打ちになる |
| 容量を超過した際の遅延の急増 | PagedAttention セクション6.2 | リクエスト率がシステムの容量を超えると、キューが果てしなく長くなり遅延が急増する | 支持。 セクション4のTTFT 8.6倍と同じ現象 |
| 容量に達する前にスループットが頭打ちになるケース | Recasens他, 「Mind the Memory Gap」, arXiv 2503.08311, セクション3〜5 | H100上のOPT-2.7B等において、大きなバッチでもメモリの限界に留まり、バッチ1の 225 tok/s がバッチ256で 7,607 tok/s(約33.8倍であり、期待された256倍ではない)にとどまる | 限定的に支持。 セクション4の頭打ちがKV容量だけの問題ではない可能性を示す根拠 |
| KV 8ビットの品質 | vLLM公式ブログ 「The State of FP8 KV-Cache and Attention Quantization in vLLM」(2026-04-22) | 補正を行わないFP8(スケール1.0)における推論タスクの精度低下は、Qwen3-30B-A3B-Thinking-2507で最大1〜2ポイント、Qwen3.5-27Bで最大0.7ポイント(H100) | 支持。 文献上の変化は小さいが、モデルと補正に依存する。私たちのモデル(1.7B)と評価についてはセクション5を参照 |
| KV 8ビット(整数) | LMDeployドキュメント(INT8 KV, OpenCompass) | llama2-7b-chatのMMLUが35.64から35.58へ、internlm2.5-chat-7bのMMLUが72.30から72.27へ変化。FP8ではなくINT8であるためそのまま適用することはできない | 関連。vLLMの --kv-cache-dtype fp8 とは異なる方式 |
| プリemption(先取り)方式 | vLLM公式ドキュメント(最適化ページ)、v0.30.0 scheduler.py、PagedAttention セクション4.5および7.3 |
V1におけるプリemptionはスワップではなく再計算が基本であり、犠牲となるリクエストのブロックをすべて返却し、計算されたトークン数を0に戻してキューの先頭に戻す。論文では小さなブロックにおいて再計算が効率的であると説明されている | 支持。 セクション4のプリemptionに関する記述と一致(プリemption後のプレフィックスキャッシュヒットは未確認) |
| デフォルト値 | v0.30.0 config/cache.py |
プレフィックスキャッシュ有効(デフォルト)、ブロックサイズ16 | 支持。 0.31.0で直接確認した値(有効、16、チャンク予算2,048)と一致 |
ベンダーおよびプロジェクトのブログ(vLLM、LMDeploy)の数値は、条件が本文に記載されているもののみを転記しました。ACMのPagedAttentionページにアクセスできず、arXivの抽象ページの表記に従いました。
確認できなかった事項
- 異なるハードウェア環境における反復の変動。 この環境では変動が0.5%以内でしたが(セクション2)、異なるGPUや周辺の負荷がある環境では異なる可能性があります。同時実行64のようにキューが蓄積する区間での反復は5回で測定していません。
- 異なるモデル、異なるGPU、より長いコンテキスト。 1.7Bの1つのモデル、8GBクラスのGPU、入力4,096までが対象です。
--max-num-batched-tokensの512〜8192の間の値(デフォルトの2,048は確認済み)。- KV 8ビットの出力品質と、プレフィックスが重複しない大量のリクエストにおけるプレフィックスキャッシュのCPU負荷。
- プリemptionされたリクエストが再開される際にプレフィックスキャッシュにヒットするかどうか。 返却されたブロックがハッシュを保持したまま空きブロックキューに残るという設計上の記述から、一部ヒットする可能性があると推測されるのみで、公式の記述や測定による確認はできていません。
- プリemptionが発生する条件の全体像。 サーバー指標としてプリemption回数は読み取りましたが(セクション4)、入力・出力長や同時実行数を細かく変更しながら曲線を描く測定は行っていません。
- SGLangなど他のサーバーとの比較、マルチGPU、量子化モデル(21本で一部実施)。
確認したバージョンと日付
2026-10-07基準。vLLM 0.31.0, PyTorch 2.13 (CUDA 13), Qwen3-1.7B (bf16)。