大模型在线推理并不是一种均匀的计算任务。Prefill 阶段需要并行处理整段输入,通常更依赖算力和显存带宽;Decode 阶段逐 token 生成结果,更看重低延迟、KV Cache 容量与持续调度能力。来源方案在 Amazon SageMaker HyperPod 上结合 vLLM 和 HyperPod Inference Operator,实现了 Disaggregated Prefill and Decode(DPD),让两个阶段可以分别部署、扩缩和调优。
为什么要把两个阶段拆开
在传统共置部署中,同一个 vLLM 实例既执行 Prefill,也执行 Decode。这种模式部署简单,但两类负载会竞争 GPU:长提示词可能占用大量计算资源,正在生成 token 的请求则可能因此出现延迟抖动。
DPD 将一次推理拆成两个资源域:
- Prefill Worker 读取提示词,计算首轮隐藏状态并建立 KV Cache。
- KV 传输层把后续解码所需的数据交给 Decode Worker。
- Decode Worker 复用这些状态,持续生成 token。
- 路由或编排组件负责请求关联、实例选择、失败处理和流量控制。
拆分后的关键收益不是“凭空减少计算量”,而是可以按照不同瓶颈配置 GPU。例如,Prefill 池可以使用计算吞吐更高的实例并承接批量长上下文,Decode 池则按并发序列数和 KV Cache 压力扩容。
代价也很明确:KV Cache 必须跨进程甚至跨节点传输,网络吞吐、拓扑距离和序列化开销都会进入请求关键路径。如果提示词很短、生成量较少,新增的数据传输和调度成本可能抵消拆分收益。
Operator 在这里解决什么问题
HyperPod Inference Operator 把推理工作负载放进 Kubernetes 式的声明式控制循环。对于 DPD,Operator 的价值不只是启动两个 Pod,还包括维护目标副本数、处理节点故障,以及让 Prefill、Decode 和服务入口形成可持续运维的部署单元。
生产设计时应把以下参数分开管理:
| 维度 | Prefill 池 | Decode 池 |
|---|---|---|
| 主要容量指标 | 输入 token/s、首 token 延迟 | 活跃序列数、输出 token/s、单 token 延迟 |
| 常见压力来源 | 长上下文、突发批量请求 | 长输出、高并发、KV Cache 占用 |
| 扩缩依据 | 队列长度、待处理输入 token | 活跃请求、生成队列、GPU KV Cache 使用率 |
| 网络要求 | 快速输出 KV 数据 | 稳定接收 KV 数据并保持低尾延迟 |
不要只按 GPU 利用率扩缩。Decode Worker 即使计算单元没有跑满,也可能已经受限于显存中的 KV Cache;Prefill Worker 则可能在请求间歇期利用率骤降,但队列里已经积累了大量输入 token。
可以这样检查并准备集群
下面的命令可以直接用于已配置 kubectl 的 HyperPod Kubernetes 环境。它们不假定 Operator 的 CRD 名称,而是先从集群中发现实际安装的资源类型,避免把版本相关的 API 名称写死。
# 查看与 HyperPod、推理或模型服务相关的 CRD
kubectl get crd -o name \
| grep -Ei 'hyperpod|inference|model|endpoint'
# 查看 GPU 节点及其可分配资源
kubectl get nodes \
-o custom-columns='NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu,TYPE:.metadata.labels.node\.kubernetes\.io/instance-type'
# 确认 NVIDIA 设备插件暴露了 GPU
kubectl get pods -A -o wide \
| grep -Ei 'nvidia|device-plugin'
# 部署后观察 Pod 分布、重启和节点位置
kubectl get pods -A -o wide \
| grep -Ei 'prefill|decode|vllm'
如果第一条命令返回了 Operator 提供的 CRD,可以继续执行:
# 将 <resource> 替换为集群实际返回的资源名
kubectl explain <resource> --recursive
kubectl get <resource> -A
这一步很重要:来源摘要没有给出具体 CRD 版本和字段,因此实际清单应以集群中安装的 HyperPod Inference Operator API 为准。
一个可改造的 vLLM DPD 配置骨架
下面是一个最小 Kubernetes 配置骨架,用来明确 Prefill 与 Decode 的资源边界。它假设当前 vLLM 镜像支持 NIXL KV connector,并使用 kv_producer 和 kv_consumer 角色;不同 vLLM 版本的 connector 名称、角色参数和额外协调地址可能不同,运行前应通过 vllm serve --help 和对应版本文档确认。生产环境中,可把相同的容器参数迁移到 HyperPod Inference Operator 的自定义资源中,由 Operator 接管生命周期。
运行前需要修改镜像标签、模型路径、GPU 数量和节点选择标签:
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-prefill
spec:
replicas: 2
selector:
matchLabels:
app: vllm-prefill
template:
metadata:
labels:
app: vllm-prefill
inference-role: prefill
spec:
containers:
- name: vllm
image: vllm/vllm-openai:<validated-version>
args:
- serve
- /models/your-model
- --host=0.0.0.0
- --port=8000
- --tensor-parallel-size=1
- --kv-transfer-config={"kv_connector":"NixlConnector","kv_role":"kv_producer"}
resources:
limits:
nvidia.com/gpu: 1
ports:
- name: http
containerPort: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-decode
spec:
replicas: 4
selector:
matchLabels:
app: vllm-decode
template:
metadata:
labels:
app: vllm-decode
inference-role: decode
spec:
containers:
- name: vllm
image: vllm/vllm-openai:<validated-version>
args:
- serve
- /models/your-model
- --host=0.0.0.0
- --port=8000
- --tensor-parallel-size=1
- --kv-transfer-config={"kv_connector":"NixlConnector","kv_role":"kv_consumer"}
resources:
limits:
nvidia.com/gpu: 1
ports:
- name: http
containerPort: 8000
把文件保存为 dpd-workers.yaml 后,可以先做服务端校验,再交给集群:
kubectl apply --dry-run=server -f dpd-workers.yaml
kubectl apply -f dpd-workers.yaml
kubectl rollout status deployment/vllm-prefill
kubectl rollout status deployment/vllm-decode
这份骨架只定义了两个 Worker 池,并不构成完整 DPD 服务。还需要由 HyperPod Inference Operator 对应的资源、兼容路由器或编排层建立 Prefill 到 Decode 的请求关联与 KV 传输。不要把两个 Deployment 简单挂到同一个随机负载均衡 Service 后就认为完成了 DPD,因为普通 Service 不理解推理阶段和 KV Cache 所属关系。
上线前用数据决定是否拆分
评估 DPD 时,至少分别记录 TTFT(Time to First Token)、TPOT(Time per Output Token)、端到端延迟和吞吐量。测试流量要覆盖真实的输入与输出长度分布,而不是只跑固定的短提示词。
一个务实的采用清单是:
- 固定模型、量化方式和 vLLM 版本,对比共置部署与 DPD。
- 分别测试短输入短输出、长输入短输出、短输入长输出和长输入长输出。
- 观察 Prefill 队列、Decode 活跃序列、GPU 显存以及 KV 传输带宽。
- 验证 Prefill 或 Decode Pod 重启时,请求是否重试、失败或丢失状态。
- 检查跨可用区或跨低速网络调度是否显著拉高尾延迟。
- 为两个池设置独立扩缩信号,并限制最大副本数,避免拥塞在阶段之间来回放大。
DPD 更适合输入长度、输出长度或并发模式差异明显的服务。若模型较小、流量稳定且上下文较短,共置部署通常更容易运维。SageMaker HyperPod、vLLM 与 HyperPod Inference Operator 的组合提供了拆分和调度基础,但最终是否值得采用,应由真实请求分布、KV 传输成本和故障恢复结果共同决定。