vLLM統合(LMCacheConnector)
深度: [MEDIUM] / 確信度: [VERIFIED] 最終更新: 2026-02-16(Phase 1 セッション1)
概要
LMCacheとvLLMを接続するアダプタ層。vLLMのKVConnectorBase_V1インターフェースを実装し、
attentionレイヤー実行中のKVキャッシュstore/retrieveをLMCacheに委譲する。
クラス階層
KVConnectorBase_V1 (vLLM)
└── LMCacheConnectorV1Dynamic ← vLLMに登録される外殻
└── LMCacheConnectorV1Impl ← 実装本体(Worker側)
└── LMCacheEngine ← 直接参照(LMCacheManager経由で取得)
参照:
target/LMCache/lmcache/integration/vllm/lmcache_connector_v1.py(Dynamic)target/LMCache/lmcache/integration/vllm/vllm_v1_adapter.py:964(Impl.save_kv_layer)
主要メソッド(Store方向)
save_kv_layer()
シグネチャ: save_kv_layer(layer_name: str, kv_layer: Tensor, attn_metadata: AttentionMetadata, **kwargs)
vLLMの各attentionレイヤー実行後に呼ばれる。
use_layerwise=Falseの場合は即座にreturn(非レイヤーワイズパスは別経路)kv_role="kv_consumer"の場合もreturn(consumeのみ、storeしない)
Layer 0の処理:
connector_metadata.requestsからsave_spec.can_save=Trueのリクエストを抽出skip_leading_tokensをchunk_size(256)の倍数に切り下げてマスク整合store_maskを構築:prefix部分=False、新規部分=TrueLMCacheEngine.store_layer()でGenerator生成、self.layerwise_storersに追加- 最初のリクエストのみ
sync=True(CUDAストリーム同期)
全レイヤー共通: layerwise_storers内の全Generatorをnext()で1ステップ進行。
ConnectorMetadata
参照: target/LMCache/lmcache/integration/vllm/vllm_v1_adapter.py (LMCacheConnectorMetadata)
Scheduler側で構築され、Worker側に渡される。各リクエストのtoken_ids、slot_mapping、save_spec(can_save, skip_leading_tokens)を含む。
上流・下流
- 上流: vLLM GPUModelRunner(
save_kv_layerフック) - 下流: LMCacheEngine(
store_layer/store/retrieve/retrieve_layer) - 関連: LMCacheManager(ライフサイクル管理、Engine取得)
主要メソッド(Retrieve方向)
Scheduler側: get_num_new_matched_tokens()
参照: target/LMCache/lmcache/integration/vllm/vllm_v1_adapter.py:1193
vLLM Schedulerのschedule()から呼ばれ、外部KVキャッシュのヒット数を返す。
LookupClient.lookup_cache(req_id)で既存キャッシュ確認(2回目以降)- 未キャッシュなら
LookupClient.lookup(token_ids, req_id)でZMQ経由でWorker側に問い合わせ LoadSpec(vllm_cached_tokens, lmcache_cached_tokens, can_load=False)を生成update_state_after_alloc()でcan_load=Trueに更新(ブロック確保成功時)build_connector_meta()でReqMeta(load_spec=LoadSpec)をLMCacheConnectorMetadataに格納
Worker側: start_load_kv()
参照: target/LMCache/lmcache/integration/vllm/vllm_v1_adapter.py:737
vLLMのforward実行前にForwardContextから呼ばれ、KVキャッシュのGPU復元を開始。
token_maskの構築:
request.load_spec.vllm_cached_tokensをchunk_sizeの倍数に切り下げ →masked_token_counttoken_mask[:masked_token_count] = False(vLLM既キャッシュ分)、残り=True
2モード分岐:
- Layerwise (
use_layerwise=True):LMCacheEngine.retrieve_layer()でGenerator取得next()× 2回で先行2レイヤー分をキックself.layerwise_retrieversにGenerator追加
- Bulk (
use_layerwise=False):LMCacheEngine.retrieve()を呼び出し、ret_maskを取得- 取得失敗時は
record_failed_blocks()で失敗ブロックIDを_invalid_block_idsに記録
Worker側: wait_for_layer_load()
参照: target/LMCache/lmcache/integration/vllm/vllm_v1_adapter.py:940
各attentionレイヤー実行前に呼ばれ、該当レイヤーのKVロード完了を待機。
layerwise_retrievers内の全Generatorをnext()で1ステップ進行。
最終レイヤーではret_maskを取得して検証。
設計上の注意点
LMCacheConnectorV1Dynamicは純粋な委譲シェル。全メソッドがself._lmcache_engine(V1Impl)に転送- LMCacheManagerにstore()メソッドは存在しない。V1ImplがEngineを直接呼ぶ
kv_roleは"kv_both"(default)/"kv_producer"/"kv_consumer"の3値。producer時はskip_leading_tokens=0(全トークンstore)current_layerカウンタでレイヤー追跡。wait_for_save()でリセット- Retrieve 2モード:
use_layerwise(デフォルトFalse)でBulk/Layerwiseを切替 - LookupClient-LookupServer分離: SchedulerプロセスのLookupClientからWorkerプロセスのLookupServerにZMQ IPC通信
- LoadSpec: Scheduler→Worker間でlookup結果を伝達するデータ構造(ConnectorMetadata経由)