【推理】NVIDIA DLI培训:大规模部署与优化 AI 推理(推理原理,K8S,网关层,pd分离,MoE,Dynamo)
文章目录
- [【推理】NVIDIA DLI培训:大规模部署与优化 AI 推理(推理原理,K8S,网关层,pd分离,MoE,Dynamo)](#【推理】NVIDIA DLI培训:大规模部署与优化 AI 推理(推理原理,K8S,网关层,pd分离,MoE,Dynamo))
-
- [一、LLM 推理原理](#一、LLM 推理原理)
-
- [1.1 扩展定律与推理的物理约束](#1.1 扩展定律与推理的物理约束)
- [1.2 推理性能指标与业务 SLO](#1.2 推理性能指标与业务 SLO)
- [二、K8s 基础与单体架构](#二、K8s 基础与单体架构)
-
- [2.1 Kubernetes 基础与组件分工](#2.1 Kubernetes 基础与组件分工)
- [2.2 单体服务的部署与运行基线](#2.2 单体服务的部署与运行基线)
- [2.3 规模化前的优化检查项](#2.3 规模化前的优化检查项)
- 三、网关层与韧性工程
-
- [3.1 网关控制平面与统一模型入口](#3.1 网关控制平面与统一模型入口)
- [3.2 接入控制:身份、token 配额与并发预算](#3.2 接入控制:身份、token 配额与并发预算)
- [3.3 请求生命周期:超时、重试、取消与排空](#3.3 请求生命周期:超时、重试、取消与排空)
- [3.4 灰度发布与请求镜像](#3.4 灰度发布与请求镜像)
- [3.5 使用 KEDA 实现弹性扩容](#3.5 使用 KEDA 实现弹性扩容)
- [四、打破单体架构:解耦推理、MoE 与 Dynamo](#四、打破单体架构:解耦推理、MoE 与 Dynamo)
-
- [4.1 聚合、解耦与缓存路由](#4.1 聚合、解耦与缓存路由)
- [4.2 PD 分离:预填充与解码分离](#4.2 PD 分离:预填充与解码分离)
- [4.3 MoE:密集型、稀疏型与专家并行](#4.3 MoE:密集型、稀疏型与专家并行)
- [4.4 Dynamo 架构:路由、缓存、传输与资源规划](#4.4 Dynamo 架构:路由、缓存、传输与资源规划)
- [4.5 Grove 编排与拓扑调度](#4.5 Grove 编排与拓扑调度)
- [五、Dynamo 架构实战:部署、调优与验证](#五、Dynamo 架构实战:部署、调优与验证)
-
- [5.1 部署与基准测试:比较不同资源配置](#5.1 部署与基准测试:比较不同资源配置)
- [5.2 用观测数据定位性能瓶颈](#5.2 用观测数据定位性能瓶颈)
- [5.3 生产验收与发布闭环](#5.3 生产验收与发布闭环)


大规模 AI 推理系统需要兼顾模型质量、延迟、吞吐量、成本与可靠性。推理优化决定处理能力,网关与编排机制决定这些能力如何稳定地服务于业务。
模型服务能响应请求之后,怎样在流量增长时保持延迟可控,并判断新增 GPU 是否花得值得?
NVIDIA 本次课程主要包含,从 LLM 推理原理、K8s 与单体部署,逐步讨论网关治理、弹性扩容,以及预填充/解码分离、MoE 和 Dynamo 分布式架构。
文中会区分两类内容:通用的工程机制 ,例如容量规划、统一接入、背压、弹性扩容与缓存路由;课程采用的具体实现,例如 NIM、Dynamo、NIXL 和 Grove。后者既包含产品,也包含 NVIDIA 主导的开源项目,不能一概视为商业产品;Envoy AI Gateway、KEDA 等社区工具也不属于 NVIDIA 专有能力。理解各层解决的问题后,可以结合自己的部署平台选择实现。
以下部署和压测示例用于说明配置思路,生产建议是基于这些机制整理的落地检查项;课程实验本身不能替代真实业务的容量、质量和故障验证。
一、LLM 推理原理
1.1 扩展定律与推理的物理约束
课程讨论的扩展趋势包括更大的模型、更长的上下文和更多推理时计算。增加推理步骤、候选生成与验证预算,可以改善复杂任务表现,具体收益需要评测。模型规模影响权重存储与计算量,上下文长度影响 KV 占用,长推理和 Agent 多次调用则增加总执行工作量。
自回归大语言模型的推理通常包含两个阶段。
**预填充(Prefill)**处理输入序列,计算注意力所需的键和值,建立 KV 缓存。长输入提供较大的并行计算空间,通常形成计算密集型负载,常见于长文档分析与检索增强问答。
**解码(Decode)**逐步生成后续 token 并更新缓存。较小批量下,权重与缓存读取容易受到显存带宽限制。代码生成、长篇回答和推理模型的长输出会持续占用解码资源。
实际瓶颈受批量、模型结构、精度和并行策略影响,输入与输出增长需要分别评估。
| 负载类型 | 典型业务 | 主要关注点 | 优化方向 |
|---|---|---|---|
| 长输入、短输出 | 文档分类、检索增强问答 | 输入处理时间、首 token 延迟 | 减少有效输入、复用前缀、提高预填充能力 |
| 中短输入、长输出 | 代码生成、长回复、推理任务 | 输出速度、解码资源占用 | 控制生成预算、优化解码、增加解码容量 |
| 重复前缀、多轮请求 | 固定系统提示词、连续对话、Agent 调用 | 缓存命中率、重复计算 | 前缀缓存、KV 缓存感知路由 |
| 混合且波动的流量 | 多租户模型平台 | 尾延迟、排队、公平分配 | 网关治理、弹性扩容、分阶段调度 |
1.2 推理性能指标与业务 SLO
**服务等级目标(SLO)**量化服务性能与可用性。交互式应用关注尾延迟和输出速度,批量系统关注完成量与任务成本。
| 指标 | 定义 | 工程意义 |
|---|---|---|
| TTFT | 从发起请求到收到首个输出 token 的时间 | 包含网络、排队、输入处理及首 token 生成等开销 |
| ITL | 相邻输出 token 之间的时间间隔 | 描述生成过程的流畅程度及延迟波动 |
| TPOT | 每个后续输出 token 的平均生成时间 | 用于概括单次请求的解码速度 |
| 请求端到端延迟 | 从请求发起到响应完成的时间 | 衡量完整任务的等待时间 |
| 输出 token 吞吐量 | 单位时间生成的输出 token 数 | 衡量服务总体产出能力 |
| 排队请求数 | 已接收、尚未进入执行的请求数量 | 反映供需失衡与容量压力 |
对于至少生成两个 token 的流式请求,可以近似表示为:
text
端到端延迟 ≈ TTFT +(输出 token 数 − 1)× TPOT
评估应统一客户端与服务端口径,区分首个流式事件与最终回答的首字延迟,并结合平均值和 P95、P99 分析慢请求。
二、K8s 基础与单体架构
2.1 Kubernetes 基础与组件分工
Kubernetes 通过 Pod 承载容器、Deployment 管理副本、Service 提供访问、PVC 声明存储。推理工作负载还需配置 GPU 资源、节点选择、容忍与就绪探针。
从职责上看,可以把推理平台分为模型执行、接入治理、资源编排三个层次,再用指标、日志和追踪贯穿各层。使用其他平台部署模型服务时,这一分工仍然适用;下面的组件是课程在各层采用的具体实现,并非全部必选。
| 组件 | 所在层次与职责 | 实现归属与使用边界 |
|---|---|---|
| vLLM | 模型执行:模型计算、批处理与缓存管理 | 社区开源推理引擎,可独立部署 |
| TensorRT-LLM | 模型执行:面向 NVIDIA GPU 优化推理 | NVIDIA 开源项目,优化能力与其软硬件生态相关 |
| NVIDIA NIM | 模型服务封装:提供模型运行时、配置与服务接口 | NVIDIA 产品;封装范围和可用配置依具体模型及版本而定 |
| Envoy AI Gateway | 接入治理:模型路由、API 适配与 token 统计,结合 Envoy Gateway 执行认证等策略 | 社区开源项目;资源名称和配置方式属于该实现 |
| KEDA | 资源编排:将外部指标接入扩缩容控制 | 通用的 Kubernetes 开源组件,可用于多种工作负载 |
| NVIDIA Dynamo | 分布式推理协调:缓存路由、阶段解耦与资源规划 | NVIDIA 主导的开源框架,需结合推理后端及组件配置使用 |
| Grove | 资源编排:表达角色依赖与编组调度要求 | NVIDIA 主导的开源项目,面向多组件工作负载 |
2.2 单体服务的部署与运行基线
这里的"单体"指预填充与解码聚合在同一执行单元中,并不意味着整个业务系统只有一个服务。它可以通过多个副本扩容,每个执行单元也可以使用一张或多张 GPU;比较性能时,需要固定模型、引擎、精度与并行配置。
课程使用 NIM 演示模型服务封装:将模型资产、优化运行时和 API 组合为可部署的微服务。NIM 承担的是这套方案中的交付与运行封装;GPU 分配、流量治理和生命周期管理仍需平台配合。下面讨论的这些机制,也适用于直接部署 vLLM 等推理引擎。
模型文件缓存减少重复下载,KV 缓存减少重复计算。权重加载、初始化与预热耗时,以及存储吞吐,都应纳入扩容预算。
启动探针为初始化保留时间,就绪探针决定实例能否接收流量。生产基线应覆盖 GPU 分配、模型版本、真实推理请求与指标采集,再将健康实例接入统一网关。
2.3 规模化前的优化检查项
应用侧应设置输入与生成预算。多轮对话增加输入 token,长输出占用解码时间,输出格式与停止条件需要随任务配置。
| 参数或机制 | 使用方式 | 需要验证的结果 |
|---|---|---|
max_tokens、stop |
设置生成上限或结束条件 | 输出完整性、实际生成长度、结束原因 |
reasoning_effort |
为支持该参数的模型配置推理预算 | 任务正确率、耗时、最终回答是否完整 |
stream |
通过 SSE 增量返回内容 | 首字延迟、流中断处理、完整响应时间 |
| 对话历史与上下文上限 | 管理输入长度及历史保留 | 任务质量、预填充时间、缓存占用 |
生成预算需要结合 finish_reason、实际 token 使用量和回答完整性验证。推理模型可能在最终回答出现前耗尽预算,结构化响应还需要应用侧校验。
客户端并发增加批处理机会,也可能提高显存占用、排队与尾延迟,需要通过负载测试确定合理区间。
模型与执行层优化
下面这些是推理引擎中常见的优化思路,并非 NIM 或 Dynamo 独有。具体能否启用、如何组合,取决于模型、引擎版本和硬件支持:
| 优化机制 | 工作原理 | 收益条件与代价 |
|---|---|---|
| 低精度与量化 | 减少权重或相关张量的位宽 | 节省存储与带宽;需要硬件、内核支持及质量评测 |
| 连续批处理 | 请求完成后及时将新请求加入执行批次 | 提高资源利用率;批量与延迟之间需要权衡 |
| 分块预填充 | 将长输入拆分为较小计算块,与解码交错调度 | 缓解长输入对正在生成请求的干扰 |
| 推测性解码 | 草稿模型提出多个候选 token,由目标模型验证 | 收益取决于接受率、验证成本及额外资源占用 |
| 分页 KV 缓存 | 按块分配和管理缓存,减少预留空间与碎片 | 提高显存利用效率,支持更多在途请求 |
| 前缀缓存 | 复用相同 token 前缀对应的 KV 状态 | 减少重复预填充;依赖前缀重合、缓存保留与路由策略 |
BF16 和 FP8 分别使用 16 位、8 位表示。32B 模型的主权重可粗略估算为 64 GB、32 GB,实际显存还包含缓存、工作空间与未量化张量。
权重量化与 KV 量化是独立配置。精度选择应比较业务质量、TTFT、吞吐量与显存压力,并验证节省的空间能否提高有效并发。
显存容量还需要按照在途请求的上下文长度规划。对于采用常规 KV 布局的模型,可作如下粗略估算:
text
显存预算 = 模型权重 + KV 缓存 + 运行工作空间 + 预留余量
KV 缓存字节数 ≈ 2 × 层数 × KV 头数 × 头维度 × 已缓存 token 总数 × 每元素字节数
其中,系数 2 对应 Key 和 Value。共享缓存块需要去重计数,滑动窗口、压缩布局和模型并行会改变实际占用。容量测试应覆盖真实的输入、输出长度分布,同时观察 KV 使用率、排队与请求抢占,确定满足 SLO 的并发上限。
三、网关层与韧性工程
3.1 网关控制平面与统一模型入口
统一入口、身份认证、路由、限流和使用量统计是通用的接入治理需求。课程选择 Envoy Gateway 与 Envoy AI Gateway 来实现;其他网关也可以承担这些职责,但协议支持与策略能力需要逐项确认。
在这套实现中,网关控制平面负责监听 Gateway、路由与策略资源,将声明配置转换并下发。数据平面由 Envoy 代理及 AI 外部处理器承接请求,执行认证、路由、限流和使用量统计。配置是否生效与请求是否正常,需要分别观察控制器状态和请求链路。
多个模型直接暴露后,客户端需要分别管理地址、认证方式和调用规则。统一网关可以集中维护这些接口契约,并将不同模型纳入一致的访问治理体系。
课程中的资源链路为:
text
Gateway → AIGatewayRoute → AIServiceBackend → Backend → 模型服务或 Dynamo 前端
GatewayClass 指定控制器实现,Gateway 声明监听器,AIGatewayRoute 配置 AI 请求路由与 token 使用统计,AIServiceBackend 描述后端的 API schema,Backend 指向服务端点。其中,Backend 属于 Envoy Gateway 扩展,另外两个 AI 资源属于 Envoy AI Gateway 扩展。
课程采用 x-model 请求头选择模型或部署配置,例如 vllm-agg、vllm-disagg。这是实验约定的路由方式,并非所有模型 API 的通用要求。请求体中的 model 描述后端模型,两者可以通过模型名称映射保持一致。稳定的业务模型名称有助于在后端版本切换时维持客户端契约。
下面示例假定已配置与 x-model: Qwen/Qwen3-32B 对应的网关路由及 API Key 认证:
bash
# GATEWAY_BASE_URL 与 INFERENCE_API_KEY 预先设置为实际入口和客户端密钥
curl --fail-with-body --max-time 120 \
"$GATEWAY_BASE_URL/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "x-api-key: $INFERENCE_API_KEY" \
-H "x-model: Qwen/Qwen3-32B" \
-d '{"model":"Qwen/Qwen3-32B","messages":[{"role":"user","content":"简要说明预填充与解码的区别。"}],"max_tokens":256}'
跨命名空间引用应按实际资源关系配置 ReferenceGrant。网络访问还需要结合 Service 可达性、NetworkPolicy 与后端授权配置验证。
3.2 接入控制:身份、token 配额与并发预算
课程使用 Envoy Gateway 的 SecurityPolicy 从 x-api-key 提取客户端凭据,并使用 BackendTrafficPolicy 配置限流和后端流量策略。这些资源名属于具体实现;换用其他网关时,需要保留的是"认证身份---租户配额---后端容量"的约束关系。生产使用时,配额身份应来自认证结果或受信任的上游映射,客户端提交的用户标识需要经过验证。
token 配额比单纯的请求次数更能反映 LLM 请求长度差异。例如,十次短请求与一次长文档请求,即使请求次数接近,也可能占用不同数量的计算资源。输入 token、输出 token 与总 token 可以分别形成预算;具体 GPU 成本还受到模型、缓存命中、批处理和两个推理阶段的影响。
Envoy AI Gateway 的外部处理器从响应中提取 token 使用量,供统计与配额扣减使用。响应完成后才确定的使用量需要结合请求大小上限、生成预算与在途并发限制,才能控制突发占用。
后端通过在途请求数与队列上限控制容量。长输入增加预填充压力,长输出持续占用解码资源,同一并发数也可能形成不同负载。因此,应结合任务类型设置接入预算,在容量不足时实施背压,并区分租户配额耗尽与服务过载。
3.3 请求生命周期:超时、重试、取消与排空
请求需要一个覆盖网关、排队与模型执行的总时间预算。每次重试都应受剩余预算约束,并使用退避和次数上限。连接失败等短暂故障可以重试,持续过载需要接入控制和容量恢复;重试流量本身也会消耗推理资源。
流式响应开始交付后,应用需要定义中断、重连与结果状态。客户端取消或断开连接时,取消信号应传递到推理引擎,使无效任务及时退出执行。验证时应检查在途请求退出与缓存块复用;引擎预分配的显存可能继续保留。
发布与缩容需要先停止新请求进入待终止实例,再处理已有长连接。Kubernetes 会更新终止端点的状态,具体排空仍依赖网关和服务的实现。preStop、进程的终止信号处理与 terminationGracePeriodSeconds 应协调配置,为已有请求留出完成时间,并定义超出时间预算后的处理方式。
例如,两个副本滚动更新时,应观察新实例的加载与就绪、旧实例的长流式请求完成情况,以及剩余实例的排队变化,将请求连续性与备用容量一起验收。
3.4 灰度发布与请求镜像
灰度发布 将真实请求按权重分配给不同后端,客户端会收到对应后端的响应。请求镜像将请求副本发送到影子后端,客户端继续接收主后端响应。两者适用于不同的上线阶段。
课程以 BF16、FP8 后端演示 90/10 流量拆分。流量拆分和镜像是通用的发布手段,BF16、FP8 只是这个实验中的后端差异。生产验证需要统一模型名称与输入输出契约,采集有效响应比较质量。镜像会增加计算与数据处理量,应配置采样比例和预算;灰度推进依据错误率、尾延迟和任务质量,并保留回滚配置。
3.5 使用 KEDA 实现弹性扩容
KEDA 提供外部指标接入与扩缩容配置,并为工作负载创建和管理 HPA。HPA 本身也支持自定义及外部指标;KEDA 将指标接入和触发器配置集中到 ScaledObject 中。
这部分的通用思路是"根据需求信号调整服务容量"。KEDA 是一种实现方式;如果已有平台具备指标驱动的扩缩容能力,应先确认指标口径、冷启动处理和缩容策略是否满足需求,再决定是否引入额外组件。
推理扩容应结合运行请求、排队请求、KV 压力与延迟趋势。运行请求数反映正在执行的负载,排队请求数反映未被满足的需求;执行批量达到上限后,队列仍可能继续增长。GPU 利用率作为辅助信号,需要与这些指标关联。
以下示例将课程配置整理为通用推理 Deployment,使用**总运行请求数与 AverageValue**表达每副本目标。工作负载名为 model-inference,命名空间为 inference;示例阈值 30 和副本范围 1~2 应根据实际容量测试调整:
yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: model-inference-scaler
namespace: inference
spec:
scaleTargetRef:
name: model-inference
minReplicaCount: 1
maxReplicaCount: 2
advanced:
horizontalPodAutoscalerConfig:
behavior:
scaleDown:
stabilizationWindowSeconds: 600
triggers:
- type: prometheus
metricType: AverageValue
metadata:
serverAddress: http://kube-prometheus-stack-prometheus.prometheus:9090
query: sum(vllm:num_requests_running{namespace="inference",pod=~"model-inference-.*"})
threshold: "30"
ignoreNullValues: "false"
在这一口径下,总运行请求数为 45、每副本目标为 30 时,理想目标副本数为 ceil(45 / 30) = 2;实际结果还受到 HPA 容差、稳定窗口与副本上限影响。如果改用平均值查询,需要重新核对 metricType 与 HPA 计算方式,避免对已经取平均的指标再次按副本数摊分。
1 个以上副本之间的缩容稳定行为由 HPA 配置控制。KEDA 的 cooldownPeriod 主要用于回到零副本的等待过程,当前示例通过 minReplicaCount: 1 保留基础容量。
扩容验证需要覆盖"指标升高---目标副本增加---新 Pod 就绪---请求分流---延迟恢复"。Pod 扩容依赖已有 GPU 容量,GPU 节点供给属于另一个控制层次;模型加载还会增加冷启动时间。基础副本和预留容量应覆盖这一恢复窗口。
指标中断时的副本行为需要明确配置并告警。HPA、工作负载 Operator 与 GitOps 应协调字段管理,GPU 节点扩容应与 Pod 扩容分别观测。
四、打破单体架构:解耦推理、MoE 与 Dynamo
4.1 聚合、解耦与缓存路由
预填充/解码分离、KV 缓存感知路由和模型并行是通用的推理架构思路。Dynamo 是课程采用的分布式推理实现,负责协调多个工作节点,将请求路由、KV 状态、预填充与解码资源纳入系统级优化;课程中的模型计算仍由 vLLM 后端执行。
课程比较了四种部署模式:
| 部署模式 | 阶段组织方式 | 工作节点选择方式 | 重点验证 |
|---|---|---|---|
vllm-agg |
同一 worker 处理预填充与解码 | 基础路由 | 聚合服务基线 |
vllm-agg-router |
保持聚合执行 | KV 缓存感知路由 | 缓存复用与负载分配 |
vllm-disagg |
独立预填充、解码 worker | 基础解耦调度 | 阶段分离的收益与传输成本 |
vllm-disagg-router |
保持阶段解耦 | KV 缓存感知路由 | 两种机制组合后的效果 |
聚合与解耦 决定两个阶段在哪里执行、如何分配资源;KV 缓存感知路由决定请求分配到哪个工作节点。两种机制可以独立配置,分别对应资源隔离与重复计算问题。
聚合部署中的 worker 可以使用多张 GPU,也可以部署多个副本。解耦部署可以在同一节点的不同 GPU 上运行,也可以跨节点运行。评估时应同时记录阶段结构、GPU 数量、节点位置和通信方式。
4.2 PD 分离:预填充与解码分离
解耦配置为预填充和解码建立独立工作节点。预填充构建 KV 状态,解码基于这些状态继续生成。在课程的 Dynamo 方案中,相关数据通过 NIXL 传输;阶段分离需要 KV 交接机制,但并不要求所有实现都采用 NIXL。
课程版本的 Dynamo 设计还包含条件解耦:工作节点可以根据有效预填充长度、缓存命中与预填充队列状态,决定本地处理或提交远程预填充任务。以下图示表达这套方案中远程预填充的逻辑协作关系,具体调用和传输路径取决于后端集成:
#mermaid-svg-AD10EBwKLBH0ivHs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AD10EBwKLBH0ivHs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AD10EBwKLBH0ivHs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AD10EBwKLBH0ivHs .error-icon{fill:#552222;}#mermaid-svg-AD10EBwKLBH0ivHs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AD10EBwKLBH0ivHs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AD10EBwKLBH0ivHs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AD10EBwKLBH0ivHs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AD10EBwKLBH0ivHs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AD10EBwKLBH0ivHs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AD10EBwKLBH0ivHs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AD10EBwKLBH0ivHs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AD10EBwKLBH0ivHs .marker.cross{stroke:#333333;}#mermaid-svg-AD10EBwKLBH0ivHs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AD10EBwKLBH0ivHs p{margin:0;}#mermaid-svg-AD10EBwKLBH0ivHs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-AD10EBwKLBH0ivHs .cluster-label text{fill:#333;}#mermaid-svg-AD10EBwKLBH0ivHs .cluster-label span{color:#333;}#mermaid-svg-AD10EBwKLBH0ivHs .cluster-label span p{background-color:transparent;}#mermaid-svg-AD10EBwKLBH0ivHs .label text,#mermaid-svg-AD10EBwKLBH0ivHs span{fill:#333;color:#333;}#mermaid-svg-AD10EBwKLBH0ivHs .node rect,#mermaid-svg-AD10EBwKLBH0ivHs .node circle,#mermaid-svg-AD10EBwKLBH0ivHs .node ellipse,#mermaid-svg-AD10EBwKLBH0ivHs .node polygon,#mermaid-svg-AD10EBwKLBH0ivHs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AD10EBwKLBH0ivHs .rough-node .label text,#mermaid-svg-AD10EBwKLBH0ivHs .node .label text,#mermaid-svg-AD10EBwKLBH0ivHs .image-shape .label,#mermaid-svg-AD10EBwKLBH0ivHs .icon-shape .label{text-anchor:middle;}#mermaid-svg-AD10EBwKLBH0ivHs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AD10EBwKLBH0ivHs .rough-node .label,#mermaid-svg-AD10EBwKLBH0ivHs .node .label,#mermaid-svg-AD10EBwKLBH0ivHs .image-shape .label,#mermaid-svg-AD10EBwKLBH0ivHs .icon-shape .label{text-align:center;}#mermaid-svg-AD10EBwKLBH0ivHs .node.clickable{cursor:pointer;}#mermaid-svg-AD10EBwKLBH0ivHs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-AD10EBwKLBH0ivHs .arrowheadPath{fill:#333333;}#mermaid-svg-AD10EBwKLBH0ivHs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AD10EBwKLBH0ivHs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AD10EBwKLBH0ivHs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AD10EBwKLBH0ivHs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-AD10EBwKLBH0ivHs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AD10EBwKLBH0ivHs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-AD10EBwKLBH0ivHs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AD10EBwKLBH0ivHs .cluster text{fill:#333;}#mermaid-svg-AD10EBwKLBH0ivHs .cluster span{color:#333;}#mermaid-svg-AD10EBwKLBH0ivHs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AD10EBwKLBH0ivHs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AD10EBwKLBH0ivHs rect.text{fill:none;stroke-width:0;}#mermaid-svg-AD10EBwKLBH0ivHs .icon-shape,#mermaid-svg-AD10EBwKLBH0ivHs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AD10EBwKLBH0ivHs .icon-shape p,#mermaid-svg-AD10EBwKLBH0ivHs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-AD10EBwKLBH0ivHs .icon-shape .label rect,#mermaid-svg-AD10EBwKLBH0ivHs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AD10EBwKLBH0ivHs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AD10EBwKLBH0ivHs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AD10EBwKLBH0ivHs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 远程预填充任务
通过 NIXL 传输 KV 状态
生成响应
客户端
Envoy AI Gateway
Dynamo 前端与路由
解码工作节点及协调逻辑
预填充工作节点
当长输入持续进入时,预填充与解码共享资源可能增加正在生成请求的延迟波动。阶段解耦后,可以分别配置批处理、GPU 数量和并行策略,并根据需求调整预填充、解码比例。
张量并行(TP)将单层计算分布到多个 GPU,数据并行(DP)通过多个模型实例处理不同请求。两阶段可采用不同组合,配置需要兼顾显存容量、通信开销、批量及硬件拓扑。
解耦增加了 KV 传输、协调和部署复杂度,也需要为各阶段配置模型运行资源。长输入与混合高并发场景可以优先验证阶段隔离收益;短输入、低负载场景则应保留聚合基线,并将额外传输时间计入比较。
4.3 MoE:密集型、稀疏型与专家并行
密集型模型中,每个 token 通常经过相同的前馈网络。混合专家模型(MoE)在专家层设置多个网络,由路由机制为每个 token 选择部分专家参与计算。因此,MoE 的总参数量与每个 token 的激活参数量需要分别考察,模型权重的存储需求也需要单独核算。
专家并行(EP)将专家分布到不同 GPU。token 分发和结果聚合带来通信开销,专家选择不均衡还可能形成热点。扩大专家并行范围可以分散专家负载,同时增加跨设备通信需求。
预填充阶段的较大 token 批量与解码阶段的较小批量,可能对应不同的专家分布和通信效率。解耦允许两个阶段独立配置 EP、TP 与 DP,并通过吞吐量、ITL 和互连负载验证效果。
4.4 Dynamo 架构:路由、缓存、传输与资源规划
前缀缓存复用的是相同 token 前缀对应的计算状态。重复的系统提示词、相同文档上下文和连续对话历史,可以形成可复用的缓存块。
普通路由可能将后续请求分配给没有相关缓存的 worker。Dynamo 的 KV Router 通过缓存事件维护前缀状态,并结合新增预填充计算量与活跃解码块,评估各 worker 的处理成本。
例如,worker A 拥有较长匹配前缀,但正在处理较多解码请求;worker B 缓存重合较少,但负载较低。路由决策需要权衡节省的预填充计算与新增排队、解码压力。缓存命中率应与 TTFT、ITL 一起观察。
课程在前端通过 DYN_ROUTER_MODE=kv 启用该机制。路由收益需要在固定 worker 数量的条件下验证,并使用具有可控重复前缀的测试请求。
生产中的缓存管理还需与模型版本、提示词模板和租户隔离策略对应,并确认跨 worker 的 KV 布局兼容。缓存卸载的收益取决于恢复与传输成本相对于重新预填充的成本,应同时记录缓存命中、驱逐和读取耗时。
在 Dynamo 中,相关职责由以下模块承担:
- KVBM:管理 KV 块的分配、保留、复用与卸载,在 GPU 显存、主机内存等层次之间权衡容量和访问成本。
- NIXL:提供 KV 数据传输能力,连接预填充、解码与缓存管理;实际性能取决于数据量、传输后端和硬件互连。
- Planner:结合队列、缓存压力与性能目标规划工作节点容量,并通过资源控制接口调整预填充、解码配置。
这些模块需要对应的后端集成与配置,其支持范围应以所用 Dynamo 版本为准。课程中的可观测性堆栈通过 Prometheus 指标、Loki 日志和 Tempo 追踪,关联路由、计算、传输与扩缩容行为。这些是可独立选用的通用观测工具;换用其他工具时,仍应保留对上述环节的关联分析能力。
Planner 面向推理服务图的阶段容量规划,通用 HPA 面向工作负载副本控制,节点扩容提供硬件容量。生产架构应划分各层的控制对象,并为预填充和解码明确副本管理方。
4.5 Grove 编排与拓扑调度
分布式推理包含前端、预填充、解码等多个角色。普通 Deployment 分别管理 Pod 副本;Grove 进一步表达服务图、角色关系、最低可用资源和协调扩展要求。
课程环境中,用户提交 DynamoGraphDeployment,Dynamo Operator 将其转换为 Grove 资源,再由 Grove 与 KAI Scheduler 协同完成编排。这是课程环境选择的编排链路,并非部署所有推理服务的前提;需要跨多个角色协调资源时,才有必要进一步评估这类能力。
| Grove 资源 | 作用 |
|---|---|
| PodCliqueSet | 定义整个多角色工作负载及服务图副本 |
| PodClique | 管理特定角色的 Pod 集合 |
| PodGang | 表达需要共同满足的最小调度要求 |
| PodCliqueScalingGroup | 将需要协调扩展的角色组织为一个扩展组 |
编组调度依据最低成员要求分配资源,减少只启动部分依赖组件的情况。拓扑配置则约束组件放置位置,将通信需求与可用的 NVLink、PCIe 或跨节点网络结合起来。具体保证取决于配置和调度器能力。
预填充与解码可以分别扩容;一个阶段内部紧密耦合的成员可以协调扩容。扩缩容操作应通过负责该服务图的资源与控制器完成,使声明配置与底层 Pod 状态保持一致。
拓扑策略需要同时考虑性能与故障域:紧密通信的成员可放置在高带宽互连范围内,完整服务副本则根据可用性目标分布到不同节点或故障域。调度验证需要确认实际放置、互连性能与可用 GPU 是否符合约束。
五、Dynamo 架构实战:部署、调优与验证
5.1 部署与基准测试:比较不同资源配置
课程最后的实战评估使用 Qwen/Qwen3-1.7B,任务是完成聚合、解耦部署及预填充/解码比例调优。测试负载固定输入长度约 3,000 token、输出长度约 150 token,请求速率在 2~8 req/s 之间变化。这组条件用于比较实验配置,不能直接代表其他模型或业务的容量需求。
评估提供四张 worker GPU 的预算,并限定每个阶段采用 1 或 2 个副本:
| 解耦配置 | 预填充 GPU | 解码 GPU | 总 GPU | 比较目标 |
|---|---|---|---|---|
| 1P/1D | 1 | 1 | 2 | 建立解耦基线 |
| 1P/2D | 1 | 2 | 3 | 观察增加解码容量的效果 |
| 2P/1D | 2 | 1 | 3 | 观察增加预填充容量的效果 |
| 2P/2D | 2 | 2 | 4 | 观察两阶段同时扩展的效果 |
其中,1P/2D 与 2P/1D 具有相同 GPU 数量,适合观察资源分配方向;不同总 GPU 数的配置,则需要同时比较总体能力与单位 GPU 效率。
建议按以下顺序执行:
- 固定模型、运行时版本、硬件和输入数据,记录聚合基线。
- 固定 GPU 预算,对比聚合与解耦;固定 worker 数量,对比基础路由与 KV 路由。
- 保持相同请求轨迹,对比预填充、解码副本比例。
- 增加长输出与重复前缀负载,验证结论对其他业务的适用性。
- 在持续负载和突发负载下检查 SLO、错误率、扩容耗时及成本。
课程的部分配置比较同时改变了 worker 副本数。分析报告应分别记录容量变化与路由变化,避免将新增 GPU 的收益全部归因于缓存策略。
课程使用 NVIDIA 生态中的 AIPerf 压测工具,按 Mooncake trace 格式重放请求。可迁移的方法是固定请求轨迹、记录实际 token 数并统一比较口径,工具本身可以替换。以下示例沿用评估中的测试方式,数据集需要预先生成,路由需要已经就绪:
bash
aiperf profile \
-m "Qwen/Qwen3-1.7B" \
--endpoint-type chat \
--url "$GATEWAY_BASE_URL" \
-H "x-model: assessment-disagg" \
--input-file "results/assessment-dataset.jsonl" \
--custom-dataset-type mooncake_trace \
--fixed-schedule \
--streaming \
--artifact-dir "results/assessment-disagg-benchmark"
合成输入的分词器应与目标模型匹配,并记录实际输入、输出 token 数。固定到达时间的负载适合观察队列积累;固定在途并发的负载适合探索吞吐量与延迟之间的关系。测试应区分预热与冷启动,并为缓存路由单独设计重复前缀和缓存冷暖状态。
架构选择可以先筛选满足质量和延迟 SLO 的配置,再比较成本。若将满足 SLO 的有效输出吞吐量记为 G,可估算:
text
每百万有效输出 token 的 GPU 成本
= GPU 总费用(元/小时)× 1,000,000 ÷(3,600 × G)
G 以 token/s 计,来自满足业务要求的有效响应。完整成本核算还应纳入 CPU、存储、网络、空闲容量与运维费用。
5.2 用观测数据定位性能瓶颈
课程通过 Prometheus 采集推理、GPU 和 Kubernetes 指标,通过 Grafana 展示趋势,并在 Dynamo 实验中加入 Loki 日志与 Tempo 追踪。
指标名称和标签会随后端、版本与采集配置变化,应先检查实际暴露的数据。以下以 inference 命名空间中的 vLLM Deployment 为例,namespace、pod 标签需要由采集配置正确附加:
promql
# 当前排队请求总数:Gauge 直接查询
sum(vllm:num_requests_waiting{namespace="inference",pod=~"model-inference-.*"})
# 最高 KV 缓存使用比例,识别压力最大的执行单元
max(vllm:kv_cache_usage_perc{namespace="inference",pod=~"model-inference-.*"})
# GPU 利用率的时间窗口平均值
avg(avg_over_time(DCGM_FI_DEV_GPU_UTIL{namespace="inference",pod=~"model-inference-.*"}[5m]))
# 当前模型 P95 首 token 延迟:对直方图桶的增量速率计算分位数
histogram_quantile(0.95,
sum by (le) (
rate(vllm:time_to_first_token_seconds_bucket{namespace="inference",pod=~"model-inference-.*"}[5m])
)
)
Counter 适合使用 rate() 观察增量速度,Gauge 描述当前状态,可直接查询或计算时间窗口平均值。查询前还需要确认 GPU 与 Pod 的标签映射正确,以及采集目标是否完整。
| 观测现象 | 需要关联的数据 | 优先验证的方向 |
|---|---|---|
| TTFT 上升、排队增加 | 请求到达率、输入长度、预填充队列 | 输入负载、预填充能力与接入限流 |
| TTFT 稳定、输出变慢 | ITL、活跃请求、KV 占用 | 解码容量、显存带宽与批处理参数 |
| 增加副本后仍有慢请求 | 各副本请求量、缓存命中、路由记录 | 分流是否均衡、缓存是否过度集中 |
| 扩容目标增加、Pod 长时间未就绪 | 调度事件、GPU 余量、加载日志 | 资源不足、镜像或模型加载瓶颈 |
| 解耦后延迟增加 | KV 数据量、传输耗时、GPU 拓扑 | 互连能力、阶段比例与协调开销 |
| 缓存命中提高、业务延迟未改善 | worker 负载、排队、请求追踪 | 缓存收益是否被热点和等待抵消 |
请求标识用于关联日志,分布式追踪需要同时配置采样、上下文传播与导出器。通过单个请求的网关、路由、预填充、传输和解码时间,可以验证聚合指标所提示的瓶颈。
5.3 生产验收与发布闭环
落地时,应保存三个相互关联的结果:部署配置 记录模型、精度、缓存、并行与副本参数;测试记录 保存负载轨迹、AIPerf 工件和质量评测;运行策略确定配额、扩缩容阈值、告警与回滚条件。
发布过程应覆盖模型预加载、实例就绪、真实推理验证、小比例灰度、SLO 与质量观察、流量推进及回滚。资源预算需要同时容纳新实例初始化与旧实例排空。
生产验收还应包含突发流量、单个 worker 故障、指标中断,以及长流式请求期间的缩容。记录受影响请求、SLO 恢复时间与资源释放行为,使性能测试、故障处理和发布策略形成闭环。
对已有部署平台上的模型服务,我会先建立聚合部署的质量、延迟和成本基线,再补齐统一入口、配额、监控与安全缩容。只有当数据表明瓶颈来自预填充与解码相互干扰、缓存复用不足,或多角色资源难以协调时,再评估解耦、缓存路由和编组调度。这样,课程中的工具就有了明确的引入理由,也更容易判断其收益是否覆盖新增的运维复杂度。