概述#

LMCache MP 模式(多进程)将 LMCache 作为一个 独立服务 运行,vLLM 实例通过 ZMQ 连接到该服务。每个节点的 LMCache 服务器可以为多个 vLLM Pod 提供服务,提供进程隔离、共享缓存和独立资源扩展。

主要优势#

  • 进程隔离 -- LMCache 和 vLLM 在独立的进程(或容器)中运行,因此与缓存相关的问题不会导致推理引擎崩溃。

  • 推理路径上没有 GIL 争用或 Python 开销 -- 通过在单独的进程中运行 LMCache,它的 Python GIL 和 CPU 工作(哈希、内存管理、L2 I/O)不会与 vLLM 的推理线程竞争。

  • 跨 Pod 共享缓存 -- 同一节点上的多个 vLLM 实例共享一个 L1 缓存,最大化 KV 重用。

  • 独立资源扩展 -- 为缓存分配 CPU 内存,与用于推理的 GPU 显存独立。

  • 多层存储 (L1 + L2) -- L1 缓存(在 CPU DRAM 中,或通过 GPUDirect Storage 的 NVMe 块),由通过 NIXL(GDS、POSIX、HF3FS 等)的持久化 L2 存储提供支撑。

  • 内置可观察性 -- 开箱即用的 Prometheus 指标和遥测事件系统。

先决条件#

  • vLLM 建议使用最新版本以获得最佳兼容性

  • LMCache 最新开发分支

服务器变体#

LMCache 提供两个服务器入口点:

入口点

描述

lmcache server

推荐。 ZMQ + FastAPI HTTP 前端 — 参见 HTTP API

python3 -m lmcache.v1.multiprocess.server

(旧版)仅支持 ZMQ 的服务器,没有 HTTP 端点;与 lmcache server 相同的 --engine-type / --supported-transfer-mode 标志。建议使用 lmcache server

以下部分介绍 LMCache MP 模式的内部实现,适合希望了解、调试或扩展该系统的读者。

高层架构#

vLLM Instance(s)
     |
     | ZMQ (tcp)
     v
MessageQueueServer (mq.py)
     |
     | dispatch by RequestType
     v
MPCacheServer (server.py)
     |
     |--- TokenHasher / SessionManager
     |
     v
StorageManager (distributed/storage_manager.py)
     |
     |--- L1Manager (l1_manager.py)
     |       |--- L1MemoryManager (CPU DRAM) or
     |       |    GDSL1MemoryManager (NVMe slab via cuFile)
     |       |--- TTLLock per object (read/write)
     |
     |--- StoreController  -----> L2 Adapter(s) (async L1->L2 push)
     |--- PrefetchController ---> L2 Adapter(s) (async L2->L1 load)
     |--- EvictionController ----> L1Manager (watermark-triggered eviction)
     |
     v
EventBus + OTel providers (observability)

引擎和模块#

All server entry points share the same MPCacheServer and StorageManager core. MPCacheServer is now a thin compositor: it holds an MPCacheServerContext and a list of EngineModule instances assembled by _build_modules() (in server.py) based on --engine-type and --supported-transfer-mode.

``server.py`` -- 默认的纯 ZMQ 服务器。创建 MPCacheServer,组装引擎模块(LookupModule + ManagementModule + LMCacheDrivenTransferModule 和/或 EngineDrivenTransferModule,具体取决于 --supported-transfer-modelmcache_drivenengine_driven 仅加载其中一个,auto(默认)两者均加载 — 当设置了 --engine-type 时,还会附加 CacheBlend 模块:blend 附加 BlendV3Module(当前的分页感知实现),blend_legacy 附加 BlendModule(原始实现))。启动 MessageQueueServer,为已加载模块暴露的每个 RequestType 注册处理程序,并在保活循环中阻塞。

``modules/blend.py`` -- 定义了 BlendModuleBlendEngineV2,它们添加了原始的 CacheBlend 操作(CB_REGISTER_KV_CACHE, CB_LOOKUP_PRE_COMPUTED, CB_STORE_PRE_COMPUTED, CB_RETRIEVE_PRE_COMPUTED, CB_STORE_FINAL 及其 V2 变体)。启用跨文档段落的非前缀 KV Cache 重用。通过将 --engine-type blend_legacy 传递给 lmcache server 进行选择。

``modules/blend_v3.py`` -- 定义了 BlendV3Module,这是一个分页感知的 CacheBlend V3 流水线,运行在稀疏预取路径上。新增了 V3 RPC(CB_REGISTER_ROPE_V3CB_UNREGISTER_ROPE_V3CB_RETRIEVE_PRE_COMPUTED_V3CB_UNIFIED_LOOKUP),并复用现有的 LMCacheDrivenTransferModuleLookupModule。通过向 lmcache server 传递 --engine-type blend 来启用。

两种 blend 变体都要求 --supported-transfer-modelmcache_drivenauto,当其为 engine_driven 时将拒绝加载。

``http_server.py`` -- 将 run_cache_server()(来自 server.py)封装为 FastAPI 应用。端点由 http_apis/ 下的模块提供,并通过 HTTPAPIRegistry 自动注册:GET /(基本存活检查)、GET /healthcheck(供 Kubernetes 探针使用)、POST /clear-cache(清除 L1 CPU 内存中的全部 KV Cache 数据)以及 GET /status(查看详细内部状态)。ZMQ 服务器在同一进程内运行,所有已配置的运行时插件在 FastAPI 启动期间由 MPRuntimePluginLauncher 拉起。

ZMQ 协议#

vLLM 和 LMCache 之间的通信使用 ZMQ(DEALER/ROUTER 模式)。

RequestType 枚举(在 protocols/base.py 中定义):

请求类型

处理程序类型

描述

REGISTER_KV_CACHE

同步

为 vLLM 实例注册 GPU KV Cache 张量。

UNREGISTER_KV_CACHE

同步

注销 KV Cache 张量。

REGISTER_KV_CACHE_ENGINE_DRIVEN_CONTEXT

同步

注册一个引擎驱动的 KV Cache 上下文(使用 PREPARE/COMMIT 传输路径的 CPU/加速器工作线程)。仅在 --supported-transfer-modeengine_drivenauto 时加载。当使用 SHM 路径时,返回一个 RegisterEngineDrivenContextResponse,携带 SHM 段名称和池大小(对于 pickle 路径为空)。

UNREGISTER_KV_CACHE_ENGINE_DRIVEN_CONTEXT

同步

注销引擎驱动的 KV Cache 上下文。

STORE

阻塞

将 KV Cache 块从 GPU 存储到 L1 (CPU)。基于 LMCache 的传输路径 (CUDA IPC);仅在 --supported-transfer-modelmcache_drivenauto 时加载。

RETRIEVE

阻塞

将 KV Cache 块从 L1 (CPU) 复制回 GPU。由 LMCache 驱动的传输路径 (CUDA IPC);仅在 --supported-transfer-modelmcache_drivenauto 时加载。

PREPARE_STORE

阻塞

(引擎驱动路径)工作线程请求服务器为一个键准备存储端传输状态。当 --supported-transfer-mode 设置为 engine_drivenauto 时加载。

COMMIT_STORE

阻塞

(引擎驱动路径)工作线程提交块的序列化字节(pickle 路径),或释放已准备好的共享内存槽(SHM 路径),以便服务器将数据持久化到 L1 存储。

PREPARE_RETRIEVE

阻塞

(引擎驱动路径)工作线程请求服务器为指定键准备检索负载。pickle 路径直接内联返回字节;SHM 路径返回槽位信息,供工作线程从共享内存中读取。

COMMIT_RETRIEVE

阻塞

(引擎驱动路径)工作线程确认检索完成,服务器随即释放底层读取锁并回收相关传输状态。

LOOKUP

阻塞

提交前缀查找;预取任务由 request_id 在服务器端跟踪。

QUERY_PREFETCH_STATUS

阻塞

通过 request_id 查询预取作业。当完成时返回已加载的块数,预取仍在进行中时返回 None

QUERY_PREFETCH_LOOKUP_HITS

阻塞

在预取完成之前,通过 request_id 查询查找阶段的命中块计数。当查找仍在运行时返回 None

FREE_LOOKUP_LOCKS

阻塞

从取消的查找中释放读取锁,而无需执行完整的检索。

END_SESSION

阻塞

移除已完成请求的会话状态。

CLEAR

阻塞

清除所有缓存数据。

GET_CHUNK_SIZE

同步

返回服务器的块大小。

PING

阻塞

存活 ping;处理程序始终返回 True

REPORT_BLOCK_ALLOCATION

阻塞

vLLM 调度器的即发即忘通道,用于向可观察性子系统上报 GPU 块分配事件。

NOOP

同步

调试心跳 -- 返回确认字符串。

CB_REGISTER_KV_CACHE

同步

(Blend) 注册 CacheBlend KV 缓冲区。

CB_UNREGISTER_KV_CACHE

同步

(Blend) 取消注册 CacheBlend KV 缓冲区。

CB_STORE_PRE_COMPUTED

阻塞

(Blend)存储预计算的段落块。

CB_LOOKUP_PRE_COMPUTED

阻塞

(Blend) 查找预计算段块。

CB_RETRIEVE_PRE_COMPUTED

阻塞

(Blend) 将预计算的段落块检索到 GPU。

CB_STORE_FINAL

阻塞

(Blend) 存储最终混合块。

CB_LOOKUP_PRE_COMPUTED_V2

阻塞

(Blend V2)查找预计算块;返回 CBMatchResult 条目(包含旧范围/当前范围和每块哈希),以便检索步骤可以跳过重新哈希。

CB_RETRIEVE_PRE_COMPUTED_V2

阻塞

(Blend V2)使用 CB_LOOKUP_PRE_COMPUTED_V2 返回的 CBMatchResult 列表检索预计算的块。

CB_REGISTER_ROPE_V3

同步

(Blend V3) 将 RoPE cos/sin 缓存共享到已经通过 REGISTER_KV_CACHE 注册的上下文中。

CB_UNREGISTER_ROPE_V3

同步

(Blend V3) 丢弃 RoPE 状态(分页 KV Cache 仍然存在;使用 UNREGISTER_KV_CACHE 来释放它)。

CB_RETRIEVE_PRE_COMPUTED_V3

阻塞

(Blend V3)将所有匹配的块(前缀命中和非前缀命中)按各 token 块 ID 分散写入分页 KV;仅对发生偏移的子集重新应用 RoPE。

CB_UNIFIED_LOOKUP

阻塞

(Blend V3)唯一的实时查找路径:单次 RPC 同时执行前缀匹配和非前缀匹配,完成协调后发起一次稀疏合并预取,并按 TP rank 进行分类。返回 CBUnifiedLookupResult(预取仍在进行时返回 None)。

P2P_LOOKUP_AND_LOCK

阻塞

(P2P) Look up the given keys and read-lock the locally cached prefix. Returns a task id which the caller passes to P2P_QUERY_LOOKUP_RESULTS to poll for the transfer addresses. Part of the peer-to-peer KV cache sharing surface; the handler module is not yet wired into the default _build_modules() path -- see P2P KV 缓存共享.

P2P_QUERY_LOOKUP_RESULTS

阻塞

(P2P) Poll the transfer addresses for a lookup task. Returns a list of TransferChannelAddress once the lookup is complete, or None while the lookup is still in progress or its results have already been consumed.

P2P_UNLOCK_OBJECTS

阻塞

(P2P) Release the read locks previously taken by P2P_LOOKUP_AND_LOCK on the given keys.

处理程序类型:

  • SYNC -- 直接在 ZMQ 主循环中运行(快速,非阻塞)。

  • BLOCKING -- 分发到线程池执行(可能涉及 GPU 拷贝或 I/O)。

配置系统#

每个配置模块都暴露一个可组合的三元组:

(DataclassConfig, add_*_args(parser), parse_args_to_*_config(args))

server.py:parse_args() 组合它们:

parser = argparse.ArgumentParser(...)
add_mp_server_args(parser)        # from multiprocess/config.py
                                  # includes runtime-plugin args
                                  # (--runtime-plugin-locations,
                                  #  --runtime-plugin-config)
add_storage_manager_args(parser)  # from distributed/config.py
  # which internally calls add_l2_adapters_args(parser)
add_observability_args(parser)    # from mp_observability/config.py

http_server.py 复用该模式,为 lmcache server CLI 额外添加了 add_http_frontend_args()add_coordinator_args()。CacheBlend 不再作为独立入口点,而是在运行时通过向 server.py(或 lmcache server)传递 --engine-type 来启用:--engine-type blend 附加 BlendV3Module(当前的分页感知实现),--engine-type blend_legacy 附加 BlendModule(原始实现)。

分布式存储#

StorageManager#

lmcache/v1/distributed/storage_manager.py

将 L1、L2 和所有控制器连接在一起的顶级管理器。关键方法:

  • reserve_write() / finish_write() -- 对 L1 的两阶段写入。

  • submit_prefetch_task() / query_prefetch_status() -- 异步查找 + L2 预取。

  • read_prefetched_results() / finish_read_prefetched() -- 从 L1 读取预取的数据,并自动管理锁。

L1Manager#

lmcache/v1/distributed/l1_manager.py

在 CPU 内存中使用状态机管理对象:

None --> write_locked --> ready --> read_locked
          (reserve_write)  (finish_write)  (reserve_read)
                              |                |
                              v                v
                           evictable      finish_read -> ready

每个对象都有两个 TTLLock 实例(读和写),并具有可配置的超时,以防止因崩溃的客户端导致的死锁。

底层内存分配由在启动时选择的两个可互换层之一处理(两者都满足 L1ManagerProtocol):

  • L1MemoryManager(默认)-- 固定 CPU DRAM,按需惰性增长至 --l1-size-gb

  • GDSL1MemoryManager -- 当设置了 --gds-l1-path 时,使用 NVMe slab 文件作为存储介质。数据字节驻留在磁盘上;读写操作通过 cuFile 在 GPU 暂存缓冲区与 slab 之间直接进行 DMA,由进程全局的 GDSContextgpu_connector/gds_context.py)驱动,并从 gpu_ops 分发。在此模式下,CPU 层被禁用。

L2 适配器#

lmcache/v1/distributed/l2_adapters/

L2AdapterInterface(在 base.py 中)定义了三个异步任务方法:

  • submit_store_task(key, data) -- 将数据推送到 L2。

  • submit_lookup_and_lock_task(keys) -- 检查键是否存在于 L2 中。

  • submit_load_task(keys, layout_desc) -- 从 L2 加载数据到 L1。

工厂函数 create_l2_adapter()(位于 __init__.py)通过对配置类型执行 isinstance() 检查,实例化对应的适配器。

新适配器类型通过 register_l2_adapter_type()config.py 中注册。

控制器#

StoreController (storage_controllers/store_controller.py):事件驱动的后台线程,使用 select.poll() 监听 listener eventfd 和各适配器的存储 eventfd。当 L1 中出现新对象(通过 StoreListener 发信号)时,根据 StorePolicy 向每个 L2 适配器提交异步存储任务。

EvictionController (storage_controllers/eviction_controller.py):定期将 L1 内存用量与水位线阈值进行比较。触发后,使用配置的策略(LRUIsolatedLRUnoop)逐出对象,直至用量降到目标以下。IsolatedLRUcache_salt 维度逐出,配额上限由 /quota HTTP 端点注册;参见 Quota Management

PrefetchController (storage_controllers/prefetch_controller.py):处理 StorageManagerLOOKUP RPC 期间提交的 L2 查找和加载请求。当键不在 L1 中时,查询 L2 适配器并将命中的数据加载回 L1。

请求流#

查找流程#

vLLM                MPCacheServer          StorageManager         L1Manager       L2 (PrefetchController)
 |                       |                       |                    |                    |
 |---LOOKUP(key)-------->|                       |                    |                    |
 |                       |--submit_prefetch------>|                    |                    |
 |                       |                       |--reserve_read----->|                    |
 |                       |                       |<--hit_count--------|                    |
 |                       |                       |--submit_prefetch_request--------------->|
 |                       |                       |    (remaining keys)                     |
 |                       |--query_prefetch------->|                    |                    |
 |                       |                       |--query_prefetch_result----------------->|
 |                       |<--found_count----------|                    |                    |
 |<--found_count---------|                       |                    |                    |

存储流程#

vLLM                MPCacheServer          StorageManager         L1Manager
 |                       |                       |                    |
 |---STORE(key,blocks)-->|                       |                    |
 |                       |--reserve_write-------->|                    |
 |                       |                       |--reserve_write---->|
 |                       |                       |<--memory_objs------|
 |                       |  (GPU->CPU copy)      |                    |
 |                       |--finish_write--------->|                    |
 |                       |                       |--finish_write----->|
 |                       |                       |                    |
 |                       |                       |  [StoreController detects new objects]
 |                       |                       |  [async L1->L2 push via adapters]
 |<--event_handle--------|                       |                    |

获取流程#

vLLM                MPCacheServer          StorageManager         L1Manager
 |                       |                       |                    |
 |---RETRIEVE(key)------>|                       |                    |
 |                       |--read_prefetched------>|                    |
 |                       |                       |--unsafe_read------>|
 |                       |                       |<--memory_objs------|
 |                       |  (CPU->GPU copy)      |                    |
 |                       |--finish_read_prefetch->|                    |
 |                       |                       |--finish_read------>|
 |<--event_handle--------|                       |                    |

可观察性内部实现#

EventBus (lmcache/v1/mp_observability/event_bus.py) 是一个全局单例,在服务器启动时由 init_observability() 初始化。生产者(L1Manager、StorageManager、MPCacheServer)将 Event 对象发布到有界队列(--event-bus-queue-size,默认 10000,溢出时尾部丢弃)。一个后台排空线程(drain thread)将每个事件分发给所有已注册的订阅者。

订阅者 位于 lmcache/v1/mp_observability/subscribers/ 下,按关注点分组:metrics/(OTel 计数器和生命周期直方图)、logging/(Python 日志处理器、查找哈希 JSONL)以及 tracing/(由 START/END 事件对构建的 OTel span)。init_observability() 根据 CLI 标志(--disable-metrics--disable-logging--enable-tracing)注册相应的订阅者集合。

OTel 提供者在构造订阅者之前通过 otel_init.py 完成初始化,确保模块级的 get_meter() / get_tracer() 调用绑定到真实的提供者。指标同时导出到进程内的 Prometheus /metrics 端点(--prometheus-port,默认 9090),并在设置了 --otlp-endpoint 时推送到 OTel 收集器。

如何扩展#

添加新的 L2 适配器#

lmcache/v1/distributed/l2_adapters/ 下创建一个新的 *_l2_adapter.py 模块 — __init__.py 会通过 pkgutil 自动发现匹配该后缀的模块,并在首次使用时惰性导入,无需修改其他文件。

  1. 创建一个配置类,继承自 L2AdapterConfigBase,并实现 from_dict()help() 方法。

  2. 创建一个实现 L2AdapterInterface 的适配器类,以及一个小型工厂函数 (config, l1_memory_desc) -> L2AdapterInterface

  3. 在模块级别,自注册配置和工厂:

    register_l2_adapter_type("my_adapter", MyAdapterConfig)
    register_l2_adapter_factory("my_adapter", _create_my_adapter)
    

请参阅 mock_l2_adapter.pys3_l2_adapter.py 以获取参考实现。

添加可观察性订阅者#

  1. 创建一个继承自 EventSubscriber 的订阅者类(定义在 lmcache/v1/mp_observability/event_bus.py 中):实现 get_subscriptions() 以返回 {EventType: callback} 映射;可选地重写 shutdown() 以进行清理。

  2. 将类放置在对应的关注组(subscribers/metrics/subscribers/logging/subscribers/tracing/)下,并从该包的 __init__.py 中导出。

  3. init_observability()lmcache/v1/mp_observability/config.py)中,通过 bus.register_subscriber(...) 在与其关注点(metrics / logging / tracing)匹配的分支内注册订阅者,如有需要可受相应 CLI 标志控制。

添加新的请求类型#

  1. protocols/base.py 中向 RequestType 添加一个新成员。

  2. 在适当的 protocols/*.py 文件中创建一个 ProtocolDefinitionenginecontrollerobservabilitydebugblendblend_v2blend_v3),并将请求名称添加到该模块的 REQUEST_NAMES 中。

  3. 在适当的 EngineModule 上实现处理程序方法(例如 LookupModuleLMCacheDrivenTransferModuleBlendV3Module),并将其作为该模块的 get_handlers() 中的 HandlerSpec 公开。

  4. run_cache_server() 通过 add_handler_helper() 注册各已加载模块返回的每一个 HandlerSpec,无需手动注册。

关键源文件#

文件

目的

lmcache/v1/multiprocess/server.py

MPCacheServer + ZMQ 服务器入口点

lmcache/v1/multiprocess/config.py

MPServerConfig, HTTPFrontendConfig

lmcache/v1/multiprocess/engine_context.py

MPCacheServerContext(传递给每个 EngineModule 的共享状态)

lmcache/v1/multiprocess/engine_module.py

EngineModule 协议, HandlerSpecThreadPoolType(每个模块的处理程序注册)

lmcache/v1/multiprocess/modules/

引擎模块实现:lookup.py (LookupModule)、management.py (ManagementModule)、lmcache_driven_transfer.py (LMCacheDrivenTransferModule)、engine_driven_transfer.py (EngineDrivenTransferModule)、blend.pyBlendModule / BlendEngineV2,由 --engine-type blend_legacy 选择),以及 blend_v3.pyBlendV3Module,由 --engine-type blend 选择的分页感知 CacheBlend V3 流水线)。

lmcache/v1/multiprocess/http_server.py

带健康检查和许多其他有用 API 的 FastAPI 包装器

lmcache/v1/multiprocess/http_api_registry.py

HTTPAPIRegistry 会自动发现 http_apis/ 中的路由器

lmcache/v1/multiprocess/http_apis/

可扩展的 HTTP 端点 (/, /healthcheck, /clear-cache, /status)

lmcache/v1/multiprocess/mp_runtime_plugin_launcher.py

MPRuntimePluginLauncher 通过将完整的服务器配置序列化为环境变量来生成运行时插件

lmcache/v1/multiprocess/protocols/base.py

请求类型,处理程序类型,协议定义

lmcache/v1/distributed/storage_manager.py

存储管理器(顶级管理器)

lmcache/v1/distributed/config.py

StorageManagerConfig 层次结构

lmcache/v1/distributed/l1_manager.py

L1Manager(对象状态机)

lmcache/v1/distributed/l2_adapters/config.py

L2 适配器配置注册表

lmcache/v1/distributed/l2_adapters/base.py

L2AdapterInterface

lmcache/v1/distributed/storage_controllers/store_controller.py

StoreController(事件驱动 L1->L2)

lmcache/v1/distributed/storage_controllers/eviction_controller.py

逐出控制器(基于水印触发)

lmcache/v1/distributed/storage_controllers/prefetch_controller.py

PrefetchController (L2->L1 未命中时)

lmcache/v1/mp_observability/config.py

可观察性配置 + init_observability() 入口点

lmcache/v1/mp_observability/event_bus.py

事件总线单例和 EventSubscriber 基类

lmcache/v1/mp_observability/event.py

Event / EventType 定义

lmcache/v1/mp_observability/otel_init.py

OTel 指标 / 跟踪提供程序设置

lmcache/v1/mp_observability/subscribers/

指标、日志和追踪订阅者

lmcache/v1/mp_observability/trace/

追踪记录 (--trace-level storage) 捕获堆栈