普惠 DeepSeek-V4:Kthena + 昇腾 3 分钟搭建 PD 分离推理
一、背景介绍
在大模型推理部署中,Prefill-Decode(P/D)分离是一种被广泛采用的性能优化架构。随着大语言模型参数量不断增长,推理过程中的计算资源消耗和延迟问题日益突出。传统的一体化推理架构难以同时优化首token延迟(TTFT)和整体吞吐率(TPOT),而P/D分离通过将推理过程拆分为两个独立阶段,让每个阶段使用最适合其计算特性的并行策略,实现了显著的性能提升。

本文将详细介绍如何通过Kthena控制器,在昇腾NPU上部署DeepSeek-V4-Flash模型,完成P/D分离的实践。我们会深入解析P/D分离的技术原理、Kthena的编排能力,以及ModelRoute如何实现P/D实例的自动发现与KV传输协作。
二、P/D分离技术原理
2.1 大模型推理的两阶段解析
大语言模型的推理过程是一个自回归生成过程,本质上分为两个截然不同的阶段:
Prefill阶段(首token生成)
Prefill阶段负责处理用户输入的prompt,将完整的输入序列通过模型前向传播,生成第一个输出token。这个阶段具有以下特征:
-
计算密集型:需要处理整个输入序列,每个token都需要与所有输入token进行注意力计算 -
并行度高:输入序列的所有位置可以并行计算,适合较大的张量并行(TP)规模 -
内存访问模式:KV Cache首次生成,需要写入到高速缓存中 -
延迟敏感:用户等待首token的时间直接影响体验
在我们的配置中,Prefill阶段采用DP(数据并行)=2、TP(张量并行)=8的配置,利用更大的张量并行度来加速矩阵运算:
--data-parallel-size 2 \
--tensor-parallel-size 8 \
--max-num-batched-tokens 8192 \
--max-num-seqs 4 \
Decode阶段(增量生成)
Decode阶段是自回归生成过程,每次只处理一个新生成的token,并将其加入序列进行下一轮推理。这个阶段的特点与Prefill截然不同:
-
Memory-Bound型:每次只计算一个token,但需要读取完整的KV Cache -
并行度需求低:单个token的计算量有限,过大的张量并行反而增加通信开销 -
吞吐率敏感:需要最大化单位时间内生成的token数量 -
KV传输频繁:每个Decode实例都需要访问所有Prefill实例生成的KV Cache
Decode阶段采用DP(数据并行)=8、TP(张量并行)=2的配置,通过更大的数据并行来提升整体吞吐:
--data-parallel-size 8 \
--tensor-parallel-size 2 \
--max-num-batched-tokens 144 \
--max-num-seqs 48 \
2.2 为什么P/D分离能提升性能
传统的单体架构面临"一刀切"的困境:为了同时满足Prefill和Decode的需求,必须在并行策略上做出妥协,导致两个阶段都无法达到最优。而P/D分离的核心价值在于解耦:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
以DeepSeek V4为例:
-
Prefill优化:更大的TP size(8)加速注意力计算,更大的批处理量(8192 tokens)提升吞吐 -
Decode优化:更大的DP size(8)支持更多并发序列,更小的TP size(2)减少通信开销
2.3 KV Cache传输机制
P/D分离后,Prefill和Decode之间需要高效传输KV Cache,这是P/D分离架构中最关键的技术挑战之一。
在我们的部署中,使用Mooncake Connector V1实现KV传输:
--kv-transfer-config\
'{"kv_connector": "MooncakeConnectorV1",
"kv_role": "kv_producer", # Prefill为producer
"kv_port": "9000",
"engine_id": "$MOONCAKE_ENGINE_ID",
...
}'
Mooncake KV传输原理:
-
Producer端(Prefill):生成的KV Cache通过Mooncake引擎传输到Decode节点 -
Consumer端(Decode):从Mooncake引擎拉取KV Cache用于注意力计算 -
Engine ID:每个P/D实例组有唯一的engine ID( ${GROUP_NAME}_${ROLE_ID}),确保数据传输到正确的目标
# Prefill配置
"kv_role":"kv_producer"
# Decode配置
"kv_role":"kv_consumer"
Mooncake具备昇腾NPU优化的高性能通信库,能够实现节点间KV Cache的低延迟传输,是P/D分离能够实际落地的关键技术。
三、为什么P/D分离需要适配的Router
3.1 路由在P/D分离架构中的核心作用
在P/D分离架构中,请求的路由不再是简单地分发到某个后端实例,而是需要智能地协调Prefill和Decode两个阶段,这与传统微服务路由有本质区别。
传统微服务路由:
Client Request → Router → Backend Instance (处理完整请求)
P/D分离路由:
Client Request → Router → Prefill Instance (生成首token)
↕ (KV传输)
Decode Instance (完成剩余生成)
3.2 路由需要解决的挑战
挑战一:请求生命周期管理
一个完整的请求在P/D架构中需要经过多个阶段:
-
请求首先路由到Prefill处理 -
Prefill生成首token后,需要将请求转交给Decode -
Decode可能需要多轮生成,每轮都涉及KV传输 -
最终结果需要汇总返回给用户
这要求Router必须理解P/D的请求流程,而不仅仅是做简单的负载均衡。
挑战二:P/D实例发现与匹配
-
Prefill和Decode实例数量可能不同(1P2D、2P1D等) -
请求需要在正确的Prefill和Decode实例之间传递 -
需要跟踪每个请求当前由哪个实例处理
挑战三:KV传输的协调
KV Cache的传输需要满足以下条件:
-
Prefill生成的KV必须传输到处理该请求的Decode实例 -
Mooncake的engine_id需要正确配置以匹配P/D实例 -
传输超时和错误处理
挑战四:流量分配策略
不同场景下可能需要不同的P/D配比:
-
计算密集型场景:增加Prefill副本 -
IO密集型场景:增加Decode副本 -
Router需要支持动态调整流量分配
3.3 ModelRoute的适配设计
Kthena的ModelRoute正是为解决上述挑战而设计的适配层。它不仅负责基本的请求路由,还需要理解P/D分离的语义,协调Prefill和Decode的协作。
四、ModelRoute配置详解
4.1 整体配置结构
apiVersion:networking.serving.volcano.sh/v1alpha1
kind:ModelRoute
metadata:
name:deepseek-v4
namespace:default
spec:
modelName:"deepseek_v4"
rules:
-name:"default"
targetModels:
-modelServerName:"deepseekv4-pd"
---
apiVersion:networking.serving.volcano.sh/v1alpha1
kind:ModelServer
metadata:
name:deepseekv4-pd
namespace:default
spec:
inferenceEngine:vLLM
model:"deepseek_v4"
workloadPort:
port:7100
protocol:http
workloadSelector: # 工作负载选择器
matchLabels:
modelserving.volcano.sh/name:deepseekv4-pd # 这是最基本的标签匹配,用于识别属于该服务的所有Pod。
pdGroup: # P/D分组配置
groupKey:"modelserving.volcano.sh/group-name"# 指定用于分组的标签key
prefillLabels: # 标记哪些Pod是Prefill角色
modelserving.volcano.sh/role:prefill
decodeLabels: # 标记哪些Pod是Decode角色
modelserving.volcano.sh/role:decode
trafficPolicy:
timeout:"300s"
retry:
attempts:3
retryInterval:"150ms"
kvConnector:
type:mooncake
其中P/D分组配置(pdGroup)是实现P/D识别的关键配置:
-
groupKey:指定用于分组的标签key,具有相同 groupKey值的Pod属于同一个P/D实例组。这解决了一个关键问题:当我们部署多个P/D实例组时(如2×(1P1D)),Router需要知道哪些Prefill和Decode属于同一个组。 -
prefillLabels:标记哪些Pod是Prefill角色。 -
decodeLabels:标记哪些Pod是Decode角色。
4.2 实例发现的实现机制
Kthena控制器通过以下步骤实现P/D实例的自动发现:
步骤1:标签注入
在deepseek-serv.yaml中定义的ModelServing资源会被Kthena控制器处理,自动为每个Pod注入标签:
metadata:
labels:
modelserving.volcano.sh/name:deepseekv4-pd
modelserving.volcano.sh/group-name:<group-id> # 自动生成
modelserving.volcano.sh/role:prefill/decode # 根据role名称
modelserving.volcano.sh/role-id:<role-id> # 自动生成
步骤2:标签查询
ModelRoute的pdGroup配置会被控制器用于查询匹配的Pod:
1. 查询所有 labels[modelserving.volcano.sh/name] = deepseekv4-pd 的Pod
2. 按 labels[modelserving.volcano.sh/group-name] 分组
3. 在每个组内,识别prefillLabels和decodeLabels匹配的Pod
步骤3:动态维护
当发生扩缩容时:
-
新Pod创建后自动获得标签 -
Router实时感知Pod变化 -
无需手动更新配置
4.3 KV传输的协调
ModelRoute通过以下配置协调KV传输:
kvConnector:
type:mooncake
Mooncake Connector的工作流程:
1️⃣ Prefill启动时:
-
从环境变量获取 GROUP_NAME和ROLE_ID -
构建 engine_id = ${GROUP_NAME}_${ROLE_ID} -
启动Mooncake Server,监听KV请求
2️⃣ Decode启动时:
-
使用相同的 GROUP_NAME但不同的ROLE_ID -
配置为kv_consumer角色 -
通过engine_id连接到对应Prefill的Mooncake Server
-
Prefill处理用户输入,生成KV Cache -
KV Cache通过Mooncake传输到对应Decode实例 -
Decode使用接收到的KV继续生成
4.4 流量策略配置
trafficPolicy:
timeout:"300s"
retry:
attempts:3
retryInterval:"150ms"
这些配置确保了请求在P/D之间的可靠传递:
-
timeout:整个生成过程可能需要较长时间,设置5分钟超时 -
retry:如果请求在Prefill或Decode环节失败,自动重试
五、Kthena编排的核心优势
5.1 声明式编排简化运维
传统方式下,部署P/D分离架构需要:
-
手动创建和管理多组Deployment/Service -
手动配置Service之间的发现机制 -
手动管理标签选择器和Endpoints
使用Kthena的ModelServing,仅需声明式配置:
apiVersion:workload.serving.volcano.sh/v1alpha1
kind:ModelServing
metadata:
name:deepseekv4-pd
spec:
replicas:1
template:
roles:
-name:prefill
replicas:1
-name:decode
replicas:1
控制器会自动完成:
-
创建和管理Prefill/Decode的Pod -
注入必要的标签(group-name、role、role-id) -
设置健康检查 -
配置资源限制
5.2 灵活的P/D比例调整
单实例1P1D:
roles:
-name:prefill
replicas:1
-name:decode
replicas:1
调整为2P1D(提升Prefill吞吐):
roles:
-name:prefill
replicas:2 # 从1改为2
-name:decode
replicas:1
调整为1P2D(提升Decode吞吐):
roles:
-name:prefill
replicas:1
-name:decode
replicas:2 # 从1改为2
部署2组独立的1P1D实例(横向扩展):
spec:
replicas:2 # 整体副本数设为2,每组自动生成1P1D
我们测试了以下几种灵活的P/D比例配置:
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
所有这些调整都只需修改yaml配置并执行:
kubectl apply -f deepseek-serv.yaml
Kthena控制器会自动处理Pod的创建、销毁和负载均衡。
5.3 自动服务发现
在传统的P/D部署中,需要手动配置服务发现:
-
Prefill服务需要知道所有Decode实例的地址 -
Decode服务需要知道所有Prefill实例的地址 -
扩缩容时需要手动更新配置
Kthena通过pdGroup和标签机制实现了自动服务发现:
-
新增的Prefill或Decode实例自动被Router识别 -
使用相同的group-key的实例自动组成P/D组 -
无需手动配置实例地址
六、部署实践
6.1 模型准备
为了加速部署和启动过程,我们将DeepSeek-V4-Flash模型权重预先下载到所有计算节点的 /models/DeepSeek-V4-Flash-w8a8-mtp 目录下。该目录应包含完整的模型权重文件、配置文件以及chat_template.jinja模板文件。
从ModelScope下载模型权重:
# 安装ModelScope
pip install modelscope
# 下载DeepSeek V4 Flash模型
modelscope download --model Eco-Tech/DeepSeek-V4-Flash-w8a8-mtp --local_dir /models/DeepSeek-V4-Flash-w8a8-mtp
如果使用git-lfs进行大文件管理,也可以:
# 安装git-lfs
git lfs install
# 克隆模型仓库
GIT_LFS_SKIP_SMUDGE=1 git clone https://www.modelscope.cn/Eco-Tech/DeepSeek-V4-Flash-w8a8-mtp.git /models/DeepSeek-V4-Flash-w8a8-mtp
# 进入目录并下载LFS大文件
cd /models/DeepSeek-V4-Flash-w8a8-mtp
git lfs pull
注意事项:
-
确保所有计算节点的模型目录路径一致( /models/DeepSeek-V4-Flash-w8a8-mtp) -
可以在共享存储(如NFS)上预先下载模型,然后挂载到各个节点 -
模型下载完成后,建议验证文件完整性: ls -la /models/DeepSeek-V4-Flash-w8a8-mtp/ # 应包含 config.json, model.safetensors, chat_template.jinja 等文件
6.2 完整部署流程
Step 1: 创建ConfigMap(包含启动脚本)
kubectl apply -f config.yaml
config.yaml定义了Prefill和Decode的启动脚本,包含:
-
环境变量配置 -
vLLM启动参数 -
Mooncake KV连接配置
Step 2: 部署ModelServing
kubectl apply -f deepseek-serv.yaml
创建完整的P/D分离实例,包括:
-
Prefill实例(1副本) -
Decode实例(1副本) -
自动注入的标签和配置
Step 3: 配置路由
kubectl apply -f modelRoute.yaml
创建ModelRoute和ModelServer两个对象:
-
ModelRoute:定义路由规则 -
ModelServer:定义后端服务
6.2 验证部署
# 查看ModelServing状态
kubectl get modelserving deepseekv4-pd
# 查看所有相关Pod
kubectl get pods -l modelserving.volcano.sh/name=deepseekv4-pd
# 查看Pod详情(确认标签)
kubectl get pods -l modelserving.volcano.sh/name=deepseekv4-pd -o wide
# 检查Pod日志
kubectl logs -l modelserving.volcano.sh/role=prefill
kubectl logs -l modelserving.volcano.sh/role=decode
6.3 扩缩容操作
扩缩容Prefill:
# 编辑配置
kubectl edit modelserving deepseekv4-pd
# 将 prefill.replicas 从 1 改为 2
# 或者使用patch
kubectl patch modelserving deepseekv4-pd --type='json' \
-p='[{"op": "replace", "path": "/spec/template/roles/0/replicas", "value": 2}]'
扩缩容Decode:
kubectl patch modelserving deepseekv4-pd --type='json' \
-p='[{"op": "replace", "path": "/spec/template/roles/1/replicas", "value": 2}]'
七、总结
通过本次实践,我们验证了 Kthena 在昇腾 NPU 环境下部署 DeepSeek-V4-Flash 模型 P/D 分离(Prefill/Decode Disaggregation) 架构的完整可行性。
主要成果:
-
成功实现P/D分离部署,Prefill和Decode独立运行 -
通过Mooncake KV传输实现P/D协作 -
支持灵活的P/D比例调整(1P1D、2P1D、1P2D等) -
支持多实例横向扩展
Kthena的核心价值:
-
简易性:声明式配置替代复杂的手动编排,控制器自动处理Pod管理和标签注入 -
灵活性:通过replicas字段即可独立调整P/D比例,无需修改其他配置 -
自动发现:pdGroup机制实现P/D实例的自动识别和配对 -
KV协调:与Mooncake深度集成,确保KV传输的正确路由
综上所述,P/D 分离是提升大模型分布式推理效能的核心技术路径,而 Kthena 的适配 Router 设计与编排逻辑,为这一复杂架构在生产环境中的标准化部署提供了确定性的方案,确保了大模型服务在昇腾算力底座上的高效稳定运行。
相关部署模板参考Kthena项目地址:https://github.com/volcano-sh/kthena/tree/main/examples/models/deepseek-v4-flash
Kthena GitHub地址:https://github.com/volcano-sh/kthena
更多信息,欢迎访问 Kthena 官网: https://kthena.volcano.sh/
欢迎Star★,Fork,来 Kthena 社区一起玩转LLM推理!

关注魔方公众号,获取更多前沿资讯
添加社区小助手k8s2222,进入技术交流群
- 点赞
- 收藏
- 关注作者
评论(0)