
原文The vLLM MoE Playbook: A Practical Guide to TP, DP, PP and Expert Parallelism:https://www.amd.com/en.html
原文作者:Pin Siang Tan, Hongxia Yang, Peng Sun, Andy Luo, Jun Kang Chow, Ye Hur Cheong, Tun Jian Tan.
部署 DeepSeek-R1 这类超大 Mixture-of-Experts(MoE)模型时,问题从来不只是“我有多少块 GPU”,而是:这些 GPU 怎么配合工作。
选错并行策略→ KV cache 被复制 8 倍、显存直接爆掉,或者通信开销占了一半时间、吞吐被腰斩。
选对并行策略→ 同样的硬件上,针对你的业务场景,性能可以有非常明显的提升。
这篇文章用一套形象、可视化的框架,系统讲清 vLLM 里的几种并行方式:
Tensor Parallelism(TP,张量并行)
Data Parallelism(DP,数据并行)
Pipeline Parallelism(PP,流水线并行)
Expert Parallelism(EP,专家并行,MoE 专用开关)
配合大量示意图,我们会从「每一层的计算和显存」出发,解释:
TP 如何切分权重、为何需要 AllReduce
DP+EP 在 MoE 场景下如何配合 AllToAll 做请求级并行
为什么所谓的“DP Attention” 和传统数据并行完全不是一回事
什么时候一定要开--enable-expert-parallel,什么时候反而是徒增开销
我们也基于在AMD GPU 上部署 DeepSeek-R1、Qwen3-235B、Llama-4-Maverick 的实测结果,给出清晰的「交叉点」:
TP+EP:低并发、交互式场景下延迟更优
DP+EP:高并发、大吞吐场景下扩展性更好
你会看到:专家激活密度(每个 token 实际激活多少 expert)会直接决定 EP 是加速还是减速;而像 DeepSeek 这种 MLA/MQA 模型,在 KV cache 管理上又需要特别对待。
最后,我们给出一个实践向的决策框架,帮助你根据并发度、模型结构、硬件限制,选出最合适的并行组合。
范围说明
本文主要聚焦在单机部署(典型为 8 块 GPU,通过 AMD Infinity Fabric™ / xGMI 互联)。多机场景只做轻量讨论,例子与推荐方案均为单机优化版本。

核心概念
在 vLLM 中,底层有 3 种基本并行策略:Tensor Parallelism(TP,张量并行)、Pipeline Parallelism(PP,流水线并行)、Data Parallelism(DP,数据并行)。Expert Parallelism(EP,专家并行)则是专门为 MoE 模型设计的“修饰开关“,需要和 TP 或 DP 组合使用 [1, 4]。
Tensor Parallelism(TP)
做什么的?- 把单个层切分到多块 GPU 上:每块 GPU 只负责该层的一部分计算,最后通过集合通信(AllReduce)把结果合并。

图 1:Tensor Parallelism,tensor parallel = 4 的数据流
在图 1 中,单个请求 X 的张量被切成 4 份,分别放到 4 块 GPU 上:
所有 GPU 共同处理同一个请求、同一层的不同切片
每块GPU 只存这层权重的 1/4
每层计算结束后都需要一次AllReduce做同步
典型使用场景
单块 GPU 放不下整模,需要跨 GPU 切分模型
希望降低单个请求延迟:同一个 token 的计算并行跑在多块 GPU 上
约束:TP 大小必须能整除 attention head 数量。比如想用 TP=3,模型有 64 个 head,就会报类似:“Total number of attention heads (64) must be divisible by tensor parallel size (3)”。
启动示例
vllm serve model-name --tensor-parallel-size 4
Data Parallelism(DP)
做什么的?- 复制出多个「完整模型副本」,每个副本独立处理不同请求,从而提升整体吞吐。

图 2:Data Parallelism,DP=4 的数据流
在图 2 中,多条不同的请求同时被处理:
每块 GPU 上都有一份完整模型副本
各GPU 互不通信、独立处理不同请求
并发请求多时,整体吞吐能做到近似4倍
典型使用场景:请求之间互不依赖,希望提升整体QPS/吞吐
约束:DP 一般不降低单请求延迟,只是多开车道。
启动示例
vllm serve model-name --data-parallel-size 4
Pipeline Parallelism(PP)
做什么的?- 把模型的不同层拆给不同 GPU / 节点,每块 GPU 负责一段「流水线阶段」,数据像装配线一样一级一级往后传。

图 3:Vanilla Pipeline Parallelism,PP=4 的数据流
在图 3 的示意中,为了方便理解,只画了一条请求的「串行」流水线:
同一时刻只有一块 GPU 在干活,其他 GPU 处于空闲(pipeline bubble)
对单条请求,总延迟 = 4 个流水阶段的顺序总和
GPU 利用率只有 25%(4 块只用了 1 块)
什么时候考虑 PP?
模型太大,单机 + TP 也放不下,需要跨节点再切一层(PP+TP)
GPU 数量不是 2 的幂(3/5/6/7/9 …)时,希望更灵活切分
约束
和 DP 类似,PP 通常也不会降低单请求延迟
原始(vanilla)PP 如果只跑一条请求,大量 GPU 会闲着
vLLM 的优化
vLLM 不会傻傻地让流水线一次只跑一个请求,而是同时塞进多条请求:
GPU 0 处理请求 B 的第 1 段
GPU 1 同时处理请求 A 的第 2 段
GPU 2 可能在处理更早一条请求的第 3 段
这样流水线各阶段都能被填满,大幅减少pipeline bubble。
特征总结
每块 GPU 持有模型的一个「stage」子集
数据在stage 间顺序流动
单请求延迟:比TP 更高,因为要过完全部 stage
吞吐:在高并发时可以很可观
更适合多机部署:单机内TP,跨机用 PP
启动示例
# Pure PP: 4 GPUs as 4 pipeline stages
vllm serve model-name --pipeline-parallel-size 4
# TP within nodes + PP across nodes (2 pipeline stages with each pipeline has 4 GPUs)
vllm serve model-name --tensor-parallel-size 4 --pipeline-parallel-size 2
MoE 并行中的几个关键误区
在讨论 MoE 前,先把这几个概念彻底分清,否则很容易在配置里踩坑。
术语表:Sharded Experts vs Split Experts
理解「专家」如何在 GPU 间分布,是看懂本文所有图的基础。
Sharded Experts(不开 --enable-expert-parallel 时)
定义:每块 GPU 都有所有 expert,但每个 expert 的权重张量会被拆分到多块 GPU 上
例子:256 个 routed experts,TP=8 时,每块 GPU 都有 256 个 expert,但每个 expert 的权重只保存 1/8
通信:需要 AllReduce 来聚合这些分片结果
Split Experts(打开 --enable-expert-parallel 时)
定义:expert 被分发到不同 GPU 上,每块 GPU 只有部分完整 expert
例子:256 个 routed experts,TP=8 + EP 时,每块 GPU 只有 32 个完整 expert(GPU0 放 0–31,GPU1 放 32–63,依此类推)
通信:
o 和 DP 结合时:用 AllToAll 做token 与 expert 的路由
o 只和 TP 结合时:用 AllReduce
误区 1:“Expert Parallelism 是一种单独的并行方式”
事实:Expert Parallelism(EP)不是一套新的并行算法,而是一个开关--enable-expert-parallel,用来改写 MoE 层的通信与映射方式,只能和 TP 或 DP 搭配使用。
只有当:TP_SIZE × DP_SIZE > 1时,EP 才会真正生效,否则会被直接忽略。
EP 开关控制什么?
不开 EP:每块 GPU 上都有全部专家,权重张量被切片(shard),使用AllReduce 聚合;
开EP:专家在 GPU 之间做分布(split),当 DP > 1 时:使用 AllToAll(DP Attention);当DP = 1、只有 TP 时:仍然是 AllReduce。
误区2:“DP Attention 就是普通的数据并行”
事实:在 MoE 模型上,vLLM 使用的是一种特殊的 “DP Attention”,和传统意义上的 Data Parallelism 完全不同。
名词区分
传统 DP(Data Parallelism)
o 每块 GPU(或一个 TP 组)上都有完整一份模型副本
o 各副本处理不同请求,互不通信(推理阶段)
DP Attention
o 仍然是用 --data-parallel-size N 配置,但语义是:在一个逻辑「大模型副本」内部做请求级并行
o Attention 层是复制的,而 MoE 层的行为取决于是否开 EP
o 推理过程中需要 AllGather / AllToAll / slice 等操作,在 GPU 间反复重排 batch
o 只能在:
■ 搭配 EP:形成「DP + EP」
■ 不搭 EP:退化为传统 DP,不再具备 KV cache 分区收益
TP 对 MLA/MQA 的问题
Multi-Latent Attention(MLA)与 Multi-Query Attention(MQA)只有一个 KV 头:
TP 可以按 head 维把 Q/K/V 的线性层切片
但KV cache 只有一个 head,没法再按head 维度切
结果就是:KV cache 在所有 TP rank 上完整复制
例子:TP=32 时:
线性层计算:每块 GPU 只算 1/32 的 head ✅
KV cache:每块 GPU 都有 完整副本❌
显存浪费极其严重
DP Attention 解决什么?
DP Attention 不再是「多个独立模型副本」,而是一个逻辑模型内部的分工:
每块 GPU 上都有完整的非 MoE 层(attention、dense)
但 KV cache 按请求 / token 维度切分:
每块 GPU 只存自己负责那一部分请求的 KV cache
推理时通过 AllToAll 在 GPU 之间互相转发 token
对比传统 DP:
o 传统 DP:每块 GPU 处理自己的 batch,KV cache 完整复制在每个副本中
o DP Attention:一个「逻辑 batch」被拆散,KV cache 被分布到多个 GPU
示例:TP=4,DP=8(共 32 块 GPU)
32 块 GPU = 8 个 DP 组 × 每组 4 块 GPU 做 TP
非 MoE 计算:每块 GPU 算 1/4 的 head(组内 TP)
KV cache:每个 DP 组只持有自己请求的 KV,组内 4 块再细分
AllReduce:只在每个 4-GPU TP 组内做,不跨 32 块全局
不同 DP 组之间处理的是完全不同的一批请求
可用性
MoE + DP Attention 在 vLLM v0.9.0+ 的 V1 engine 中可用,
是为 DeepSeek-V2/V3/R1 这类 MLA/MQA 架构专门设计的 [2]。
误区3:“所有 experts 在 MoE 中都是一样的”
事实:MoE 模型中通常有两类 expert,行为截然不同。
Routed Experts
通过路由机制按需激活
每个token 只会激活一小部分 expert(例如 256 中激活 8 个)
EP 开启时:通过 determine_expert_map 把 routed expert 分布到不同 GPU
EP 关闭时:所有 routed expert 在每块 GPU 上都存在,但权重会按 flatten_tp_across_dp做切片
DeepSeek-R1:有 256 个 routed experts
Shared Experts
每个 token 都会激活(没有路由)
更像一层普通的 dense MLP
默认情况权重也是切片存储,只有在以下条件同时满足时才会复制:
o EP 开启
o tensor parallel size > 1
o data parallel size > 1
o 使用 all2all 特定 backend(如 allgather_reducescatter、naive、deepep_high_throughput、deepep_low_latency)
DeepSeek-R1:有 1 个 shared expert
Routed Experts 分布公式
EP_SIZE = TP_SIZE × DP_SIZE
Routed experts perGPU= Total Routed Experts / EP_SIZE
例:DeepSeek-R1(256 routed + 1 shared)

关键点:在总 GPU 数一样(这里都是 8 块)且 EP 开启时,TP=8 和DP=8 在「routed expert 分布数量」上是一样的(每块 32 个)。
误区4:“TP+EP 的通信和 DP+EP 一样都是 AllToAll”
事实:TP+EP 只会用 AllReduce,完全不会走 AllToAll。在 vLLM 源码中,AllToAll kernel 的启用条件是:dp_size > 1
# From vllm/model_executor/layers/fused_moe/config.py:669
@property
def use_all2all_kernels(self):
return self.dp_size > 1 and self.use_ep # Both conditions must be true
由于纯 TP 场景下 dp_size = 1,所以:
不论是否开 EP,都不会走 AllToAll
只会使用 AllReduce 这种「密集集合通信」
结论:
TP+EP:通信 = AllReduce(和不开 EP 时一样)
DP+EP:通信 = AllToAll(这是 DP Attention 的核心机制)
这也解释了:对于 MoE 模型,TP=8 不管开不开 --enable-expert-parallel,行为其实非常接近(通信模式一致,区别主要在 expert 映射)。
关键启示:KV cache 分区对 MLA/MQA 至关重要:
TP+EP:不能做 KV cache 分区,每块 GPU 都有完整 KV cache
DP+EP:可以按请求/token 把 KV cache 分布到多个 GPU 上
单一策略深挖:Expert Parallelism在MoE中到底改了什么?
Expert Parallelism 会改变 MoE 层如何映射到 GPU、以及通信模式,搞懂这一点是 MoE 部署的关键。
vLLM 内部的 MoE Expert 分布
MoE expert 的映射会经过一个 flatten_tp_across_dp 函数 [3]:
# From vllm/model_executor/layers/fused_moe/config.py:687-695 def flatten_tp_across_dp(tp_size: int, dp_size: int, dp_rank: int): flatten_tp_size = dp_size * tp_size flatten_tp_rank = dp_rank * tp_size + tp_rank return flatten_tp_size, flatten_tp_rank
注意:无论是否开 EP,这个函数都会被调用,也就是说 MoE 在 TP/DP 维度的布局本身就会被展平成一个统一空间。
Expert Parallelism 为什么能降低 MoE 延迟?
对 MoE 来说,瓶颈主要是内存带宽,而不是算力:
像 DeepSeek 这样的大模型,每个 token 实际只激活 37B 参数,占总 671B 的一小部分
GPU 大部分时间都在「从显存里搬 expert 权重」,不是在算矩阵乘
每块 GPU 的 HBM 带宽是固定的 → 单机带宽常常成为瓶颈
解决思路:把 experts 分散到多块 GPU 上,让多个 GPU 并行从各自 HBM 中读取权重,整体等价于提升了「有效带宽」。
以 8 块 GPU + EP 为例:
256 个 routed expert 均匀分到 8 块 GPU → 每块 32 个完整 expert
当 token 路由到不同 expert 时,可以跨 GPU 并行读取对应权重
整体看,相当于把「读 expert 权重」这件事分摊到了 8 倍 HBM 带宽上
通信代价
开 EP 之后,需要 AllToAll 把 token 路由到 expert 所在 GPU,再把结果路由回来
绝大多数模型下,这个 AllToAll 成本远小于内存带宽节省
(超极端「激活非常稀疏」的模型是例外,下文会看到 Llama-4 Maverick 的例子)
参考链接
[1] vLLM Documentation:https://docs.vllm.ai/
[2] vLLM DeepSeek Recipe:
https://docs.vllm.ai/projects/recipes/en/latest/DeepSeek/DeepSeek-V3.html
[3] vLLM Parallel Configuration Source Code:
https://github.com/vllm-project/vllm/blob/main/vllm/model_executor/layers/fused_moe/config.py
[4] vLLM RFC: Data Parallel Attention and Expert Parallel MoEs (Issue #16037):
https://github.com/vllm-project/vllm/issues/16037