vLLM 数据并行部署实战指南:内部、混合与外部负载均衡三种拓扑
【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm
vLLM 的数据并行(Data Parallel, DP)部署允许将同一份模型权重复制到多组独立实例/GPU 上,各自处理互不重叠的请求批次,从而在吞吐敏感的场景下水平扩展服务能力。本篇结合 docs/serving/data_parallel_deployment.md 的官方部署说明与vllm/config、vllm/v1/engine中的源码实现,完整覆盖 DP 部署的进程架构、三种在线负载均衡模式(内部 LB、混合 LB、外部 LB)的命令行配置、多机部署与 Ray 后端的差异,以及离线(LLM类)用法,帮助你在单机、多机乃至 Kubernetes 环境下正确落地数据并行服务。
什么是 DP 部署:权重复制与请求批次切分
数据并行的核心思想是把模型权重完整复制到多个 DP rank 上,每个 rank 独立持有自己的 KV cache,并处理一批独立的请求。vLLM 同时支持稠密(dense)模型和 MoE 模型的 DP 部署,两者在行为上有本质区别:
- 稠密模型:各 DP rank 之间完全独立,没有任何跨 rank 的同步要求。对非 MoE 模型而言,外部负载平衡其实"退化"为启动多个彼此独立的 vLLM 实例即可。
- MoE 模型(尤其是 DeepSeek 这类采用 MLA,Multi-head Latent Attention 的模型):常见且高效的组合是注意力层走数据并行,专家层走专家并行(EP)或张量并行(TP)。此时各 DP rank 并不完全独立——前向传播必须对齐,即使某些 rank 当前没有请求,其专家层在每次前向中也必须参与同步,即执行"哑"前向(dummy forward pass)。
从源码结构看,这一对齐机制落在引擎核心循环中:vllm/v1/engine/core.py 显示,当某 rank 本轮没有就绪请求时(且引擎不处于休眠态),会执行execute_dummy_batch()补齐空批次;随后调用_has_global_unfinished_reqs()做 all-reduce 判断全局是否还有未完成的请求。该 all-reduce 做了优化,每 32 步才执行一次(见 vllm/v1/engine/core.py),以避免每步同步带来的开销。
默认情况下,MoE 的专家层会形成一个大小为DP × TP的张量并行组;如果想改用专家并行,需要在多机场景的所有节点上都加上--enable-expert-parallel参数。EP 模式下注意力层与专家层的行为差异可参考 docs/serving/expert_parallel_deployment.md。
进程架构:Core Engine、ZMQ 与 DP Coordinator
在 vLLM 的进程模型中,每个 DP rank 都部署为一个独立的 "core engine" 进程,通过 ZMQ socket 与前端(front-end)API server 进程通信。当 DP 与 TP 组合使用时,每个 DP 引擎还拥有与其 TP size 相等的每 GPU worker 进程。
支撑这套架构的关键组件是DP Coordinator进程,其实现位于 vllm/v1/engine/coordinator.py。根据源码中的类注释,它承担三类职责:
- 负载统计收集与发布:从各 DP 引擎收集统计信息(当前是 waiting 队列和 running 队列长度),并发布给所有前端进程用于负载平衡决策。
- 全局 "request wave" 状态跟踪:引擎在"全局运行/暂停"两种状态之间交替,wave 号是全体 worker 从运行态转入暂停态的累计次数,由 DP rank 0 引擎上报、经 Coordinator 广播。
- 广播
START_DP_WAVE消息:当某个引擎暂停时收到新请求,前端会同时通知 Coordinator,由它唤醒所有引擎进入运行态。
MoE 部署中"只要任一 rank 有请求在跑,其余空闲 rank 必须执行 dummy 前向"的语义正是由 Coordinator 与上述 all-reduce 共同保障的;当 all-reduce 确认所有 rank 都空闲后,引擎才会集体暂停以节省算力。
在在线(API server)部署中,各 DP 引擎的 KV cache 彼此独立,因此在 rank 间做负载均衡是有价值的——尤其是把共享前缀的 prompt 智能地路由到同一个 DP rank,以最大化 prefix caching 的收益。官方文档指出,当前的内部负载均衡基于各引擎的 running/waiting 队列,后续版本计划引入 KV cache 感知的路由逻辑。
内部负载均衡:单一 API 端点的自包含部署
内部 LB 模式下,vLLM 对外暴露单一 API 端点,所有 DP rank 的调度与路由都封装在 API server 进程内部,对客户端完全透明。
单机部署
只需在vllm serve命令中加入--data-parallel-size:
# DP=4,需要 4 张 GPU vllm serve $MODEL --data-parallel-size 4 # DP=4 × TP=2,需要 8 张 GPU vllm serve $MODEL --data-parallel-size 4 --tensor-parallel-size 2DP 可以与张量并行任意组合,所需 GPU 总数为DP × TP(再乘以 PP/PCP 等)。一个容易踩坑的细节:--max-num-seqs是按每个 DP rank 生效的,容量规划时要按 rank 数相乘计算全局并发上限。
多机部署(MP 后端)
跨多机运行单一 DP 部署时,需要在每个节点上各启动一个vllm serve,并指定该节点承载哪些 DP rank。此时仍然只有一个 HTTP 入口——API server 只在一个节点上运行,但它不一定与 DP rank 同机。
DP=4、TP=2,head 节点承载 rank 0/1,第二节点承载 rank 2/3:
# Node 0 (with ip address 10.99.48.128) vllm serve $MODEL --data-parallel-size 4 --data-parallel-size-local 2 \ --data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345 # Node 1 vllm serve $MODEL --headless --data-parallel-size 4 --data-parallel-size-local 2 \ --data-parallel-start-rank 2 \ --data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345DP=4,API server 全部放在第一节点、所有引擎放在第二节点(--data-parallel-size-local 0表示本节点不承载引擎):
# Node 0 (with ip address 10.99.48.128) vllm serve $MODEL --data-parallel-size 4 --data-parallel-size-local 0 \ --data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345 # Node 1 vllm serve $MODEL --headless --data-parallel-size 4 --data-parallel-size-local 4 \ --data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345相关参数在 vllm/config/parallel.py 的ParallelConfig中定义,关键默认值如下:
| 参数 | 含义 | 默认值(源码) |
|---|---|---|
--data-parallel-size | 全局 DP rank 总数 | 1 |
--data-parallel-size-local | 本节点承载的 rank 数,0 表示本节点只跑前端/协调 | 1(0 为哨兵值) |
--data-parallel-start-rank | 本节点首个 rank 的全局编号 | 推断 |
--data-parallel-address | 协调用 head 节点 IP(data_parallel_master_ip) | 127.0.0.1 |
--data-parallel-rpc-port | 各节点共享的 DP 通信端口 | 29550 |
--headless | 本节点不启动 API server | False |
注意--data-parallel-size-local与--data-parallel-size的一致性校验:__post_init__会校验data_parallel_size_local <= data_parallel_size(见 vllm/config/parallel.py),且--data-parallel-rank必须落在[0, data_parallel_size)区间内。
使用 Ray 作为 DP 后端
同一套内部 DP 模式也可以指定--data-parallel-backend=ray使用 Ray 来拉起所有 rank:
vllm serve $MODEL --data-parallel-size 4 --data-parallel-size-local 2 \ --data-parallel-backend=rayRay 后端与 MP 后端的显著差异:
- 只需任意一个节点上执行一条启动命令,即可拉起本地和远程的所有 DP rank,省去逐节点手动启动;
- 无需指定
--data-parallel-address(以命令所在节点为准),也无需--data-parallel-rpc-port; - 当单个 DP 组需要跨节点(即一份模型副本至少分布在两台机器上)时,必须设置环境变量
VLLM_RAY_DP_PACK_STRATEGY="span",此时--data-parallel-size-local会被忽略并自动推断。从源码看,该策略下data_parallel_size_local被强制置为 1(见 vllm/engine/arg_utils.py); - 远程 DP rank 按 Ray 集群的节点资源自动分配。
API server 横向扩展
大 DP 规模下,API server 进程本身可能成为瓶颈。正交的--api-server-count参数可以水平扩展 API server 进程数(例如--api-server-count=4),对用户完全透明——仍然只暴露单一 HTTP 端点/端口。需要注意这一扩展是"内部"的,仍被限制在 head 节点上。
混合负载均衡:节点内自治 + 节点间外部路由
混合 LB(hybrid load balancing)介于内部与外部模式之间:每个节点各自运行自己的 API server,只把请求路由给本节点上共置的 DP 引擎;跨节点的请求分布交给上游负载均衡器(ingress controller、流量路由器等)完成。
启用方式是在所有节点仍按全局 DP size 启动的前提下加上--data-parallel-hybrid-lb,与内部 LB 的关键区别:
- 必须提供
--data-parallel-size-local和--data-parallel-start-rank,让每个节点明确知道自己拥有哪些 rank; - 与
--headless不兼容,因为每个节点都要暴露 API 端点; --api-server-count需要按每个节点的本地 rank 数量来缩放。
从源码看,这一模式的判定逻辑在 vllm/engine/arg_utils.py:非 headless 节点一旦提供了--data-parallel-start-rank,就会自动推断启用 hybrid LB;如果data_parallel_size_local == 1则自动退化为纯外部 LB 并给出警告。混合模式的核心收益是每个节点保留本地调度决策,减少跨节点流量、避免大 DP 规模下单节点 API server 瓶颈。
外部负载均衡:把每个 DP rank 当作独立部署
面向更大规模的部署,把 DP rank 的编排与负载平衡完全外置往往更合理:把每个 DP rank 当作一个独立的 vLLM 部署(有自己的 endpoint),由外部路由器在各服务器之间分发 HTTP 请求,并可以利用各 server 的实时遥测做路由决策。
- 非 MoE 模型:直接启动若干互相独立的 vLLM 实例即可,不要附加任何
--data-parallel-*参数——外部 DP CLI 选项仅对 MoE 部署开放。这一点也有源码级校验:vllm/engine/arg_utils.py 中,若data_parallel_size > 1且处于外部 LB 模式但模型不是 MoE,会直接抛出Non-MoE models do not support external data parallel mode错误。 - MoE DP+EP 拓扑:通过
--data-parallel-rank等参数配置等价的外部拓扑(显式提供--data-parallel-rank会自动置位data_parallel_external_lb,见 vllm/config/parallel.py 的字段注释)。
DP rank 共置在同一节点(同 IP)时,使用默认 RPC 端口,但每个 rank 必须指定不同的 HTTP 端口:
# Rank 0 CUDA_VISIBLE_DEVICES=0 vllm serve $MODEL --data-parallel-size 2 --data-parallel-rank 0 \ --port 8000 # Rank 1 CUDA_VISIBLE_DEVICES=1 vllm serve $MODEL --data-parallel-size 2 --data-parallel-rank 1 \ --port 8001多机场景下,还必须额外指定 rank 0 的地址与端口:
# Rank 0 (with ip address 10.99.48.128) vllm serve $MODEL --data-parallel-size 2 --data-parallel-rank 0 \ --data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345 # Rank 1 vllm serve $MODEL --data-parallel-size 2 --data-parallel-rank 1 \ --data-parallel-address 10.99.48.128 --data-parallel-rpc-port 13345外部 LB 模式下 Coordinator 进程依然存在,与 DP rank 0 引擎共置。另外从源码看,故障容忍(fault tolerance)特性明确要求外部 LB 模式(--data-parallel-external-lb或--data-parallel-rank),内部 LB 模式不受支持(见 vllm/engine/arg_utils.py)。
上图中每个虚线框对应一次独立的vllm serve启动——在 Kubernetes 中,这通常就是独立的 Pod。
离线使用:LLM 类与 SPMD 环境
DP 部署不仅限于在线 API 服务,离线推理(LLM类)同样支持 DP+EP。官方示例 examples/features/data_parallel/data_parallel_offline.py 演示了完整用法:
# 单机 python examples/features/data_parallel/data_parallel_offline.py \ --model="ibm-research/PowerMoE-3b" -dp=2 -tp=2 # 多机 Node 0(ip 10.99.48.128) python examples/features/data_parallel/data_parallel_offline.py \ --model="ibm-research/PowerMoE-3b" -dp=2 -tp=2 \ --dp-num-nodes=2 --dp-node-rank=0 \ --dp-master-addr=10.99.48.128 --dp-master-port=13345 # 多机 Node 1 相同,仅 --dp-node-rank=1该脚本的实现要点:
- 每个 DP rank 运行在独立进程中,通过环境变量
VLLM_DP_RANK、VLLM_DP_RANK_LOCAL、VLLM_DP_SIZE、VLLM_DP_MASTER_IP、VLLM_DP_MASTER_PORT传递 rank 信息(见示例第 94–98 行); - 各 rank 处理数据集的不同分片,prompt 列表按 rank 均匀切分,若某 rank 分到的 prompt 为空则填入占位 prompt(DP 语义下各 rank 需要保持前向对齐);
- 各 rank 可以使用不同的 sampling params——示例中按 rank 奇偶设置不同的
max_tokens,说明 DP rank 间参数可以彼此独立。
选型建议与关键约束汇总
| 场景 | 推荐模式 | 关键点 |
|---|---|---|
| 单机,快速横向扩吞吐 | 内部 LB | --data-parallel-size=N,单一端点,最省事 |
| 多机,希望单一入口 | 内部 LB(MP 或 Ray 后端) | MP 需逐节点启动并指定--data-parallel-address/--data-parallel-rpc-port;Ray 一条命令拉起全局 |
| 多机,节点各自暴露端点 | 混合 LB | --data-parallel-hybrid-lb+--data-parallel-size-local+--data-parallel-start-rank,上游再路由跨节点流量 |
| 大规模、K8s 一 rank 一 Pod | 外部 LB(MoE 专属) | 每 rank 独立 endpoint + 独立端口,外部路由器 + 实时遥测决策 |
| 稠密模型大规模扩展 | 多个独立实例 | 不加任何--data-parallel-*参数,纯外部 LB |
| 离线批量推理 | LLM类 + SPMD 环境变量 | 参考离线示例脚本 |
几条硬约束值得在容量规划前牢记:
--max-num-seqs按 DP rank 计数,全局并发上限 =max_num_seqs × DP;- 内部/混合/外部三种 LB 模式互斥,hybrid 与 external 不能同时开启(vllm/engine/arg_utils.py 会直接报错),hybrid 也不兼容
--headless; - 外部 DP CLI 选项仅适用于 MoE 模型;
- Elastic EP 与
data_parallel_external_lb/data_parallel_hybrid_lb不兼容(见 vllm/config/parallel.py),因为它依赖单一 API server; - MoE 的 DP 部署天然要求跨 rank 前向对齐,空闲 rank 也会消耗算力执行 dummy 前向,评估成本时应将此计入。
通过内部、混合、外部三种模式,vLLM 的 DP 部署可以从小规模单机的单条命令,平滑扩展到多机乃至 K8s 上"一 rank 一 Pod"的宽 EP 拓扑;理解 Core Engine 进程、ZMQ 通信与 DP Coordinator 的 wave 协调机制,是正确组合这些模式、排查跨 rank 同步问题的基础。
【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考