ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

vLLM 分离式 Prefill/Decode 部署实战:XpYd 代理、多轮 KV 复用与 KV Cache 事件发布

vLLM 分离式 Prefill/Decode 部署实战:XpYd 代理、多轮 KV 复用与 KV Cache 事件发布 vLLM 分离式 Prefill/Decode 部署实战XpYd 代理、多轮 KV 复用与 KV Cache 事件发布【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm本文围绕 disaggregated_serving 示例目录 展开讲解 vLLM 的 Disaggregated ServingPrefill/Decode 分离部署能力从最经典的 XpYdX 个 Prefill 实例 Y 个 Decode 实例拉取模式代理到双向 KV 传输的多轮对话代理、Push 模式代理再到 KV cache 事件的 ZMQ 发布与订阅。读完本文你可以直接复制仓库中的脚本搭建一套 P/D 分离的推理集群并理解代理如何转发kv_transfer_params完成跨实例 KV cache 迁移。示例目录概览examples/disaggregated/disaggregated_serving/README.md 说明该目录包含演示 vLLM disaggregated serving 特性的脚本。README 中列出的核心文件如下文件作用disagg_proxy_demo.py演示 XpYdX 个 prefill 实例、Y 个 decode 实例的拉取模式代理kv_events.sh演示 KV cache 事件发布KV cache event publishingmooncake_connectorMooncakeConnector 的代理演示位于相邻的mooncake_connector目录此外当前仓库中该目录还包含以下未在 README 中列出的补充脚本可以推断是后续迭代加入的disagg_proxy_multiturn.py支持双向 KV 传输的多轮对话代理让每一轮复用上一轮 Decode 节点上的 KV 块disagg_proxy_pushconnector_demo.py与拉取模式配套的 Push 模式代理演示moriio_toy_proxy_server.pyMoRI-IO P/D 分离的单节点协议参考代理。XpYd 拉取模式代理disagg_proxy_demo.py这是分离式部署最典型的形态启动多个 vLLM 实例示例中 2 个 prefill 2 个 decode再启动代理进行统一路由。文件头部 docstring 给出的启动方式为python3 examples/disaggregated/disaggregated_serving/disagg_proxy_demo.py \ --model $model_name \ --prefill localhost:8100 localhost:8101 \ --decode localhost:8200 localhost:8201 \ --port 8000命令行参数parse_argsdisagg_proxy_demo.py#L419-L446定义了四个参数参数缩写说明--model/-m必填模型名用于启动时校验各实例服务的模型是否一致--prefill/-p多个Prefill 节点 URL 列表host:port--decode/-d多个Decode 节点 URL 列表host:port--port默认 8000代理自身监听端口启动时ProxyServer.validate_parsed_serve_args会强制要求 prefill、decode 节点各至少一个并逐一校验实例地址格式host 为 IP 或localhost端口在 1~65535 之间随后调用verify_model_config请求每个实例的/v1/models比对模型名后缀是否一致不一致则直接抛错——这避免了 P/D 节点模型错位导致的隐性故障。两阶段请求转发代理对/v1/completions与/v1/chat/completions均执行同样的两段式转发以create_completion为例见 disagg_proxy_demo.py#L250-L278Prefill 阶段复制一份请求并将max_tokens改写为 1chat 接口同时改写max_completion_tokens转发给轮询选中的 prefill 实例。该实例只完成提示词的 KV 计算产出 token 被丢弃Decode 阶段将原始请求转发给轮询选中的 decode 实例以StreamingResponse流式返回给客户端。KV 数据的实际迁移由 P/D 两侧引擎通过 KV connector 完成代理只负责编排两次 HTTP 调用。调度策略由SchedulingPolicy抽象类定义默认实现RoundRobinSchedulingPolicy基于itertools.cycle做轮询上游连接失败时forward_request抛出HTTPException代理会调用remove_instance_endpoint将故障实例摘除并重建 cycler实现简单的故障剔除。代理的 HTTP 接口setup_routesdisagg_proxy_demo.py#L67-L85注册了四个路由POST /v1/completions、POST /v1/chat/completions客户端入口均要求Content-Type: application/json否则返回 415GET /status返回 prefill/decode 节点数量与地址列表可用于运维监控POST /instances/add运行时动态扩容节点需要X-API-Key请求头且服务端设置了ADMIN_API_KEY环境变量请求体形如{type: prefill, instance: host:port}代理会先通过/v1/models校验模型一致后再加入实例池。需要注意 docstring 中的一段说明该 demo 计划在内置 PDController 支持 XpYd 之后移除因此它定位是协议演示而非生产级路由组件。多轮对话的双向 KV 传输disagg_proxy_multiturn.py多轮聊天场景下第一轮结束后 KV 块留在 Decode 节点上如果第二轮重新走 Prefill 重算会浪费大量计算。disagg_proxy_multiturn.py 头部 docstring 给出了其架构与请求流Client ──► Proxy ──► Prefill (P) ──► Decode (D)每个请求的处理流程为客户端向代理发送 chat/completions 请求代理按conversation_id查询上一轮缓存的 D 节点块信息命中缓存时代理把 D 的块信息附到请求上让 P 直接读取 D 上的 KV 块而不是重算代理将请求发给 Pmax_tokens1非流式P 返回携带自身块信息的kv_transfer_params代理将请求和 P 的块信息转发给 D流式D 流式返回响应最后一个 chunk 中包含 D 的kv_transfer_params代理将其缓存供下一轮使用。其中conversation_id是请求 JSON 顶层的非标准扩展字段用于跨轮次关联同一个会话缺少该字段时代理无法串联轮次会退化为无缓存行为。docstring 同时提醒严格的 OpenAI 兼容前端会拒绝未知字段因此该字段只被代理消费、不会转发给 vLLM 引擎。Push 模式代理disagg_proxy_pushconnector_demo.pydisagg_proxy_pushconnector_demo.py 是拉取模式的“孪生”演示客户端侧 API 完全相同区别在于 P/D 之间 KV 传输的协调方向见其头部 docstringPull 模式disagg_proxy_demo.py代理把 P 的kv_transfer_params含remote_block_ids转发给 D由 D 通过 NIXL READ 主动从 P 拉取 KVPush 模式代理只把 P 的坐标remote_engine_id、remote_host、remote_port、tp_size、pp_size和共享的remote_request_id交给 DD 先通过 NIXL 通知向 P 注册自己本地分配的块随后由 P 通过 NIXL WRITE 把 KV 推给 D。Push 模式下 vLLM 实例需配置NixlPushConnector以及匹配的engine_id/side_channel_port代理的启动命令比 Pull 模式多了 P 侧坐标参数python3 examples/disaggregated/disaggregated_serving/\ disagg_proxy_pushconnector_demo.py \ --model $model_name \ --prefill localhost:8100 \ --decode localhost:8200 \ --prefill-engine-id prefill-engine-001 \ --prefill-kv-host 10.0.0.1 \ --prefill-side-channel-port 5600 \ --prefill-tp-size 1 \ --prefill-pp-size 1 \ --port 8000KV Cache 事件发布kv_events.shkv_events.sh 演示引擎对外发布 KV cache 事件的完整链路。脚本开头即声明该功能为实验特性The usage of KV cache events is experimental and subject to change。服务端配置脚本通过环境变量HF_MODEL_NAME默认meta-llama/Meta-Llama-3.1-8B-Instruct确定模型并设置VLLM_HOST_IP为机器第一个 IP。核心是带--kv-events-config的启动命令kv_events.sh#L37-L44vllm serve $MODEL_NAME \ --port 8100 \ --max-model-len 100 \ --enforce-eager \ --gpu-memory-utilization 0.8 \ --trust-remote-code \ --kv-events-config \ {enable_kv_cache_events: true, publisher: zmq, topic: kv-events}其中--kv-events-config是一个 JSON 配置enable_kv_cache_events开启事件发布publisher指定发布通道为 ZMQtopic为订阅主题名kv-events。脚本随后用wait_for_server轮询/v1/completions直到服务就绪超时 1200 秒再启动订阅者最后发送两条示例请求触发事件并打印两次 completions 的响应。需要注意一个路径细节脚本按$SCRIPT_DIR/kv_events_subscriber.py定位订阅者即期望它与kv_events.sh位于同一目录而当前仓库中该文件实际位于 examples/features/kv_events/kv_events_subscriber.py运行前需将其放到kv_events.sh所在目录或将路径改为指向 features 目录否则订阅进程无法启动。订阅者实现要点kv_events_subscriber.py 展示了事件消费端的标准写法消息类型使用msgspec定义KVEventBatch含时间戳ts与事件列表事件包括BlockStored新增块携带block_hashes、parent_block_hash、token_ids、block_size等字段块哈希类型来自 vllm/v1/core/kv_cache_utils.py 的ExternalBlockHash、BlockRemoved块被逐出与AllBlocksCleared缓存清空双通道 ZMQ主通道为 SUB socket连接tcp://localhost:5557并订阅kv-events主题另外用 REQ socket 连接tcp://localhost:5558作为重放replay通道断流补齐每条消息携带 8 字节大端序列号若发现seq last_seq 1说明有消息丢失订阅者会向 replay 通道请求从last_seq 1开始补齐直到序列号追平重放结束以空 payload 帧标记——这让外部系统可以基于事件流重建 KV 块状态的完整视图。这类事件对上层调度系统很有价值路由/缓存感知组件可以据此掌握各实例上 KV 块的分布为跨实例前缀复用提供依据。MoRI-IO 单节点参考代理moriio_toy_proxy_server.pymoriio_toy_proxy_server.py 是 MoRI-IO 分离式部署的最小单节点参考代理。docstring 明确其定位与边界它演示 connector 期望的DP rank 固定pinning契约每个请求选定一个 prefill DP rankflat_interleaved_dp_route并通过X-data-parallel-rank请求头加上kv_transfer_params中的remote_dp_rank/remote_dp_size/remote_tp_size把请求的两段P 与 D都固定到该 rank 上它有意不提供跨 Pod 的 Wide-EP如 2P2D对等节点信息remote_hosts、multi_pod_hosts、data_parallel_size_local、is_request_leader等。生产级多 Pod 部署中这些信息通常由路由 sidecar如 llm-d-router 或 NIXL 形态的路由器生成因此该文件应作为协议参考使用而不是生产路由器。小结与适用建议理解 P/D 分离的代理层协议、kv_transfer_params的流转方式从disagg_proxy_demo.py入手最直接需要多轮会话复用 Decode 侧 KV 时参考disagg_proxy_multiturn.py的双向传输与conversation_id设计评估 Push 模式P 侧主动 NIXL WRITE时使用disagg_proxy_pushconnector_demo.py并配置NixlPushConnector构建缓存感知的外部调度/路由系统时kv_events.sh 订阅者是完整的 ZMQ 事件链路范例注意其实验状态更完整的分离式部署形态如 LMCache 集成、NIXL connector 的 prefill/decode 独立脚本、encoder 分离等可继续参考 examples/disaggregated/lmcache/、examples/disaggregated/example_connector/ 与 examples/disaggregated/disaggregated_encoder/。以上脚本均为示例级实现轮询调度、单进程状态、内存中的会话缓存等设计决定了它们适合验证协议与拓扑生产环境应结合仓库中正式的 KV connector 实现与外部路由组件评估使用。【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表