admin管理员组

文章数量:1029573

在 TKE 上使用 NVIDIA Dynamo 部署 PD 分离的大模型

刘瑾锋,腾讯云容器服务 TKE 后台开发工程师,主要负责容器服务(TKE)相关研发工作。

前言

在 2025 年 GTC 大会上,NVIDIA CEO 黄仁勋介绍了他们开源的 Dynamo 推理框架,并称它为“AI 工厂的超级操作系统”。 目前 Dynamo 在 github 上开源[1],它被设计用于在多节点分布式环境中为生成式人工智能和推理模型提供服务,支持多种推理引擎:包括 TRT-LLM、vLLM、SGLang 等等。 Dynamo 宣称具有以下核心特性:

  • 分解预填充和解码推理阶段:最大限度地提高 GPU 吞吐量,促进吞吐量和延迟之间的权衡。
  • 动态 GPU 调度:根据波动需求优化性能。
  • LLM 感知请求路由:消除不必要的 KV 缓存重新计算。
  • 加速数据传输:利用 NIXL 缩短推理响应时间。
  • KV 缓存卸载:利用多个内存分层提高系统吞吐量。

本文主要基于 dynamo 的分解预填充和解码推理阶段特性讲述如何在 TKE 上使用 dynamo 部署 PD 分离的大模型,分为以下六部分:

  • 第一部分,介绍 Dynamo 的 PD 分离架构。
  • 第二部分,给出一个在 TKE 上部署 PD 分离的示例。
  • 第三部分,介绍 Dynamo 的监控组件。
  • 第四部分,Dynamo PD 分离部署的性能验证,与 vLLM 进行对比。
  • 第五部分,部署过程中可能会遇到的一些常见问题,包括 dynamo 尚未实现的特性。
  • 第六部分,探讨 dynamo 之后的部署演变方向。

一、Dynamo 的 PD 分离是如何实现的?

PD 分离(Prefill-Decode Disaggregation)是一种针对大语言模型(LLM)推理过程的优化技术,其核心思想是将推理任务拆分为预填充(Prefill)解码(Decode)两个独立阶段,并分配到不同的计算资源上执行,以提升整体效率与资源利用率。这两个阶段对硬件资源的需求存在显著差异:

  • Prefill 阶段:计算密集型,需高算力并行处理输入提示(如 FP8 低精度加速),占用大量 GPU 算力但显存需求较低。
  • Decode 阶段:内存密集型,依赖高带宽显存频繁读取 KV 缓存,算力需求低但显存占用随上下文增长指数级上升。

Dynamo 在设计上将 Prefill 和 Decode 阶段交由不同的 Worker 执行,Prefiil Worker 从队列中获取需要执行的 Prefill 请求,并在完成 Prefill 后通知 Decode Worker,具体流程如下图所示:

Dynamo 通过引入 PrefillQueue 作为 Prefill 和 Decode 阶段的中间层,允许独立扩展 Prefill Worker 和 Decode Worker 的数量,不仅优化了资源利用率,还支持根据实时负载调整Worker数量,提升了整体性能和效率。

二、PD 分离部署指南

在以下示例中,本文使用了 3 个 H20 节点,每个节点上具有 8 个 GPU 核心,使用的推理引擎为 vLLM,模型为 neuralmagic/DeepSeek-R1-Distill-Llama-70B-FP8-dynamic,dynamo 镜像是基于 commit:

988e8826771888c9645857266032e11a7f67492a 构建的。

(注:这里没有选择满血版 DeepSeek R1 671B 作为测试模型的原因是目前 dynamo 使用 nixl 通信库,当前存在 tp 数必须小于等于 8 的限制,无法很好地部署 满血版 DeepSeek R1 671B 这种超大模型)

2.1 部署架构

在 Dynamo 中,一个典型的推理服务通常应该包括以下组件:

  • FrontEnd:与 OpenAI 兼容的 HTTP 服务器,用于处理传入请求。
  • Processor:处理请求,然后再将请求传递给 Worker。
  • Router:根据指定策略将请求路由到适当的 Worker。
  • Worker:处理实际的 LLM 推理(包括预填充和解码阶段)。

在架构上,本文使用了三个节点(也可以说是三个 Pod),每个节点部署了 Dynamo 的部分组件,具体而言:

Node 1
  • FrontEnd:与 OpenAI 兼容的 HTTP 服务器,用于处理传入请求。
  • Processor:处理请求,然后再将请求传递给 Worker。
  • Router:根据指定策略将请求路由到适当的 Worker。
  • VllmWorker:处理实际的 LLM 推理解码阶段,使用 4 个 GPU 核心,设置 tp = 4,worker = 1。
  • PrefillWorker:处理实际的 LLM 推理预填充阶段,使用 4 个 GPU 核心,设置 tp = 1,worker = 4。
Node 2
  • PrefillWorker:处理实际的 LLM 推理预填充阶段,使用 8 个 GPU 核心,设置 tp = 1,worker = 8。
Node 3
  • PrefillWorker:处理实际的 LLM 推理预填充阶段,使用 8 个 GPU 核心,设置 tp = 1,worker = 8。

也就是说在本示例中,我们使用了 1 个 4 GPU 的 Deocde 节点,以及 20 个 1 GPU 的 Prefill 节点,这个比例是根据在现有资源(3 * H20 节点)上的性能测试结果得出的。

各个节点详细的 configs 配置如下:

在部署完成后,一次推理的请求链路大致如下图所示:

2.2 中间件部署:nats 和 etcd

dynamo 依赖 nats 和 etcd 进行服务发现和通信,需要在所有节点中设置如下环境变量来确保组件之间可以通信:

代码语言:javascript代码运行次数:0运行复制
env:
- name: NATS_SERVER
  value: <your-nats-address> # nats://dynamo-llm-nats:4222
- name: ETCD_ENDPOINTS
  value: <your-etcd-address> # dynamo-llm-etcd:2379

以下提供一些示例部署 nats 和 etcd:

  • nats 的单节点部署
代码语言:javascript代码运行次数:0运行复制
# 假设当前所在路径为 dynamo 项目的根路径

# Add and update NATS Helm repository
helm repo add nats /
helm repo update

# Navigate to dependencies directory
cd deploy/Kubernetes/pipeline/dependencies

# Install NATS with custom values
helm install dynamo-llm-nats nats/nats --values nats-values.yaml
  • nats 的高可用部署 以下提供了一份 helm-chart 的 values 范例,可以通过该 values 部署一个高可用的 nats 集群。
  • etcd 的单节点部署
代码语言:javascript代码运行次数:0运行复制
# 假设当前所在路径为 dynamo 项目的根路径

# Navigate to dependencies directory
cd deploy/Kubernetes/pipeline/dependencies

# Install etcd using Bitnami chart
# 默认 pvc 申请的大小为 8Gi,在 TKE 上 CBS 申请最少为 10Gi,因此默认值无法使用。这里修改为 20 Gi。
helm install dynamo-llm-etcd \
    oci://registry-1.docker.io/bitnamicharts/etcd \
    --values etcd-values.yaml \
    --set persistence.size=20Gi
  • etcd 的高可用部署

这里推荐使用腾讯云提供的【云原生etcd】服务[2],腾讯云容器团队目前线上运维了上万套 K8S 集群,在保障 etcd 稳定运行的同时积累了大量的实践经验,可以帮助用户降低 etcd 的运维负担,从而更专注于业务发展。

2.3 Node 1

2.4 Node 2 & Node 3

2.5 API 验证

在上述过程中,我们创建了一个名为 deepseek-r1-llama-70b-dynamo-multinode 的 service,可以通过 kubectl port-forward 来快速验证 API。

代码语言:javascript代码运行次数:0运行复制
kubectl port-forward svc/deepseek-r1-llama-70b-dynamo-multinode

在另外一个终端调用 API,如下是用 curl 的一个示例:

代码语言:javascript代码运行次数:0运行复制
curl -X POST "http://localhost:80/v1/chat/completions" \ 
  -H "Content-Type: application/json" \ 
  -d '{
  "model": "neuralmagic/DeepSeek-R1-Distill-Llama-70B-FP8-dynamic",
  "messages": [
    {"role": "system", "content": "你是一个AI编程助手"},
    {"role": "user", "content": "用Python实现快速排序算法"}
  ],
  "temperature": 0.3,
  "max_tokens": 512,
  "top_p": 0.9
}'

三、Dynamo 的监控组件

要使用该组件,必须将 LLM 服务的 router 类型指定为 kv。

Dynamo 开发了 metrics 组件,专门用于监控 dynamo 的 LLM Worker 状态,目前提供如下指标:

  • llm_kv_blocks_active: 每个 Worker 的活动 KV 块数量
  • llm_kv_blocks_total: 每个 Worker 可用的 KV 块总数
  • llm_requests_active_slots: 每个 Worker 当前的活动请求插槽数量
  • llm_requests_total_slots: 每个 Worker 的可用请求插槽总数
  • llm_kv_hit_rate_percent: 每个 Worker 的累积 KV 缓存命中率
  • llm_load_avg: 各个 Worker 的平均负载
  • llm_load_std: 各个 Worker 的负载标准差

根据这些指标,可以画出如下的监控面板:

metrics 是一个独立组件,在 Kubernetes 集群环境下,你可以把它部署为 sidecar ,与 frontend 组件 Pod 绑定部署,也可以部署为一个独立 Pod,它的关键依赖项只有 etcd 和 nats,通过这两个中间件,metrics 组件实现了指标采集端点的发现和数据的收集,最后暴露到指定端口的 /metrics 路径。

当然,它也支持 push 模式,可以将收集到的指标推送到指定的 push gateway 端点上。

目前,metrics 作为一个独立二进制文件,你可以通过以下方式将它从原本的 dynamo 镜像(30+ GB)中拷贝出来,减少镜像大小至 100+ MB:

代码语言:javascript代码运行次数:0运行复制
FROM dynamo:latest-vllm AS bin
FROM ubuntu:24.04
COPY --from=bin /usr/local/bin/metrics /usr/local/bin/metrics

CMD ["metrics", "--component", "VllmWorker", "--endpoint", "load_metrics"]

四、与 vLLM 的性能对比

依据 dynamo 的 benchmark 示例,使用 genai-perf 进行压测[3],修改其中的 model、tokenizer、url 参数。

关注以下性能指标:

  • Time To First Token(TTFT):生成第一个 Token 所需要的时间。
  • Time To Second Token(TTST):生成第二个 Token 所需要的时间。
  • Request Latency:响应时间。
  • Inter Token Latency(ITL):平均每 Token 生成时间。

在性能对比过程中,以下配置项保持一致:

vllm 版本

0.7.2

block-size

128

max-model-len

3500

max-num-batched-tokens

3500

模型

euralmagic/DeepSeek-R1-Distill-Llama-70B-FP8-dynamic

模型大小

70B

  1. 为什么 vllm 版本使用 0.7.2 ? 目前 dynamo 只适配了 0.7.2 的 vllm,这里为了保持版本一致。(注意:vllm 的最新版本为 0.8.4,已经正式启用了 V1 引擎,在吞吐量方面相较于 0.7.2 大约有 1.7 倍的提升[4])
  2. 为什么设置 block-size 为 128?为了得到更好的性能,根据 dynamo 官方文档[5],大部分模型设置 block-size 为 128 的性能更好。
  3. 为什么设置 max-model-len 和 max-num-batched-tokens 为 3500?参考 dynamo 官方压测示例,模拟 chat 场景,设置了 ISL/OSL = 3000/150,请求中输入 token 数在 3000 左右,输出 token 数在 150 左右,需要的上下文长度在 3500 以内。

baseline 与 dynamo 部署的主要区别在于 tp(即 tensor-parallel-size)的设置,以及因为 dynamo 架构上 PD 分离导致的 Prefill Worker 和 Decode Worker 资源分配的问题。

4.1 vLLM baseline

我们部署了 6 个 vLLM 的 Pod 作为 baseline,设置 tp = 4,

(注:测试过 tp = 1,tp = 2,tp = 4,tp = 8 同时使用相同 gpu 数量的结果,其中 tp = 4 是效果最佳的)

具体 Deployment 配置如下图所示:

以下给出在 64 并发数和 128 并发数的结果如下:

4.2 dynamo

对第二部分部署的示例并且开启 RDMA 后进行了压测,其中包含 1 个 4 GPU 的 Decode Worker 以及 20 个 1 GPU 的 Prefill Worker。

(注:我们也尝试过其它的配比,诸如 1 个 4 tp 的 Decode Worker + 10 个 2 tp 的 Prefill Worker 等等,对比结果在当前 3 * H20 节点的情况下,上述配比是最大化 GPU 资源使用的)

在测试过程中,可以注意到 Decode Worker 内部使用 NvLink 进行通信,而 Decode Worker 和 Prefill Worker 之间通信使用的是 RDMA。

在 64 并发数和 128 并发数的结果如下:

4.3 结论

根据上述结果可以看到,使用 dynamo PD 分离情况下,相比于 vllm 0.7.2 版本(V0 引擎):

  • TTFT 在 P90 的请求中有很大提升,在 64、128 并发数下均只需 vLLM baseline 的 30 % - 40% 的时间;在 P99 的请求中也有一定的提升,是原本的 70% - 90%。
  • TTST 完全优于 baseline,主要原因可能是 PD 分离消除了两个阶段间的资源竞争。
  • ITL,也称为 TPOT,在 P90 和 P99 中相较于 vLLM baseline 也大概有 30 %左右的性能提升。
  • 整体响应时间 dynamo 也优于 baseline,提升幅度也在 10 - 20 %上下。
  • 吞吐量方面,dynamo 大约是 baseline 的 1.3 - 1.5 倍。

五、常见问题

如何解决 dynamo:latest-vllm 镜像无法拉取的问题?

目前 dynamo 镜像并没有官方供应,可以参照官方文档自行构建。以下提供一份在腾讯云 CVM 上构建的简易操作步骤:

代码语言:javascript代码运行次数:0运行复制
# 安装 docker
curl -fsSL  -o get-docker.sh
sh get-docker.sh

# 构建 dynamo 镜像
git clone .git --depth 1
cd dynamo
./container/build.sh

如何解决模型无法拉取,报错 huggingface 无法连接的问题?

如果你不提前下载模型,或者配置的模型路径不存在,那么 dynamo 会尝试从 huggingface 上拉取模型数据。 而在 TKE 的国内地域是无法访问 huggingface 的,可以在 Pod 上配置环境变量 VLLM_USE_MODELSCOPE = true 来切换成从 modelscope 下载模型。 (注意:默认构建的 dynamo 镜像中不包含 modelscope 包,所以需要提前在镜像中使用 pip install modelscope 下载好 modelscope 包,才能使用) 在这里,还是推荐大家先下载好模型,放置于 PVC 中,以便复用。

如何向 dynamo 中传入 vllm 的额外参数?

可以直接修改使用 configs.yaml 文件,在 VllmWorker 和 PrefillWorker 的配置中直接配置即可。例如要传入 --dtype=half 参数,可以这么配置:

代码语言:javascript代码运行次数:0运行复制
VllmWorker:
  # model 是模型文件所在路径
  model: /data/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B
  dtype: half
  ...
  
PrefillWorker:
  # model 是模型文件所在路径
  model: /data/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B
  dtype: half
  ...

使用官方提供的 etcd-values 无法创建 PVC?

在 TKE 上,默认的 CBS 最小支持创建的 PVC 容量为 10Gi,而在 dynamo 官方示例中提供的 values 并没有配置该容量,使用的是 helm chart 的默认值 8Gi,因此无法创建 PVC。只需参照部署指南修改 PVC 所需大小在 10Gi 以上即可。

代码语言:javascript代码运行次数:0运行复制
# 默认 pvc 申请的大小为 8Gi,在 TKE 上 CBS 申请最少为 10Gi,因此默认值无法使用。这里修改为 20 Gi。
helm install dynamo-llm-etcd \
    oci://registry-1.docker.io/bitnamicharts/etcd \
    --values etcd-values.yaml \
    --set persistence.size=20Gi

如何解决 worker 报错 Event API not supported with naive allocator ?

worker 报错 Event API not supported with naive allocator 的原因是开启了 kv 路由模式,但是没有设置 enable-prefix-caching。解决方法如下,在 VllmWorker 中开启 enable-prefix-caching。

代码语言:javascript代码运行次数:0运行复制
VllmWorker:
  # model 是模型文件所在路径
  model: /data/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B
  enable-prefix-caching: true
  router: kv
  ...

在 T4、V100 机器上运行报错 ValueError: not enough values to unpack (expected 5, got 3)

目前 dynamo 尚不支持 T4、V100 等架构较老的 GPU 机器,推荐使用 H20 以上的 GPU 机器。

如何使用 dynamo 部署多节点模型?

目前由于 nixl 限制 tp 最大为 8,所以没有办法参照以往多节点模型使用 ray 等的部署方法[6],当前无法很好地部署如 Deepseek-R1 671B 满血版等超大模型。

PD 分离的提升幅度有多大?

参照官方维护者的说法[7],在特定的吞吐量范围内,分解可以带来显著的优势。根据实验,以每个用户大约 30-60 Token/s 为目标的配置,在分解设置中往往比在单个聚合节点上显示出更好的性能。在此范围之外,传统设置(聚合)可能会优于分解方法。

举例来说,假设每个用户的目标是每秒 38 个 Token,输入 3000 个 Token,输出 150 个 Token。在这种情况下,与聚合式单节点方法相比,分解式配置可实现约 1.6 倍的性能提升(根据 GPU 数量归一化)。

dynamo 的分布式 KV Cache 管理器

dynamo 的分布式 KV Cache 管理器可将较旧或访问频率较低的 KV Cache 块卸载到更具成本效益的内存和存储解决方案中,如 CPU 内存、本地存储或网络对象或文件存储,从而解决了这一难题。这一功能使企业能够存储多达 PB 的 KV 缓存数据,而成本仅为 GPU 内存的一小部分。通过将 KV 缓存卸载到其他内存分层,开发人员可以释放宝贵的 GPU 资源,同时仍然保留和重复使用历史 KV 缓存,以降低推理计算成本。 该功能目前发布了 V1 版本作为概念验证设计,只提供了一个轻量级 KV 卸载框架,还尚未实现真正的卸载 KV Cache 到其它存储资源的功能。在 V2 版本,预计要引入跨工作实例和存储的分布式 KV 池,并纳入了上述设计中概述的所有功能。

如何检查推理服务是否使用 RDMA 进行通信?

首先在 Pod 上执行 ibv_devices 命令,确认存在 device;样例如下:

然后在推理服务运行过程中,使用 perfquery 命令确认 PortXmitData 和 PortRevData 的数值变化,如有变化,说明正在通过 RDMA 通信。

如何确定 PD 分离部署中 Prefill Worker 和 Decode Worker 的比例?

确定 Prefill Worker 和 Decode Worker 的比例是一件比较复杂的事情,跟以下事项都有关联:

  • GPU 硬件性能:不同的 GPU 在计算能力和显存大小上有很大区别,例如 H20 的显存和 H100 差距不大,但是计算能力只有 H100 的 20% 上下。
  • 关键性能指标的 SLO:这里我们先关注以下两个关键指标:TTFT,生成第一个 Token 需要的时间。ITL,也称为 TPOT,生成每一个 Token 平均需要的时间。
  • 真实请求的特征:这里主要指的是真实请求处理的 ISL(输入 Token 数) 和 OSL(输出 Token 数)。通常来讲,在 ISL 比较大而 OSL 比较小的情况下,会需要更多的 prefill 节点;而 ISL 比较小而 OSL 比较大的情况下,会需要更多的 decode 节点。
  • Prefill Worker 和 Decode Worker 的 tp 数配置:在最开始,将 Prefill Worker 的 tp 设置为最小,保证能加载模型即可。Deocde Worker 的 tp 一般设置为 Prefiil Worker 的 4 / 8 倍。如果在 Prefiil Worker 的 tp 设置为最小的情况,TTFT 无法达成 SLO,那么可以适当调大;同理,如果在 ITL 无法达成 SLO 的情况下,可以适当调大 Decode Worker 的 tp 数。(目前由于 nixl 的限制[6],tp 数最大设置为 8)

以下假设 P 和 D 使用的是相同型号的 GPU,确定 PD 比例的过程如下:

1. 首先根据真实请求的特征确定 ISL 和 OSL 来构造压力测试。推荐参考 dynamo 官方提供的脚本[3],使用 genai-perf 可以很方便地控制 ISL 和 OSL。

2. 确定关键性能指标的 SLO 和 Prefill Worker、Decode Worker 的 tp 数配置

3. 在确定 tp 数的基础上,先按照 P 和 D 的比例为 2:1 的配比(注:这里的配比指的是 GPU 数量)进行压力测试,P 的比例主要影响 TTFT 指标,D 的比例主要影响 ITL 指标,根据定义的 SLO 和压测效果调整 P、D 比例到最优效果。

六、后续社区部署演进方向

社区正在开发面向 Dynamo 组件的 Kubernetes Operator 体系,实现声明式生命周期管理范式。该架构遵循 Operator Pattern 设计原则,通过自定义资源定义(CRD)实现对 Dynamo 运行时拓扑的自动化编排。

在未来,Dynamo 支持通过命令行 CLI 工具或者可视化界面操作部署流程,通过执行 dynamo deploy 命令等方式构建 Dynamo Entities 并推送给 Dynamo API Server。Dynamo API Server 接收到部署请求后,将部署需求转化为 Kubernetes 的原生资源,如 DynamoDeployment、DynamoArtifact 等 CRD 资源。由 Dynamo Kubernetes Operator 将这些 CRD 资源转化为 Deployment、Service、HPA、ConfigMap 等资源,实现在云环境上的部署一致性。

最后,用户可以从 Dynamo API Server 处直接得到一个可直接访问的端点 URL,而不需要关心内部的部署架构。

图片来自 dynamo 官方文档

结语

NVIDIA 开源的 Dynamo 推理框架目前已发布到了 v0.0.1 版本,基于该版本的 PD 分离相较于直接使用 vLLM 部署 LLM 已经在性能上有所提升,但还有许多能力尚未实现,仍在开发当中:

  • KV Cache 管理器,现在发布了 V1 版本作为概念验证设计,提供了一个轻量级 KV 卸载框架,具有简单的异步 API - GET() 和 PUT(),允许推理引擎高效地卸载 KV 缓存。真正能投入生产的 V2 版本还在开发中。在 V2 版本,预计要引入跨工作实例和存储的分布式 KV 池,并纳入了设计中概述的所有功能。
  • Kubernetes Operator,包含自动伸缩、监控等核心功能。
  • 多节点模型部署、pipeline 并行等功能的支持,目前由于 nixl 限制 tp 最大为 8,当前无法很好地部署如 DeepSeek-R1 671B 满血版等超大模型。
  • Dynamo Planner,允许用户定义目标,然后根据系统反馈自动调整和优化性能策略,自动动态调整分配 Prefill 和 Decode 使用的 GPU 数量。
  • 对 vLLM V1 引擎的支持,相较于 V0 引擎,V1 引擎有较大的性能提升[4]。

本篇文章主要围绕着 dynamo ,介绍了如何在 TKE 上部署 PD 分离的大模型,以及简单的性能验证过程,希望能抛砖引玉,给大家带来一些启发,如有谬误,欢迎指正,一起交流。后续 TKE 将围绕 dynamo 做更多的技术解读和最佳实践分享。

参考资料

  1. Dynamo github 地址:
  2. 腾讯云云原生 etcd 创建集群的文档:
  3. genai-perf 压测脚本: .sh
  4. vllm V1: .html
  5. dynamo 官方文档: .md#dynamo-disaggregation-performance-tuning
  6. 多节点模型使用 ray 等的部署方法:
  7. PD 分离的提升幅度:
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-18,如有侵权请联系 cloudcommunity@tencent 删除nvidia部署模型配置性能

在 TKE 上使用 NVIDIA Dynamo 部署 PD 分离的大模型

刘瑾锋,腾讯云容器服务 TKE 后台开发工程师,主要负责容器服务(TKE)相关研发工作。

前言

在 2025 年 GTC 大会上,NVIDIA CEO 黄仁勋介绍了他们开源的 Dynamo 推理框架,并称它为“AI 工厂的超级操作系统”。 目前 Dynamo 在 github 上开源[1],它被设计用于在多节点分布式环境中为生成式人工智能和推理模型提供服务,支持多种推理引擎:包括 TRT-LLM、vLLM、SGLang 等等。 Dynamo 宣称具有以下核心特性:

  • 分解预填充和解码推理阶段:最大限度地提高 GPU 吞吐量,促进吞吐量和延迟之间的权衡。
  • 动态 GPU 调度:根据波动需求优化性能。
  • LLM 感知请求路由:消除不必要的 KV 缓存重新计算。
  • 加速数据传输:利用 NIXL 缩短推理响应时间。
  • KV 缓存卸载:利用多个内存分层提高系统吞吐量。

本文主要基于 dynamo 的分解预填充和解码推理阶段特性讲述如何在 TKE 上使用 dynamo 部署 PD 分离的大模型,分为以下六部分:

  • 第一部分,介绍 Dynamo 的 PD 分离架构。
  • 第二部分,给出一个在 TKE 上部署 PD 分离的示例。
  • 第三部分,介绍 Dynamo 的监控组件。
  • 第四部分,Dynamo PD 分离部署的性能验证,与 vLLM 进行对比。
  • 第五部分,部署过程中可能会遇到的一些常见问题,包括 dynamo 尚未实现的特性。
  • 第六部分,探讨 dynamo 之后的部署演变方向。

一、Dynamo 的 PD 分离是如何实现的?

PD 分离(Prefill-Decode Disaggregation)是一种针对大语言模型(LLM)推理过程的优化技术,其核心思想是将推理任务拆分为预填充(Prefill)解码(Decode)两个独立阶段,并分配到不同的计算资源上执行,以提升整体效率与资源利用率。这两个阶段对硬件资源的需求存在显著差异:

  • Prefill 阶段:计算密集型,需高算力并行处理输入提示(如 FP8 低精度加速),占用大量 GPU 算力但显存需求较低。
  • Decode 阶段:内存密集型,依赖高带宽显存频繁读取 KV 缓存,算力需求低但显存占用随上下文增长指数级上升。

Dynamo 在设计上将 Prefill 和 Decode 阶段交由不同的 Worker 执行,Prefiil Worker 从队列中获取需要执行的 Prefill 请求,并在完成 Prefill 后通知 Decode Worker,具体流程如下图所示:

Dynamo 通过引入 PrefillQueue 作为 Prefill 和 Decode 阶段的中间层,允许独立扩展 Prefill Worker 和 Decode Worker 的数量,不仅优化了资源利用率,还支持根据实时负载调整Worker数量,提升了整体性能和效率。

二、PD 分离部署指南

在以下示例中,本文使用了 3 个 H20 节点,每个节点上具有 8 个 GPU 核心,使用的推理引擎为 vLLM,模型为 neuralmagic/DeepSeek-R1-Distill-Llama-70B-FP8-dynamic,dynamo 镜像是基于 commit:

988e8826771888c9645857266032e11a7f67492a 构建的。

(注:这里没有选择满血版 DeepSeek R1 671B 作为测试模型的原因是目前 dynamo 使用 nixl 通信库,当前存在 tp 数必须小于等于 8 的限制,无法很好地部署 满血版 DeepSeek R1 671B 这种超大模型)

2.1 部署架构

在 Dynamo 中,一个典型的推理服务通常应该包括以下组件:

  • FrontEnd:与 OpenAI 兼容的 HTTP 服务器,用于处理传入请求。
  • Processor:处理请求,然后再将请求传递给 Worker。
  • Router:根据指定策略将请求路由到适当的 Worker。
  • Worker:处理实际的 LLM 推理(包括预填充和解码阶段)。

在架构上,本文使用了三个节点(也可以说是三个 Pod),每个节点部署了 Dynamo 的部分组件,具体而言:

Node 1
  • FrontEnd:与 OpenAI 兼容的 HTTP 服务器,用于处理传入请求。
  • Processor:处理请求,然后再将请求传递给 Worker。
  • Router:根据指定策略将请求路由到适当的 Worker。
  • VllmWorker:处理实际的 LLM 推理解码阶段,使用 4 个 GPU 核心,设置 tp = 4,worker = 1。
  • PrefillWorker:处理实际的 LLM 推理预填充阶段,使用 4 个 GPU 核心,设置 tp = 1,worker = 4。
Node 2
  • PrefillWorker:处理实际的 LLM 推理预填充阶段,使用 8 个 GPU 核心,设置 tp = 1,worker = 8。
Node 3
  • PrefillWorker:处理实际的 LLM 推理预填充阶段,使用 8 个 GPU 核心,设置 tp = 1,worker = 8。

也就是说在本示例中,我们使用了 1 个 4 GPU 的 Deocde 节点,以及 20 个 1 GPU 的 Prefill 节点,这个比例是根据在现有资源(3 * H20 节点)上的性能测试结果得出的。

各个节点详细的 configs 配置如下:

在部署完成后,一次推理的请求链路大致如下图所示:

2.2 中间件部署:nats 和 etcd

dynamo 依赖 nats 和 etcd 进行服务发现和通信,需要在所有节点中设置如下环境变量来确保组件之间可以通信:

代码语言:javascript代码运行次数:0运行复制
env:
- name: NATS_SERVER
  value: <your-nats-address> # nats://dynamo-llm-nats:4222
- name: ETCD_ENDPOINTS
  value: <your-etcd-address> # dynamo-llm-etcd:2379

以下提供一些示例部署 nats 和 etcd:

  • nats 的单节点部署
代码语言:javascript代码运行次数:0运行复制
# 假设当前所在路径为 dynamo 项目的根路径

# Add and update NATS Helm repository
helm repo add nats /
helm repo update

# Navigate to dependencies directory
cd deploy/Kubernetes/pipeline/dependencies

# Install NATS with custom values
helm install dynamo-llm-nats nats/nats --values nats-values.yaml
  • nats 的高可用部署 以下提供了一份 helm-chart 的 values 范例,可以通过该 values 部署一个高可用的 nats 集群。
  • etcd 的单节点部署
代码语言:javascript代码运行次数:0运行复制
# 假设当前所在路径为 dynamo 项目的根路径

# Navigate to dependencies directory
cd deploy/Kubernetes/pipeline/dependencies

# Install etcd using Bitnami chart
# 默认 pvc 申请的大小为 8Gi,在 TKE 上 CBS 申请最少为 10Gi,因此默认值无法使用。这里修改为 20 Gi。
helm install dynamo-llm-etcd \
    oci://registry-1.docker.io/bitnamicharts/etcd \
    --values etcd-values.yaml \
    --set persistence.size=20Gi
  • etcd 的高可用部署

这里推荐使用腾讯云提供的【云原生etcd】服务[2],腾讯云容器团队目前线上运维了上万套 K8S 集群,在保障 etcd 稳定运行的同时积累了大量的实践经验,可以帮助用户降低 etcd 的运维负担,从而更专注于业务发展。

2.3 Node 1

2.4 Node 2 & Node 3

2.5 API 验证

在上述过程中,我们创建了一个名为 deepseek-r1-llama-70b-dynamo-multinode 的 service,可以通过 kubectl port-forward 来快速验证 API。

代码语言:javascript代码运行次数:0运行复制
kubectl port-forward svc/deepseek-r1-llama-70b-dynamo-multinode

在另外一个终端调用 API,如下是用 curl 的一个示例:

代码语言:javascript代码运行次数:0运行复制
curl -X POST "http://localhost:80/v1/chat/completions" \ 
  -H "Content-Type: application/json" \ 
  -d '{
  "model": "neuralmagic/DeepSeek-R1-Distill-Llama-70B-FP8-dynamic",
  "messages": [
    {"role": "system", "content": "你是一个AI编程助手"},
    {"role": "user", "content": "用Python实现快速排序算法"}
  ],
  "temperature": 0.3,
  "max_tokens": 512,
  "top_p": 0.9
}'

三、Dynamo 的监控组件

要使用该组件,必须将 LLM 服务的 router 类型指定为 kv。

Dynamo 开发了 metrics 组件,专门用于监控 dynamo 的 LLM Worker 状态,目前提供如下指标:

  • llm_kv_blocks_active: 每个 Worker 的活动 KV 块数量
  • llm_kv_blocks_total: 每个 Worker 可用的 KV 块总数
  • llm_requests_active_slots: 每个 Worker 当前的活动请求插槽数量
  • llm_requests_total_slots: 每个 Worker 的可用请求插槽总数
  • llm_kv_hit_rate_percent: 每个 Worker 的累积 KV 缓存命中率
  • llm_load_avg: 各个 Worker 的平均负载
  • llm_load_std: 各个 Worker 的负载标准差

根据这些指标,可以画出如下的监控面板:

metrics 是一个独立组件,在 Kubernetes 集群环境下,你可以把它部署为 sidecar ,与 frontend 组件 Pod 绑定部署,也可以部署为一个独立 Pod,它的关键依赖项只有 etcd 和 nats,通过这两个中间件,metrics 组件实现了指标采集端点的发现和数据的收集,最后暴露到指定端口的 /metrics 路径。

当然,它也支持 push 模式,可以将收集到的指标推送到指定的 push gateway 端点上。

目前,metrics 作为一个独立二进制文件,你可以通过以下方式将它从原本的 dynamo 镜像(30+ GB)中拷贝出来,减少镜像大小至 100+ MB:

代码语言:javascript代码运行次数:0运行复制
FROM dynamo:latest-vllm AS bin
FROM ubuntu:24.04
COPY --from=bin /usr/local/bin/metrics /usr/local/bin/metrics

CMD ["metrics", "--component", "VllmWorker", "--endpoint", "load_metrics"]

四、与 vLLM 的性能对比

依据 dynamo 的 benchmark 示例,使用 genai-perf 进行压测[3],修改其中的 model、tokenizer、url 参数。

关注以下性能指标:

  • Time To First Token(TTFT):生成第一个 Token 所需要的时间。
  • Time To Second Token(TTST):生成第二个 Token 所需要的时间。
  • Request Latency:响应时间。
  • Inter Token Latency(ITL):平均每 Token 生成时间。

在性能对比过程中,以下配置项保持一致:

vllm 版本

0.7.2

block-size

128

max-model-len

3500

max-num-batched-tokens

3500

模型

euralmagic/DeepSeek-R1-Distill-Llama-70B-FP8-dynamic

模型大小

70B

  1. 为什么 vllm 版本使用 0.7.2 ? 目前 dynamo 只适配了 0.7.2 的 vllm,这里为了保持版本一致。(注意:vllm 的最新版本为 0.8.4,已经正式启用了 V1 引擎,在吞吐量方面相较于 0.7.2 大约有 1.7 倍的提升[4])
  2. 为什么设置 block-size 为 128?为了得到更好的性能,根据 dynamo 官方文档[5],大部分模型设置 block-size 为 128 的性能更好。
  3. 为什么设置 max-model-len 和 max-num-batched-tokens 为 3500?参考 dynamo 官方压测示例,模拟 chat 场景,设置了 ISL/OSL = 3000/150,请求中输入 token 数在 3000 左右,输出 token 数在 150 左右,需要的上下文长度在 3500 以内。

baseline 与 dynamo 部署的主要区别在于 tp(即 tensor-parallel-size)的设置,以及因为 dynamo 架构上 PD 分离导致的 Prefill Worker 和 Decode Worker 资源分配的问题。

4.1 vLLM baseline

我们部署了 6 个 vLLM 的 Pod 作为 baseline,设置 tp = 4,

(注:测试过 tp = 1,tp = 2,tp = 4,tp = 8 同时使用相同 gpu 数量的结果,其中 tp = 4 是效果最佳的)

具体 Deployment 配置如下图所示:

以下给出在 64 并发数和 128 并发数的结果如下:

4.2 dynamo

对第二部分部署的示例并且开启 RDMA 后进行了压测,其中包含 1 个 4 GPU 的 Decode Worker 以及 20 个 1 GPU 的 Prefill Worker。

(注:我们也尝试过其它的配比,诸如 1 个 4 tp 的 Decode Worker + 10 个 2 tp 的 Prefill Worker 等等,对比结果在当前 3 * H20 节点的情况下,上述配比是最大化 GPU 资源使用的)

在测试过程中,可以注意到 Decode Worker 内部使用 NvLink 进行通信,而 Decode Worker 和 Prefill Worker 之间通信使用的是 RDMA。

在 64 并发数和 128 并发数的结果如下:

4.3 结论

根据上述结果可以看到,使用 dynamo PD 分离情况下,相比于 vllm 0.7.2 版本(V0 引擎):

  • TTFT 在 P90 的请求中有很大提升,在 64、128 并发数下均只需 vLLM baseline 的 30 % - 40% 的时间;在 P99 的请求中也有一定的提升,是原本的 70% - 90%。
  • TTST 完全优于 baseline,主要原因可能是 PD 分离消除了两个阶段间的资源竞争。
  • ITL,也称为 TPOT,在 P90 和 P99 中相较于 vLLM baseline 也大概有 30 %左右的性能提升。
  • 整体响应时间 dynamo 也优于 baseline,提升幅度也在 10 - 20 %上下。
  • 吞吐量方面,dynamo 大约是 baseline 的 1.3 - 1.5 倍。

五、常见问题

如何解决 dynamo:latest-vllm 镜像无法拉取的问题?

目前 dynamo 镜像并没有官方供应,可以参照官方文档自行构建。以下提供一份在腾讯云 CVM 上构建的简易操作步骤:

代码语言:javascript代码运行次数:0运行复制
# 安装 docker
curl -fsSL  -o get-docker.sh
sh get-docker.sh

# 构建 dynamo 镜像
git clone .git --depth 1
cd dynamo
./container/build.sh

如何解决模型无法拉取,报错 huggingface 无法连接的问题?

如果你不提前下载模型,或者配置的模型路径不存在,那么 dynamo 会尝试从 huggingface 上拉取模型数据。 而在 TKE 的国内地域是无法访问 huggingface 的,可以在 Pod 上配置环境变量 VLLM_USE_MODELSCOPE = true 来切换成从 modelscope 下载模型。 (注意:默认构建的 dynamo 镜像中不包含 modelscope 包,所以需要提前在镜像中使用 pip install modelscope 下载好 modelscope 包,才能使用) 在这里,还是推荐大家先下载好模型,放置于 PVC 中,以便复用。

如何向 dynamo 中传入 vllm 的额外参数?

可以直接修改使用 configs.yaml 文件,在 VllmWorker 和 PrefillWorker 的配置中直接配置即可。例如要传入 --dtype=half 参数,可以这么配置:

代码语言:javascript代码运行次数:0运行复制
VllmWorker:
  # model 是模型文件所在路径
  model: /data/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B
  dtype: half
  ...
  
PrefillWorker:
  # model 是模型文件所在路径
  model: /data/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B
  dtype: half
  ...

使用官方提供的 etcd-values 无法创建 PVC?

在 TKE 上,默认的 CBS 最小支持创建的 PVC 容量为 10Gi,而在 dynamo 官方示例中提供的 values 并没有配置该容量,使用的是 helm chart 的默认值 8Gi,因此无法创建 PVC。只需参照部署指南修改 PVC 所需大小在 10Gi 以上即可。

代码语言:javascript代码运行次数:0运行复制
# 默认 pvc 申请的大小为 8Gi,在 TKE 上 CBS 申请最少为 10Gi,因此默认值无法使用。这里修改为 20 Gi。
helm install dynamo-llm-etcd \
    oci://registry-1.docker.io/bitnamicharts/etcd \
    --values etcd-values.yaml \
    --set persistence.size=20Gi

如何解决 worker 报错 Event API not supported with naive allocator ?

worker 报错 Event API not supported with naive allocator 的原因是开启了 kv 路由模式,但是没有设置 enable-prefix-caching。解决方法如下,在 VllmWorker 中开启 enable-prefix-caching。

代码语言:javascript代码运行次数:0运行复制
VllmWorker:
  # model 是模型文件所在路径
  model: /data/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B
  enable-prefix-caching: true
  router: kv
  ...

在 T4、V100 机器上运行报错 ValueError: not enough values to unpack (expected 5, got 3)

目前 dynamo 尚不支持 T4、V100 等架构较老的 GPU 机器,推荐使用 H20 以上的 GPU 机器。

如何使用 dynamo 部署多节点模型?

目前由于 nixl 限制 tp 最大为 8,所以没有办法参照以往多节点模型使用 ray 等的部署方法[6],当前无法很好地部署如 Deepseek-R1 671B 满血版等超大模型。

PD 分离的提升幅度有多大?

参照官方维护者的说法[7],在特定的吞吐量范围内,分解可以带来显著的优势。根据实验,以每个用户大约 30-60 Token/s 为目标的配置,在分解设置中往往比在单个聚合节点上显示出更好的性能。在此范围之外,传统设置(聚合)可能会优于分解方法。

举例来说,假设每个用户的目标是每秒 38 个 Token,输入 3000 个 Token,输出 150 个 Token。在这种情况下,与聚合式单节点方法相比,分解式配置可实现约 1.6 倍的性能提升(根据 GPU 数量归一化)。

dynamo 的分布式 KV Cache 管理器

dynamo 的分布式 KV Cache 管理器可将较旧或访问频率较低的 KV Cache 块卸载到更具成本效益的内存和存储解决方案中,如 CPU 内存、本地存储或网络对象或文件存储,从而解决了这一难题。这一功能使企业能够存储多达 PB 的 KV 缓存数据,而成本仅为 GPU 内存的一小部分。通过将 KV 缓存卸载到其他内存分层,开发人员可以释放宝贵的 GPU 资源,同时仍然保留和重复使用历史 KV 缓存,以降低推理计算成本。 该功能目前发布了 V1 版本作为概念验证设计,只提供了一个轻量级 KV 卸载框架,还尚未实现真正的卸载 KV Cache 到其它存储资源的功能。在 V2 版本,预计要引入跨工作实例和存储的分布式 KV 池,并纳入了上述设计中概述的所有功能。

如何检查推理服务是否使用 RDMA 进行通信?

首先在 Pod 上执行 ibv_devices 命令,确认存在 device;样例如下:

然后在推理服务运行过程中,使用 perfquery 命令确认 PortXmitData 和 PortRevData 的数值变化,如有变化,说明正在通过 RDMA 通信。

如何确定 PD 分离部署中 Prefill Worker 和 Decode Worker 的比例?

确定 Prefill Worker 和 Decode Worker 的比例是一件比较复杂的事情,跟以下事项都有关联:

  • GPU 硬件性能:不同的 GPU 在计算能力和显存大小上有很大区别,例如 H20 的显存和 H100 差距不大,但是计算能力只有 H100 的 20% 上下。
  • 关键性能指标的 SLO:这里我们先关注以下两个关键指标:TTFT,生成第一个 Token 需要的时间。ITL,也称为 TPOT,生成每一个 Token 平均需要的时间。
  • 真实请求的特征:这里主要指的是真实请求处理的 ISL(输入 Token 数) 和 OSL(输出 Token 数)。通常来讲,在 ISL 比较大而 OSL 比较小的情况下,会需要更多的 prefill 节点;而 ISL 比较小而 OSL 比较大的情况下,会需要更多的 decode 节点。
  • Prefill Worker 和 Decode Worker 的 tp 数配置:在最开始,将 Prefill Worker 的 tp 设置为最小,保证能加载模型即可。Deocde Worker 的 tp 一般设置为 Prefiil Worker 的 4 / 8 倍。如果在 Prefiil Worker 的 tp 设置为最小的情况,TTFT 无法达成 SLO,那么可以适当调大;同理,如果在 ITL 无法达成 SLO 的情况下,可以适当调大 Decode Worker 的 tp 数。(目前由于 nixl 的限制[6],tp 数最大设置为 8)

以下假设 P 和 D 使用的是相同型号的 GPU,确定 PD 比例的过程如下:

1. 首先根据真实请求的特征确定 ISL 和 OSL 来构造压力测试。推荐参考 dynamo 官方提供的脚本[3],使用 genai-perf 可以很方便地控制 ISL 和 OSL。

2. 确定关键性能指标的 SLO 和 Prefill Worker、Decode Worker 的 tp 数配置

3. 在确定 tp 数的基础上,先按照 P 和 D 的比例为 2:1 的配比(注:这里的配比指的是 GPU 数量)进行压力测试,P 的比例主要影响 TTFT 指标,D 的比例主要影响 ITL 指标,根据定义的 SLO 和压测效果调整 P、D 比例到最优效果。

六、后续社区部署演进方向

社区正在开发面向 Dynamo 组件的 Kubernetes Operator 体系,实现声明式生命周期管理范式。该架构遵循 Operator Pattern 设计原则,通过自定义资源定义(CRD)实现对 Dynamo 运行时拓扑的自动化编排。

在未来,Dynamo 支持通过命令行 CLI 工具或者可视化界面操作部署流程,通过执行 dynamo deploy 命令等方式构建 Dynamo Entities 并推送给 Dynamo API Server。Dynamo API Server 接收到部署请求后,将部署需求转化为 Kubernetes 的原生资源,如 DynamoDeployment、DynamoArtifact 等 CRD 资源。由 Dynamo Kubernetes Operator 将这些 CRD 资源转化为 Deployment、Service、HPA、ConfigMap 等资源,实现在云环境上的部署一致性。

最后,用户可以从 Dynamo API Server 处直接得到一个可直接访问的端点 URL,而不需要关心内部的部署架构。

图片来自 dynamo 官方文档

结语

NVIDIA 开源的 Dynamo 推理框架目前已发布到了 v0.0.1 版本,基于该版本的 PD 分离相较于直接使用 vLLM 部署 LLM 已经在性能上有所提升,但还有许多能力尚未实现,仍在开发当中:

  • KV Cache 管理器,现在发布了 V1 版本作为概念验证设计,提供了一个轻量级 KV 卸载框架,具有简单的异步 API - GET() 和 PUT(),允许推理引擎高效地卸载 KV 缓存。真正能投入生产的 V2 版本还在开发中。在 V2 版本,预计要引入跨工作实例和存储的分布式 KV 池,并纳入了设计中概述的所有功能。
  • Kubernetes Operator,包含自动伸缩、监控等核心功能。
  • 多节点模型部署、pipeline 并行等功能的支持,目前由于 nixl 限制 tp 最大为 8,当前无法很好地部署如 DeepSeek-R1 671B 满血版等超大模型。
  • Dynamo Planner,允许用户定义目标,然后根据系统反馈自动调整和优化性能策略,自动动态调整分配 Prefill 和 Decode 使用的 GPU 数量。
  • 对 vLLM V1 引擎的支持,相较于 V0 引擎,V1 引擎有较大的性能提升[4]。

本篇文章主要围绕着 dynamo ,介绍了如何在 TKE 上部署 PD 分离的大模型,以及简单的性能验证过程,希望能抛砖引玉,给大家带来一些启发,如有谬误,欢迎指正,一起交流。后续 TKE 将围绕 dynamo 做更多的技术解读和最佳实践分享。

参考资料

  1. Dynamo github 地址:
  2. 腾讯云云原生 etcd 创建集群的文档:
  3. genai-perf 压测脚本: .sh
  4. vllm V1: .html
  5. dynamo 官方文档: .md#dynamo-disaggregation-performance-tuning
  6. 多节点模型使用 ray 等的部署方法:
  7. PD 分离的提升幅度:
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-18,如有侵权请联系 cloudcommunity@tencent 删除nvidia部署模型配置性能

本文标签: 在 TKE 上使用 NVIDIA Dynamo 部署 PD 分离的大模型