状態: ドラフト(2026-10-13)、一部実測。 実測値は、同じサイトの「トス ML/AI Infra 準備」第 8 回にて、8GB 級 GPU 1 枚、Qwen2.5-1.5B-Instruct、vLLM 0.29.0、LMCache 0.5.5(プロセス内モード)で測定した値を再引用しています。論文および公式ドキュメントは 2026-10-13 に直接開いて確認しました。LMCache の現在の推奨方式(MP モード)と大規模モデルの値は未実測です(イメージとモデルを新しくダウンロードする必要があるため承認待ち)。 2026-10-27 追加。 承認を得て、vLLM 0.32.0 公式イメージ(LMCache 0.5.6 がすでに含まれている)と Qwen3-0.6B で MP モードを測定しました。結果は第 9 節にあり、前節の 2026-10-13 の数値はそのまま残してあります。大規模モデルと複数サーバーについては依然として未実測です。 執筆ルール: 実測データを基本とし、測定できなかったものは「未実測」、確認できなかったものは「未確認」と表示します。
LMCache: KV キャシを GPU の外へ
目次
- 1. GPU 内キャッシュが持つ 2 つの限界
- 2. LMCache の構造
- 3. なぜ TTFT とスループットが向上するのか
- 4. 実測値: 576ms から 48.6ms へ
- 5. 損益分岐: 読み込みが計算より安い場合のみ
- 6. プレフィックス以外の部分も再利用: CacheBlend、CacheGen
- 7. プリフィル・デコード分離における KV 転送
- 8. メリットがないのはどのような場合か
- 9. 2026-10-27 MP モード再測定
- 参考
1. GPU 内キャッシュが持つ 2 つの限界
第 2 回のプレフィックスキャッシュは強力ですが、GPU メモリ内だけで動作します。そのため、2 つの物足りなさが残ります。
- 容量が足りなくなると削除されます。 削除されたプレフィックスが再び来ると、最初から計算し直します。
- インスタンスごとに個別です。 同じモデルを複数の GPU にデプロイした場合、隣のインスタンスが直前に計算した KV を使用できません。
1 つ目の制限がどれほど深刻か測定したことがあります。GPU の KV 容量(21,520 トークン)より大きな文書群(文書 10 個、1 文書あたり約 5,000 トークン、合計約 5万トークン)を順番に読み込ませ、 同じ順番で再度 読み込ませました。vLLM のみを使用した場合、2 回目の読み込みにおける最初のトークンまでの時間は 576ms で、初回(575ms)と同等であり、vLLM による強力なプレフィックスキャッシュのヒットは 0 でした。最も古いものから削除するキャッシュ(LRU)に循環しながらアクセスすると、容量が少しでも足りない場合、次の番に使う文書が常に直前に削除されているためです。
2. LMCache の構造
LMCache は、サービングエンジンの脇に配置される KV キャッシュ階層です。技術レポート(arXiv 2510.09665、2025-12 改訂版)および公式ドキュメント(2026-10-13 閲覧)で確認した構造は以下の通りです。
- エンジンとの接点は KV コネクタです。 vLLM は、エンジンの外へ KV を出力および取り込むための標準インターフェース(KV connector)を備えており、LMCache はその実装の 1 つです。スケジューラー側は「このリクエストのプレフィックスのうち何トークンを外部で見つけたか」を問い合せ、モデル実行側はレイヤーごとに読み込み・保存を開始して待機します。
- 単位はチャンクです。 デフォルトの 256 トークンを 1 つの塊として扱います。vLLM のブロック(16 トークン)より大きくまとめる理由は、ストレージやネットワークは小さな断片を大量に転送する際に低速になるためです。レポートでは、帯域幅を使い切るためには一度に転送する単位が大きくなければならない根拠として、別の測定結果を引用しています。
- ストレージ階層は GPU → CPU メモリ → ローカルディスク → リモートストレージです。レポートやドキュメントには、Redis・Valkey、S3、Mooncake、NIXL、InfiniStore、共有ファイルシステム、GPUDirect Storage などがバックエンドとして挙げられています。
- 待たせないための仕組み。 保存はバックグラウンドで非同期に行われます。読み込みはレイヤー単位で計算と並行して実行されます(このレイヤーを計算している間に次のレイヤーの KV を取得する)。リクエストがキューに並んでいる間に、低速な階層の KV を高速な階層に事前に読み上げておくこともあります。
- **現在の推奨構成は、ノードごとに 1 つ起動する専用サーバー(MP モード)**です。複数の vLLM が 1 つの
lmcache serverを共同で利用します。初期の「エンジンプロセス内で動作する方式」は、ドキュメントにおいて Legacy・deprecated と表記されています。最新の正式版は v0.5.5(2026-09-12)であり、v0.5.6 プレリリース版が公開されています。
同じプレフィックスをキーとして使用するため、 インスタンス 1 が保存した KV をインスタンス 2 が見つけて使用できます。 同一ノードであれば MP サーバーの CPU メモリを、異なるノードであれば共有ストレージや RDMA を介して近隣のメモリを読み取る P2P 方式を使用します。
3. なぜ TTFT とスループットが向上するのか
核心は一言です。 再計算するプリフィルを、ストレージからの読み込みに置き換えます。
- TTFT。 最初のトークンまでの時間の大部分はプリフィルです(第 1 回)。プレフィックスの 4,864 トークンを読み込めば、残りの約 150 トークンだけを計算すれば済みます。
- スループット。 プリフィルは GPU の計算リソースを最も多く消費するフェーズです。それをスキップすることで、同じ GPU が同じ時間により多くのリクエストを受け付けることができるようになります。そのため、「同じ TTFT を維持しながら処理できるリクエストレート」が向上します。
- トークン間隔(ITL)。 第 2 回で見たように、長いプリフィルは同一 GPU のデコードを停止させます。プリフィルが短縮されれば割り込みも減り、トークン間隔も均一になります。
レポートの数値(8×H100 サーバー、Llama-3.1-8B・70B、Qwen2.5-72B など 6 つのモデル、CPU オフロード上限 500GB):
| 実験 | 条件 | 結果(最強のベースラインと比較) |
|---|---|---|
| マルチターン文書 Q&A、CPU オフロード(8.2 節) | 入力約 1 万トークン(文書約 12 ページ + 質問)、出力最大 100 トークン、ベースラインは vLLM 0.10.2(GPU プレフィックスキャッシュ)・vLLM CPU オフローディング・商用製品 2 つ | 1 リクエスト/秒における TTFT が 1.9〜8.1 倍小さく、ITL が 7〜92% 小さい、 同じ TTFT におけるスループットが 2.3〜14 倍 |
| 実際のサービス記録の再生(8.3 節) | 2 社の入出力分布、CPU 500GB、ベースライン vLLM | TTFTが3.7〜6.8倍小さく、ITLが19〜58%小さい |
| 中央ストレージサーバー(8.4節) | リモートサーバーと15Gbpsのリンク | 同じTTFTでのスループットが1.3〜3倍 |
アブストラクトにはスループットが「最大15倍」と記載されていますが、結果の節で確認した最大値は8.2節の14倍でした。リモートストレージ側のメリットが1.3〜3倍とCPUメモリより小さいのはリンクが遅いためであり、次の節の損益分岐点と同じ話になります。
4. 実測値:576msから48.6msへ
1節の実験でLMCacheを有効にしました(CPUメモリの上限1.5GB、チャンク256)。環境は8GBクラスのノートPC用GPU、Qwen2.5-1.5B-Instruct(fp16)、vLLM 0.29.0、LMCache 0.5.5で、リクエストは1つずつ送信しました。
| 設定 · パス | 最初のトークン p50 | p95 | パス全体 |
|---|---|---|---|
| vLLMのみ · 初回 | 575.5ms | 637.3ms | 6.2秒 |
| vLLMのみ · 再度 | 576.2ms | 577.9ms | 6.2秒 |
| LMCache · 初回 | 597.8ms | 676.2ms | 6.5秒 |
| LMCache · 再度 | 48.6ms | 59.6ms | 0.9秒 |
「再度」は同じ順序で再び読み込んだ2回目のパスです。
- 再読み込みの最初のトークンが 約12倍 速くなりました。LMCacheのログには、リクエストごとに約5,000トークン中4,864トークン(256 × 19)をCPUからロードし、エンジンが新しく計算したトークンは0であると記録されました。チャンク単位のため、最後の足りない部分はロードできずに再計算されます。
- ロードされたKVはドキュメントあたり0.13GBでした。パート1の式によると、Qwen2.5-1.5B(28層、KVヘッド2、ヘッド次元128、2バイト)はトークンあたり28,672バイトであり、4,864トークンであれば0.1299GiBとなり、ログと一致します。
- 初めて読み込むときは約4%遅くなりました(575.5 → 597.8ms)。読み込みながらKVをCPUに退避させるコストです。
- GPUメモリの使用量は両方の設定で同じでした。LMCacheはGPUの領域を追加で消費しません。
長さを変えてみると、コンテキスト長に応じてメリットが大きくなります(CPU 2GB、GPUから追い出されたドキュメントを再リクエスト)。
| 入力トークン | 再計算 | ロード | 倍率 |
|---|---|---|---|
| 554 | 66ms | 21ms | 3.1倍 |
| 1,077 | 119ms | 24ms | 5.0倍 |
| 2,144 | 231ms | 29ms | 8.0倍 |
| 4,273 | 481ms | 45ms | 10.7倍 |
| 6,414 | 768ms | 41ms | 約19倍 |
再計算にかかる時間は長さにほぼ比例しますが、ロードにかかる時間はGPUで直接ヒットする場合(20〜32ms)よりも数ms余分にかかる程度で緩やかです。
容量は崖のようになっています。 同じ再読み込みをCPUの上限のみを変えて測定しました(ワーキングセットのKVは計算上で約1.49GB)。
| CPU上限 | 再読み込み最初のトークン | 外部ヒット |
|---|---|---|
| なし(vLLMのみ) | 600ms | — |
| 0.5GB | 620ms | 0% |
| 1.0GB | 620ms | 0% |
| 1.5GB | 39ms | 98% |
| 2.0GB | 39ms | 98% |
ワーキングセットよりも少しでも小さければメリットは0になり、保存コストだけが残りました。1節と同様のLRU循環アクセスの罠です。現実のように一部のドキュメントが頻繁に読み込まれる分布(ジップ則、ドキュメント60個)では、小さなキャッシュも役に立ち、平均の最初のトークンがvLLMのみの278msから、CPU 1GBで174ms、2GBで63msに短縮されました。
この実験の限界:同時実行 1、1.5B モデル 1 つ、乱数単語で作った合成文書、1 回ずつ測定した値であり、今回の文書が勧める MP モードではなくインプロセスモードでした。
5. 損益分岐:読み込みが計算より安い場合のみ
読み込みが有利であるためには、 KV を転送する時間がその KV を再計算する時間より短い必要が あります。トークン n 個について書くと次のようになります。
- 再計算:n × (トークンあたりのプリフィル時間)
- 読み込み:n × (トークンあたりの KV バイト) ÷ 帯域幅 + 固定遅延
n が両辺にあるため、固定遅延を除くと、 損益分岐帯域幅 = トークンあたりの KV バイト ÷ トークンあたりのプリフィル時間となります。上記の測定値(6,414 トークン 768ms、1 トークンあたり約 0.12ms)を当てはめると、28,672 バイト ÷ 0.12ms ≈ 0.24GB/s となります(計算)。
- CPU メモリ(この GPU の PCIe 実測 13.4GB/s)は分岐より 50 倍以上速く、確実なメリットとなります。
- 1GbE 級リンク(別の実験で測定した実効 104MB/s)は分岐より遅いです。6,414 トークンの KV(約 184MB)を転送するだけでも約 1.8 秒かかり、再計算(0.77 秒)より時間がかかります(計算)。 遅いネットワークストレージからの読み込みは損になります。
- 報告書も同じ結論です。B200 GPU において、32Gbps リンクは入力が 256K トークンを超える場合のみ読み込みがプリフィルより速く、64・128Gbps はテストしたすべての長さで速かったです(8.7 節。この実験のモデル名は本文と図 15 の説明のどこにもありません — 2026-10-15 に v2 を再度開いて確認。8.1 節のモデル一覧は H100 実験基準です)。そのため著者は、読み込むか再計算するかを状況に応じて選ぶよう勧めています。
モデルと GPU が分岐を動かします。 プリフィルの計算量はトークンあたりおおよそ「2 × パラメータ数」FLOP であり、KV バイトは第 1 部の式のとおりです。両者の比(KV 1 バイトを節約したときに浮く計算量)を公開構成で計算すると次のようになります(アテンション計算は除外して概算)。
| モデル | トークンあたりのプリフィル計算 | トークンあたりの KV | KV 1 バイトあたりの計算 |
|---|---|---|---|
| Qwen2.5-1.5B | 約 3.1 GFLOP | 28KiB | 約 11 万 FLOP |
| Llama 3.1 8B | 約 16 GFLOP | 128KiB | 約 12 万 FLOP |
| Qwen2.5-7B | 約 15 GFLOP | 56KiB | 約 27 万 FLOP |
| Llama 3.1 70B | 約 140 GFLOP | 320KiB | 約 43 万 FLOP |
KV 1 バイトあたりの計算が大きいほど、読み込みが有利になります。GQA で KV を削減した大きなモデルほど「読み込む価値」が高くなります。逆に、 GPU が速いほど 再計算が速くなり、分岐帯域幅が上がります。同じストレージであっても、遅い GPU ではメリットになり、速い GPU ではデメリットになる可能性があります。
ヒット率にも分岐があります。 ヒットすると 527.6ms を節約でき(576.2 − 48.6)、ミスすると保存コスト 22.3ms が発生します(597.8 − 575.5)。ヒット確率 p において期待利益が 0 になる p は 22.3 ÷ (22.3 + 527.6) ≈ 4% です。これは本実験の値であり、一般的な定数ではありません。他の公開データの数値を当てはめると、20% 前後まで上がります。
6. 先頭以外の断片も再利用:CacheBlend、CacheGen
プレフィックスキャッシュは、 先頭から完全に一致する場合のみ 使用します。RAG のように複数の文書断片を毎回異なる順序で結合する場合、最初の断片以外はヒットしません。断片ごとに個別に作成した KV を単に繋ぎ合わせると、断片間のアテンション(後の断片が前の断片を見る処理)が抜け落ちて答えが間違ったものになります。
CacheBlend(Yao ら、EuroSys 2025)は、繋ぎ合わせた後に、 KV のズレが最も大きいトークンのみを選んで再計算します。レイヤーごとにそのようなトークンは 10〜15% ほどであり、10〜20% だけを再計算すれば十分でした。再計算を次のレイヤーの読み込みとオーバーラップさせて隠蔽します。結果として、全体再計算と比較して TTFT が 2.2〜3.3 倍削減され、スループットが 2.8〜5 倍向上し、品質(F1 および Rouge-L)の低下は 0.01〜0.03 以下でした(Mistral-7B・Yi-34B・Llama-70B、A40 2 基、NVMe 実測 4.8GB/s)。LMCache の MP サーバーは、 --engine-type blend でこの機能を有効にします。
CacheGen(Liu ら、SIGCOMM 2024)は、KV を転送するコスト自体を削減します。隣接するトークン間で KV が似ているという点を利用して差分のみを符号化し、前方のレイヤーは密に、後方のレイヤーは粗く量子化します。通常の量子化よりも KV が 3.5〜4.3 倍小さくなり、3Gbps リンクでの TTFT が量子化ベースラインより 3.2〜3.7 倍低くなり、精度低下は 2% 以内でした(Mistral-7B・Llama-34B・70B、A40 4 基)。帯域幅が低下した場合、チャンクごとに圧縮レベルを下げたり、 テキストを送信して再計算する方法に切り替えたり します。これは、第 5 節の損益分岐をチャンクごとにリアルタイムで計算しているようなものです。
7. プリフィル・デコード分離における KV 転送
KV を転送する能力は、別の用途にも使われます。第 4 部で取り上げる 分離サービングでは、プリフィル GPU で作成した KV をデコード GPU に送信する必要があります。LMCache の文書における分離構成では、プリフィル→デコード間の転送を NIXL(vLLM の NixlConnector)に任せ、vLLM の MultiConnector によって LMCache コネクタを統合し、リクエスト間の再利用を高めています。報告書によると、8K 入力・200 出力、NVLink の条件下で、vLLM 単体の分離構成よりも平均 TTFT が 1.53〜1.84 倍、平均 ITL が 1.12〜1.66 倍低かったと報告されています(8.5 節、モデル名は節内で確認できず)。
8. メリットがないケース
| 条件 | 理由 | 根拠 |
|---|---|---|
| プロンプトが短い | 再計算がすでに安いため節約効果が小さい。固定遅延のほうが大きい | 実測:554 トークンで 3.1 倍、6,414 トークンで 19 倍 |
| 同じプレフィックスが再来しない | ヒットしない場合、保存コストしか発生しない | 実測:初回読み込み +4% |
| キャッシュ容量がワーキングセットより小さい(循環アクセス) | LRU により次に使うものが常に削除される | 実測:0.5・1.0GB でヒット率 0% |
| ストレージやネットワークが遅い | 転送時間が再計算より長い | 計算:1GbE はこのモデルの分岐 0.24GB/s を下回る。報告書 8.7 節 |
| 小規模なモデル、高速な GPU | 再計算が速くなり、分岐帯域幅が上がる | 計算(第 5 節の表) |
| GPU プレフィックスキャッシュで十分である | ワーキングセットが GPU にすべて収まる場合、vLLM 単体でヒットする | 実測:チャンクサイズのテストで vLLM 単体のみを使用した場合の値と同等だった |
| 頻繁に読み込まれる文書が GPU に残る(ジップ則) | 検索・保存コストのみが加算される | 実測(2026-10-27、9-4 節):平均初トークン 17.9 → 約 20ms |
| 文書がチャンク(256 トークン)より短い | チャンクに満たない端数は読み込むことができない | 実測(2026-10-27、9-3 節):510 トークンで 1.1 倍 |
9. 2026-10-27 MP モード再測定
第 4 節は、現在の文書で「レガシー」と表示されているインプロセスモードでした。同じ 8GB 級 GPU において推奨方式である MP モード(個別の lmcache server と LMCacheMPConnector)を再度測定しました。モデルとバージョンが異なるため第 4 節の数値と直接比較はしないでいただき、同日かつ同条件で測定した「vLLM 単独 / インプロセス / MP」の 3 行の間で比較してください。
9-1. 環境と方法
- 8GB 級ノートPC 用 GPU(Ada 世代)1 基、vLLM 0.32.0 公式イメージ、LMCache 0.5.6(2026-10-14 正式版、このイメージにすでに含まれており別途インストールせず)、コンテナメモリ制限 4.5GiB。
- モデル:Qwen3-0.6B(bf16)。28 レイヤー、KV ヘッド 8 個、ヘッド次元 128 であるため、トークンあたりの KV は 114,688 バイトとなり、第 4 節の Qwen2.5-1.5B(28,672 バイト)の 4 倍です。逆にトークンあたりのプリフィル計算は約 1.2 GFLOP と半分以下です。第 5 節の表の「KV 1 バイトあたりの計算」として当てはめると約 1 万 FLOP であり、1.5B(約 11 万)の 10 分の 1 です。読み込みにとって最も不利な側のモデルです。
- MP モードの実行は、NVIDIA Dynamo 1.6.0 のサンプル(
agg_lmcache_mp.sh)と同様の形式です。
lmcache server --l1-size-gb 0.75 --eviction-policy LRU --port 5555 --http-port 8080
vllm serve Qwen/Qwen3-0.6B --disable-hybrid-kv-cache-manager \
--kv-transfer-config '{"kv_connector":"LMCacheMPConnector","kv_role":"kv_both","kv_connector_extra_config":{"lmcache.mp.port":5555}}'
- インプロセスモードは、
LMCacheConnectorV1と環境変数LMCACHE_LOCAL_CPU=True,LMCACHE_MAX_LOCAL_CPU_SIZE=0.75,LMCACHE_CHUNK_SIZE=256で有効にしました。 - メモリ予算。 LMCache サーバーは L1 を使用する前でも無名メモリを約 0.93GiB 消費し、vLLM サーバーは約 2.7GiB 消費しました。制限である 4.5GiB 内に収めるため、L1 を 0.75GB 以下に設定しました。最初の試行では、インプロセスモードのサーバーを停止した直後に MP サーバーを起動したためコンテナがメモリ不足で強制終了し、前のサーバーが完全に停止したことを確認してから起動するように修正して再測定しました。
- リクエスト:シードとして指定したランダムな単語文書の後ろに短い質問を付加して
max_tokens 2で尋ね、ストリーミングで初トークンまでの時間を測定しました。GPU の KV 領域は--kv-cache-memory-bytesで意図的に小さく制限しました。同条件を 3〜4 回実行して中央値を使用し、最初のパス(保存を含む)は個別に記録しました。
9-2. 基本的な効果:GPU にすべて収まらない文書群の再読み込み
GPU KV を 2,336 トークンに制限し、約 1,020 トークンの文書 4 つ(合計約 4,080 トークン)を同じ順序で 4 回読み込みました。
| 設定 | 初回パス(保存を含む) | 再読み込み(2〜4 回目のパスの中央値) | 文書あたりの読み込み済みトークン数 |
|---|---|---|---|
| vLLM 単独 | 55.7ms | 46.5ms | 0 |
| インプロセス(LMCacheConnectorV1、CPU 0.75GB) | 71.3ms(+28%) | 24.2ms(1.9 倍) | 768 |
| MP(LMCacheMPConnector、L1 0.75GB) | 60.7ms(+9%) | 32.9ms(1.4 倍) | 768 |
- vLLM 単独は第 4 節と同じ罠に陥りました。循環アクセスのため GPU ヒット率が 0 でした。
- チャンク単位の損失が確認されました。 1,020 トークンのうち 256 トークンのチャンク 3 つ(768 トークン)のみが読み込まれ、残りの約 250 トークンは再計算されました。文書が短いほどこの割合が大きくなります。
- MP モードはインプロセスモードよりも再読み込みが約 9ms 遅く、初回読み込みの保存コストは小さかったです。 KV がエンジンの外にある他のプロセス間を行き来するためだと考えられます。MP モードでは、GPU で直接ヒットするリクエストも vLLM 単独より 3〜4ms 遅くなりました(1,000 トークンで 15.7ms 対 12.0ms)。リクエストごとにサーバーへ問い合わせるラウンドトリップが発生するためです。
9-3. 長さ別:再計算 vs 読み込み
GPU KV を 0.75GiB(7,020 トークン)に設定し、文書を 1 回読み込んで保存した後、vLLM の /reset_prefix_cache(開発モード)で GPU キャッシュのみをクリアして再度読み込みました。LMCache 側は文書ごとに管理 API を用いて L1 をクリアしました。文書の長さごとに 4 回のうち最初の 1 回を除外して中央値を使用しました。
| 入力トークン | vLLM 単独 再計算 | MP 読み込み | 読み込み済みトークン数 | 倍率 | GPU ヒット(参考) |
|---|---|---|---|---|---|
| 約 510 | 32.2ms | 29.8ms | 256 | 1.1 倍 | 11.2ms |
| 約 1,005 | 45.9ms | 37.0ms | 768 | 1.2 倍 | 12.0ms |
| 約 2,010 | 98.3ms | 46.3ms | 1,792 | 2.1 倍 | 14.5ms |
| 約 4,020 | 226.2ms | 68.2ms | 3,840 | 3.3倍 | 19.2ms |
| 約6,030 | 390.9ms | 91.3ms | 5,888 | 4.3倍 | 23.8ms |
第4節の1.5B実測(6,414トークンで約19倍)より倍率が小さくなります。このモデルは再計算が速くKVは大きいため、同じ長さで節約できる時間が少なく、転送すべきバイト数が多いためです。それでも、長さが長くなるほど倍率は大きくなる傾向は同じでした。
最初の試行から学んだこと。 L1を空けずに長さ別のテストを実行したところ、2,000トークン以上でほとんどヒットしませんでした。LMCacheのログに「Failed to batched allocate … no enough memory」という警告が蓄積され、指標 lmcache_mp_l1_allocation_failure_chunks_total{during="l1_store"} が増加しました。退避(Eviction)は、使用率がしきたり(デフォルト0.8)を超えると非同期で20%ずつ解放する方式であるため、大きなドキュメントが一度に入ってきたときに空きを待たずに 保存を破棄しました。 エラーは発生せずにヒットのみが消えるため、L1は一度に入ってくる最大ドキュメントよりも余裕を持たせて確保し、この指標を監視する必要があります。
9-4. 容量:崖の代わりに部分ヒット、そしてジップ分布の逆効果
循環アクセスは9-2と同じドキュメント4つ(ワーキングセット約0.46GB)、ジップ分布は約480トークンのドキュメント20個を120回(指数1.1)読み込みました。GPU KVは2,336トークンです。
| 設定 | 循環:再読み込み初トークン | 循環:外部ヒットトークン | ジップ:平均初トークン |
|---|---|---|---|
| vLLM単体 | 46.5ms | 0 | 17.9ms |
| MP、L1 0.25GB | 41.2ms | 1,791 / 4,034(44%) | 20.3ms |
| MP、L1 0.5GB | 32.6ms | 3,328 | 20.0ms |
| MP、L1 0.75GB | 33.0ms | 3,328 | 19.9ms |
- 今回は崖ではありませんでした。 ワーキングセットより小さい0.25GBでも44%を読み込みました。第4節のプロセス内モードは、ワーキングセットよりわずかに小さくてもヒットが0でした。MPサーバーの退避がしきい値で一部のみを解放する方式であるため、循環アクセスでも一部が生き残ったものと見られます。
- ジップ分布では、MPモードがvLLM単体よりも遅くなりました(17.9 → 約20ms)。 頻繁に読み込まれるドキュメントはGPUのプレフィックスキャッシュに残るため、3つの設定すべてでGPUヒットが同じであり(28,208トークン)、LMCacheが読み込んだドキュメントはほとんどが480トークンであるため、チャンク1つ(256トークン)しか取得できませんでした。節約できた分よりも、リクエストごとに発生するルックアップ・保存コストの方が大きかったです。 GPUプレフィックスキャッシュがすでにうまく機能しているワークロードには、LMCacheを適用しない方が望ましいです。
9-5. MPモードならではの利点
- vLLMを再起動してもキャッシュが残りました。 ドキュメント4つを読み込んだ後、vLLMのみを終了して再起動しました(サーバーはそのまま、再起動約30秒)。GPUキャッシュは空になりましたが、4つのドキュメントすべてで768トークンをサーバーから読み込み、初トークンの中央値は37.5msであり、同じ新しいvLLMで初めて見るドキュメントは56.7msでした。プロセス内モードではキャッシュがエンジンプロセスと一緒に消滅するため、これは不可能な動作です。デプロイ・再起動・スリープモード後の初リクエストをウォームアップされた状態で処理できます。
- 2つのvLLMが1つのサーバーを共用するケースは未計測です。 1つのvLLMが約2.7GiB、サーバーが約0.93GiBを使用しており、ノードの空きメモリの半分として設定されたコンテナの制限内に2つのvLLMを一緒に起動することはできませんでした。9-5の最初の項目の再起動テストが、「別のエンジンプロセスが前のプロセスが保存したKVを読み込む」という同じ原理を代わりに示しています。
9-6. L2ローカルディスク階層と損益分岐点
L1を0.25GBと小さく設定し、ファイルシステムL2を追加しました(--l2-adapter '{"type":"fs","base_path":"…","use_odirect":true}'、ページキャッシュを経由しないO_DIRECT、コンテナの一時ディスク)。
| 項目 | 値 |
|---|---|
| 循環の再読み込み初トークン(L1 0.25GB + L2) | 41.6ms(L2がない場合は41.9ms) |
| L1から押し出された1,000トークンのドキュメントをL2から再読み込み | 54.6ms、55.4ms(768トークンを読み込み) |
| 同じドキュメントをvLLM単体で再計算 | 45.9ms |
L2読み込み速度(LMCache指標の平均) / dd O_DIRECT読み込み |
秒速3.8GB / 秒速4.8GB |
| L1→GPU読み込み速度(LMCache指標、20回平均) | 秒速11.8GB |
| GPU→L1保存速度(同指標、32回平均) | 秒速12.6GB |
- ディスクからの読み込みは再計算よりも遅くなりました(55ms対46ms)。 指標上ではL2のヒットがありましたが(
lookup_hit_l2_tokens_total1,024)、ディスク → L1 → GPUの2ステップを経由し、リクエストごとに先読みを待つ固定遅延が付加されました。 - 第5節の式に当てはめると次のようになります。 このモデルのトークンあたりのプリフィル時間は、1,000トークンで約0.046ms、6,000トークンで約0.065msでした。損益分岐点帯域幅は、114,688バイトをその時間で割って、秒間約1.8GB(6,000トークン)から2.5GB(1,000トークン)になります(計算値)。L1(秒間11.8GB)は分岐点より5倍以上速いため9-3のように勝ちましたが、ディスク(秒間3.8GB)は分岐点よりわずか1.5倍程度しか速くなく、固定遅延を克服できませんでした。第5節の1.5Bモデルであれば分岐点が秒間0.24GBであるため、同じディスクでも勝てたはずです。 モデルが小さいほど、GPUが速いほど、低速な階層の価値が下がるという第5節の結論がそのまま現れました。
- 長い文書(6,000トークン)をディスクから読み込む場合は、メモリ制限のため測定できませんでした(未計測)。固定遅延の割合が減ることで、利益が出る可能性があります。
9-7. 指標
MPサーバーのPrometheus指標は、今回の構成における管理HTTPポートの /metrics に出力されました(--prometheus-port で指定した9090は応答しない)。 lmcache_mp_ で始まる指標が48種類あり、運用時にまず確認すべきものは次のとおりです。
| 知りたいこと | 指標 | 今回確認した値 |
|---|---|---|
| ヒット率(チャンク単位) | lookup_hit_tokens_total ÷ lookup_requested_tokens_total |
長さ別テスト 83,456 ÷ 150,528 |
| どの階層から来たか | lookup_hit_l1_tokens_total, lookup_hit_l2_tokens_total |
L2テスト 5,120 / 1,024 |
| L1の埋まり具合 | l1_usage_ratio, l1_memory_usage_bytes |
0.77(L1 0.25GB) |
| 保存内容が破棄されているか | l1_allocation_failure_chunks_total{during="l1_store"} |
L2テスト 6チャンク |
| 転送速度 | l0_l1_load_throughput_GB_per_second, l0_l1_store_…, l2_load_…(ヒストグラム) |
9-6表 |
| 逐出 | l1_evicted_chunks_total, l1_eviction_loop_triggered_total |
|
| 再利用間隔 | real_reuse_gap_seconds, l1_chunk_reuse_gap_seconds |
vLLM側では vllm:prompt_tokens_by_source_total{source="external_kv_transfer"} がLMCacheから受け取ったトークン数です(この節の「外部ヒットトークン」)。管理HTTP APIには認証がないとヘルプに記載されており、デフォルトでは127.0.0.1のみでリスンします。パスのリストには /cache/clear, /reconfigure/…, /run_script があるため、このポートをポッド外へ公開すると、誰でもキャッシュをクリアしたり設定を変更したりできるようになります(/run_script のデフォルトの有効状態は未確認)。
9-8. まとめ
| 質問 | 2026-10-27 MPモード実測の結果 |
|---|---|
| 押し出された長い文書を素早く再読み込みするか | はい。6,000トークン 391 → 91ms(4.3倍) |
| 短い文書は | メリットが小さい。チャンク(256トークン)に満たない端数は再計算され、1,000トークンで1.2倍 |
| プロセス内モードとの比較 | 再読み込みは約9ms遅く、保存コストは小さい |
| エンジンを再起動してもキャッシュは残るか | はい(MPのみ可能) |
| ホット文書がGPUに残る負荷 | むしろ遅くなる(17.9 → 20ms) |
| ディスク階層 | この小さなモデルでは再計算よりも遅い |
一言で言うと。 試合の映像を見直すために、毎回新しく試合をやり直す必要はありません。録画したものを再生すればよいのです。ただし、録画データが遠くの倉庫にあり、道が混雑している場合は、いっそもう一試合やり直したほうが早いこともあります。どれくらい遠いのか、何回見直すのかを事前に測定しなければなりません。
参考
- Liu他、LMCache: An Efficient KV Cache Layer for Enterprise-Scale LLM Inference: https://arxiv.org/abs/2510.09665 (v2、2025-12-05. 5・6・8.2〜8.7・9節)
- LMCacheドキュメント: https://docs.lmcache.ai/ (
mp/index.html,mp/l2_storage/supported_storages.html,mp/disaggregated_prefill.html,mp/p2p.html,kv_cache_optimizations/cacheblend.html、2026-10-13閲覧)、リリース: https://github.com/LMCache/LMCache/releases - Yao他、CacheBlend (EuroSys 2025): https://arxiv.org/abs/2405.16444 (v3、アブストラクト・4・5・7節)
- Liu他、CacheGen (SIGCOMM 2024): https://arxiv.org/abs/2310.07240 (v6、5・7節)
- vLLM分離プリフィル・KVコネクタ: https://docs.vllm.ai/en/latest/features/disagg_prefill/、LMCacheサンプル: https://docs.vllm.ai/en/latest/examples/disaggregated/lmcache/
- 実測の引用:同サイト「トス ML/AI Infra準備」第8回(KVオフロード実測)、第24回(1GbE実効スループット)
- 2026-10-27 MPモード実測の原資料:リポジトリ
docs/experiments/2026-10-27-lmcache-mp/ - NVIDIA Dynamo 1.6.0サンプル
examples/backends/vllm/launch/agg_lmcache_mp.sh: https://github.com/ai-dynamo/dynamo/blob/v1.6.0/examples/backends/vllm/launch/agg_lmcache_mp.sh