Prhub

#42865 [KV Connector] Update lmcache kv_offloading_backend to use LMCacheMPConnector

原始 PR 作者 maobaolong 合并时间 2026-06-04 10:23 文件变更 2 提交数 9 评论 4 代码增减 +47 / -18

执行摘要

切换 LMCache 后端默认使用多进程连接器

根据 PR 描述,该变更的目的是将默认的 kv_offloading_backend=lmcache 路径切换到 LMCache 的多进程模式,这样 vLLM 通过 LMCacheMPConnector 与独立的 LMCache 服务器通信,而不是传统的进程内 LMCacheConnectorV1。同时删除不再相关的 lmcache.local_cpu / lmcache.max_local_cpu_size 额外配置,因为 KV 容量现在由独立的 LMCache 服务器管理。

建议阅读此 PR,因为它展示了如何将进程内 KV offloading 设计迁移为外部服务器模式。关键设计决策包括:使用多进程分离解耦缓存管理与推理引擎、利用 connection string 默认值简化配置、移除不再需要的配置项以避免用户误解。对于计划集成外部缓存系统的开发者有很好的参考价值。

讨论亮点

在审核过程中,主要关注点如下:

  • 用户引导:审阅者 @ApostaC 要求确保 LMCache 侧有足够信息避免用户混淆,即用户需要知道必须运行 LMCache 服务器。作者 @maobaolong 回应并创建了 LMCache 侧 PR(LMCache#3365)以在服务器不可达时给出警告。
  • 单元测试失败:@ApostaC 指出初始提交后单元测试失败。作者通过添加 stub fixture 绕过 lmcache 导入问题,并调整测试断言,最终测试通过。

实现拆解

  1. 修改核心配置方法:在 vllm/config/vllm.pyVllmConfig._post_init_kv_transfer_config 中,将 lmcache 分支的连接器字符串从 'LMCacheConnectorV1' 改为 'LMCacheMPConnector',并移除设置 lmcache.local_cpulmcache.max_local_cpu_size 的代码以及 num_kv_ranks 的计算。

  2. 适配单元测试:在 tests/v1/kv_connector/unit/test_config.py 中,因为测试环境的 CPU 测试镜像未安装 lmcache 包,直接导入 LMCacheMPConnector 会失败。为此,添加了一个占位类 _StubLMCacheMPConnector 和一个 pytest fixture stub_lmcache_mp_connector,通过 monkeypatch 替换 KVConnectorFactory._registry 中的加载器,避免实际导入。

  3. 更新测试断言:修改参数化测试 test_kv_connector,将期望的连接器从 'LMCacheConnectorV1' 改为 'LMCacheMPConnector',并将 expected_bytes 改为 None(因为不再传递本地 CPU 大小)。移除对 lmcache.local_cpulmcache.max_local_cpu_size 的断言,改为验证它们不存在于 extra_config 中,同时保留已有配置项。

  4. 删除未使用变量:清理了 _post_init_kv_transfer_config 中计算 num_kv_ranks 的局部变量,因为 lmcache 后端不再需要它,native 后端也从未使用过(native 用的是全局 CPU 字节)。

文件 模块 状态 重要度
tests/v1/kv_connector/unit/test_config.py 配置测试 modified 6.22
vllm/config/vllm.py 配置 modified 5.89

关键符号

_post_init_kv_transfer_config test_kv_connector stub_lmcache_mp_connector

关键源码片段

tests/v1/kv_connector/unit/test_config.py test-coverage

测试适配新连接器,添加 stub 避免导入 lmcache,更新预期连接器名称和 extra_config 断言。

# 占位类:避免在测试环境中导入 lmcache
class _StubLMCacheMPConnector:
    """Stand-in for LMCacheMPConnector used in config-translation tests.
    The real connector module hard-imports the optional ``lmcache`` package
    at module load time, which is not installed in the cpu_test image. This
    test only asserts on the connector *name* and the ``extra_config`` dict
    produced by ``VllmConfig``, never instantiates the connector, so a bare
    placeholder class is sufficient. Not subclassing ``SupportsHMA`` mirrors
    the real connector's HMA support (it does not support HMA either)."""
​
​
@pytest.fixture
def stub_lmcache_mp_connector(monkeypatch):
    """Replace the lazy loader so VllmConfig.__post_init__ does not import
    ``lmcache_mp_connector`` (and thus ``lmcache``) during config tests."""
    monkeypatch.setitem(
        KVConnectorFactory._registry,
        "LMCacheMPConnector",
        lambda: _StubLMCacheMPConnector,
    )
​
​
@pytest.mark.parametrize(
    "kv_offloading_backend,kv_offloading_size,tp,pp,expected_backend,expected_bytes",
    [
        ("native", 4.0, 1, 1, "OffloadingConnector", 4.0 * (1 << 30)),
        # lmcache 后端现在默认使用 LMCacheMPConnector。KV 存储容量
        # 由独立的 LMCache 服务器管理,因此 kv_offloading_size 不会被传播。
        ("lmcache", 4.0, 1, 1, "LMCacheMPConnector", None),
        ("lmcache", 8.0, 2, 2, "LMCacheMPConnector", None),
        # 当 kv_offloading_size 为 None 时,offloading 被禁用(后端被忽略)
        ("native", None, 1, 1, None, None),
    ],
)
def test_kv_connector(
    stub_lmcache_mp_connector,
    kv_offloading_backend, kv_offloading_size, tp, pp,
    expected_backend, expected_bytes,
):
    # 构造 VllmConfig(省略具体构造代码)
    # ...
    if expected_backend is None:
        assert vllm_config.kv_transfer_config is expected_backend
        return
    assert kv_transfer_config.kv_connector == expected_backend
    assert kv_transfer_config.kv_role == "kv_both"
    if kv_offloading_backend == "lmcache":
        # MP 模式下不设置本地 CPU 配置,已有配置保留
        assert "lmcache.local_cpu" not in kv_connector_extra_config
        assert "lmcache.max_local_cpu_size" not in kv_connector_extra_config
        assert kv_connector_extra_config["existing_key"] == "existing_value"
    elif kv_offloading_backend == "native":
        assert kv_connector_extra_config["cpu_bytes_to_use"] == expected_bytes
        assert kv_connector_extra_config["existing_key"] == "existing_value"
vllm/config/vllm.py core-logic

核心配置逻辑变更,切换 lmcache 后端到 LMCacheMPConnector,移除冗余配置。

def _post_init_kv_transfer_config(self) -> None:
    """Update KVTransferConfig based on top-level configs in VllmConfig.    Right now, this function reads the offloading settings from
    CacheConfig and configures the KVTransferConfig accordingly.
    """
    # Check if KV connector requires chunked prefill to be disabled.
    if (
        self.kv_transfer_config is not None
        and self.kv_transfer_config.kv_connector == "ExampleHiddenStatesConnector"
        and self.scheduler_config.enable_chunked_prefill
    ):
        raise ValueError(
            "ExampleHiddenStatesConnector does not support chunked prefill. "
            "Please disable chunked prefill (--no-enable-chunked-prefill)."
        )
​
    # KV offloading is only activated when kv_offloading_size is set.
    if (kv_offloading_size := self.cache_config.kv_offloading_size) is None:
        return
​
    kv_offloading_backend = self.cache_config.kv_offloading_backend
​
    # If no KVTransferConfig is provided, create a default one.
    if self.kv_transfer_config is None:
        self.kv_transfer_config = KVTransferConfig()
​
    if kv_offloading_backend == "native":
        if envs.VLLM_USE_SIMPLE_KV_OFFLOAD:
            config_connector = "SimpleCPUOffloadConnector"
        else:
            config_connector = "OffloadingConnector"
        self.kv_transfer_config.kv_connector = config_connector
        self.kv_transfer_config.kv_connector_extra_config.update(
            {"cpu_bytes_to_use": kv_offloading_size * (1 << 30)}
        )
    elif kv_offloading_backend == "lmcache":
        # 默认使用 LMCache 多进程 (MP) 模式。实际的 KV 存储容量由
        # 独立的 LMCache 服务器管理,因此 kv_offloading_size 不会
        # 传递到这里。当 extra_config 未提供 host/port 时,
        # LMCacheMPConnector 会回退到 tcp://localhost:5555。
        self.kv_transfer_config.kv_connector = "LMCacheMPConnector"
​
    # 所有后端共用
    self.kv_transfer_config.kv_role = "kv_both"

评论区精华

LMCache 侧错误提示 documentation

ApostaC 要求确保 LMCache 侧有足够信息避免用户混淆。

结论:作者在 LMCache 仓库创建了 PR#3365 以在服务器不可达时给出警告。 · 已解决

UT 失败修复 测试

ApostaC 指出单元测试失败。

结论:作者添加了 _StubLMCacheMPConnector 和 fixture 来避免在测试环境中导入 lmcache。 · 已解决

风险与影响

  • 外部依赖风险:现在 lmcache 后端依赖一个独立的 LMCache 服务器进程。如果服务器未启动或网络不可用,vLLM 将因连接超时(默认 300s)而启动失败或性能下降。用户需额外部署服务器,增加运维复杂度。
  • 配置向下不兼容:旧版中通过 lmcache.local_cpulmcache.max_local_cpu_size 控制本地 CPU 缓存,新版不再设置这些项。用户如果依赖这些配置 key 进行自定义逻辑(如热更新)将不再工作。但通过 kv_connector_extra_config 传递的已有配置会被保留,影响范围可控。
  • 测试模拟开销:测试中使用 monkeypatch 阻止导入 lmcache,但如果未来 KVConnectorFactory._registry 的接口变更,测试可能悄悄失效。不过这是常见的 mock 做法,风险很低。
  • 用户影响:所有使用 --kv-offloading-backend lmcache 的用户都需要运行 LMCache 服务器。kv_offloading_size 参数仍然需要设置以激活 offloading,但其具体值不再影响连接器配置;用户如果想控制容量需要在服务器侧设定。
  • 系统影响:vLLM 进程内不再承载 LMCache 的 CPU 缓存管理,减轻了进程的资源压力,但也增加了进程间通信的延迟。
  • 团队影响:vLLM 团队需与 LMCache 团队保持接口兼容,并在文档中更新部署指南。当前已创建 LMCache 侧 PR 以提供恰当的错误信息。
外部服务依赖 配置向下不兼容 测试模拟开销

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论