Source-backed architecture guide

EPD / Disaggregated Encoder:把多模态 Encoder 从 Prefill/Decode 中拆出来

vLLM 的 EPD 路径把视觉/音频 encoder 输出变成可跨进程复用的 Encoder Cache(EC)。 Encoder 实例只负责生产 EC,PD 或 P/D 实例按 mm_hash 命中并加载 EC,然后继续语言模型 prefill/decode。 当前代码主干来自 vllm#25233vllm#44049 是后续共享内存和资源回收增强,尚未出现在本次源码快照里。

Repo: vllm-project/vllm Commit: ad7125a V1 runner only 当前 connector: ECExampleConnector
分离

Encoder-only 实例

生产者实例只跑 multimodal encoder,不初始化语言模型 KV cache。代码中 get_kv_cache_spec() 在非 consumer EC transfer 下返回空。

桥接

EC Connector

connector 把 scheduler 的“命中/计划”与 worker 的“加载/保存”分开。当前本地实现是 ECExampleConnector,用共享目录保存 safetensors。

调度

compute vs load

PD scheduler 先查本地 encoder cache,再查外部 EC。外部命中时只安排加载,不把该 MM input 放进 scheduled_encoder_inputs

演进

SHM 后续增强

#44049 增加共享内存 connector、ACK 和独立容量管理,目标是降低磁盘 I/O,并让外部缓存释放成为 scheduler 闭环。

系统拓扑

EPD 不是单个 vLLM server 自动拆分,而是由示例 proxy 组织多个 OpenAI-compatible vLLM 实例。 proxy 负责先触发 encoder primer 请求,再把原始请求转发给 PD 或 P/D。

Client

  • OpenAI chat/completions
  • 文本 + image/audio
  • 可 stream 或 non-stream

EPD Proxy

  • 提取所有 MM item
  • 为每个 item 构造 primer
  • fanout 到 encoder cluster
  • 再转发原请求到 PD/P/D
↘︎
↗︎

Encoder vLLM

  • ec_role=ec_producer
  • 只执行 multimodal encoder
  • 保存 encoder_cache[mm_hash]

EC Connector Store

  • 当前:共享目录 + safetensors
  • 索引:mm_hash
  • 后续:SHM / NIXL / RDMA 方向

PD / Prefill / Decode

  • ec_role=ec_consumer
  • scheduler 命中外部 EC
  • worker load 到本地 encoder cache
  • P/D 分离时再走 KV connector

端到端请求流

1
Proxy 提取 multimodal itemextract_mm_items 扫描 messages,把 image/audio/input_audio 收集出来。
2
Proxy fanout encoder primerfanout_encoder_primer 为每个 MM item 构造只含媒体、max_tokens=1 的请求,发给 encoder cluster。
3
Encoder scheduler 选择本地计算encoder producer 没有外部命中需求,正常把 MM input 放入 scheduled_encoder_inputs,worker 执行 multimodal encoder。
4
Encoder worker 保存 ECMM encoder 输出进入 encoder_cache[mm_hash],随后 maybe_save_ec_to_connector 调用 connector 的 save_caches
5
Proxy 转发原请求到 PD 或 P/Dnon-stream 路径见 forward_non_stream,stream 路径类似。
6
PD scheduler 命中外部 EC_try_schedule_encoder_inputs 中,若 ec_connector.has_cache_item(mm_hash) 为真,加入 external_load_encoder_input
7
Scheduler 生成 metadatabuild_connector_meta 生成 ec_connector_metadata,挂到 SchedulerOutput
8
PD worker 预加载 ECECConnectorModelRunnerMixin 绑定 metadata,consumer 调用 start_load_caches,随后 _gather_mm_embeddings 使用本地 encoder cache。

功能模块与源码入口

层次 职责 关键源码 阅读要点
配置层 声明 EC connector、角色、connector 额外参数。 ECTransferConfig ec_producer 只生产;ec_consumer 只消费;ec_both 同时具备生产/消费语义。
抽象层 把 scheduler 侧计划和 worker 侧数据搬运分离。 ECConnectorBase has_cache_itemupdate_state_after_allocbuild_connector_metastart_load_cachessave_caches
connector 实现 当前本地代码用共享目录保存/加载 safetensors。 ECExampleConnector 保存路径是 shared_storage_path/mm_hash/encoder_cache.safetensors
调度层 决定 MM encoder output 是本地计算、复用本地 cache,还是从外部 EC 加载。 _try_schedule_encoder_inputs 外部命中会分配本地 encoder cache slot,但不会加入 scheduled_encoder_inputs
输出协议 把 EC metadata 从 scheduler 带到 worker。 SchedulerOutput.ec_connector_metadata metadata 是 connector 自定义结构,当前为 ECExampleConnectorMetadata.mm_datas
执行层 执行前 load EC,执行后 save EC,并把结果回传。 ECConnectorModelRunnerMixin context manager 是 EC 生命周期的中心。
模型 runner 在 MM embedding 构造前后嵌入 EC 逻辑;producer 可跳过 KV cache。 GPUModelRunner._preprocess consumer 路径 load + gather;producer 路径执行 encoder 后返回空输出。
部署入口 组织 E、PD、P、D 多个服务实例。 Proxy /v1/chat/completions vLLM 本体提供 EC 能力,服务拆分由 proxy 和启动脚本完成。

实现分支与 PR 对照

当前 checkout 的事实

当前代码已经包含 EPD 主体框架,但 connector 注册项只有 ECExampleConnector。 未发现 ECSharedMemoryConnectorECConnectorCacheManager 文件。

ECConnectorFactory.register_connector(
    "ECExampleConnector",
    "vllm.distributed.ec_transfer.ec_connector.example_connector",
    "ECExampleConnector",
)

当前传输模型

producer 将 EC tensor detach 到 CPU 后保存为 safetensors; consumer 根据 metadata 找到文件并 load 到当前平台设备。这个路径足够验证架构,但磁盘 I/O 会影响高并发 TTFT。

判断“当前代码支持什么”时,以源码为准:本地没有 SHM connector,文档和 PR 讨论中的 SHM 能力属于后续 PR 范围。

已合并 主体架构 PR

#25233 增加了 EC transfer 配置、EC connector 抽象、scheduler 外部 cache 命中逻辑、worker load/save 生命周期、proxy 示例和测试。

  • 让 encoder 实例和 PD 实例能通过 EC connector 共享 MM embeddings。
  • 让 producer 侧成为 encoder-only 执行路径,避免语言模型 KV cache 开销。
  • 让 PD scheduler 在外部命中时选择 load,而不是重算 encoder。

可记住的代码形状

if ec_connector.has_cache_item(mm_hash):
    external_load_encoder_input.append(i)
    continue

encoder_inputs_to_schedule.append(i)

这段分支就是 EPD 的调度本质:同一个 multimodal item,要么外部加载,要么本地计算。

Open 后续增强 PR

#44049 的目标是引入 ECSharedMemoryConnector 和 scheduler 侧 ECConnectorCacheManager。 这会把当前磁盘传输换成本机共享内存,并通过 ACK / unlink 管理物理缓存生命周期。

  • SHM segment 位于 /dev/shm,按 mm_hash 命名。
  • consumer 读完后写 ACK,producer 可观测发送完成。
  • scheduler 输出待释放的 EC connector mm_hash,worker 调用 free_physical_cache

它补的是哪块短板

当前本地 scheduler 没有消费 ECConnectorOutput.finished_sending/finished_recving 来驱动外部物理缓存回收。 #44049 正是在补“connector 外部存储容量管理”和“物理资源释放”这条闭环。

所以可以把 #44049 理解成:不改变 #25233 的 EPD 主架构,而是替换/增强 EC connector 后端和资源账本。

容易混淆点与当前边界

不是自动拆分

需要 proxy 和多实例启动

vLLM 内部提供 EC transfer 能力,但 E、PD、P、D 的服务编排由示例脚本和 proxy 完成。

V1 only

V2 runner 不支持 EC transfer

VLLM_USE_V2_MODEL_RUNNER 配置校验会把 EC transfer 加入 unsupported 列表。

当前后端

磁盘 connector 不是低延迟终点

本地实现是 safetensors 落盘。SHM/RDMA 等方向属于后续 connector 演进。

一句话判断当前路径: 如果实例是 ec_producer,它负责生成并保存 EC;如果实例是 ec_consumer,scheduler 会尽量从 EC connector 加载已有 embeddings,再继续语言模型路径。

源码阅读顺序

1. EC 配置 vllm/config/ec_transfer.py:角色、connector 名称、自定义配置。
2. Connector 基类 ec_connector/base.py:scheduler/worker 双角色接口。
3. 当前 connector example_connector.py:safetensors 保存、命中、加载。
4. Scheduler 分支 scheduler.py:本地 cache、外部 EC、重新计算三选一。
5. SchedulerOutput 协议 sched/output.pyec_connector_metadata 的传递点。
6. Worker lifecycle ec_connector_model_runner_mixin.py:绑定 metadata、load、save、finished。
7. GPU runner gpu_model_runner.py:EC context 嵌入 MM embeddings 构造前后。
8. Proxy 示例 disagg_epd_proxy.py:用户请求如何被拆成 encoder primer 和 PD/P/D 请求。

学习检查清单

问题 能回答时说明你读懂了
为什么 producer 不需要语言模型 KV cache? 因为它只执行 multimodal encoder,get_kv_cache_spec() 在非 consumer EC transfer 下返回空。
外部 EC 命中后,scheduler 还会分配本地 encoder cache 吗? 会。PD worker 最终仍要从本地 encoder_cache 取 embeddings,只是这些 embeddings 是 load 进来的,不是本地算出来的。
ec_connector_metadata 何时生成、何时消费? scheduler 每步 build;worker 的 EC context 在模型执行前 bind 并消费。
#44049 和 #25233 是替代关系吗? 不是。#25233 是主体架构;#44049 是 connector 后端和资源回收增强。