如果你负责过大模型推理服务,一定经历过这种血压拉满的场面:集群明明插满了显卡,在线请求一上来,GPU 利用率却像心电图一样上蹿下跳;同一份历史对话,换一张卡就要重新算一遍,显存和算力全耗在重复劳动上;大量排队请求挤在一个节点,旁边几张卡却闲着发呆。这不是显卡不够,而是“调度”出了问题。
NVIDIA Dynamo就是冲着这个痛点来的。它不负责算矩阵,也不负责写算子,而是站在 GPU 集群之上,当一个统筹全局的调度层——谁该去哪张卡、KV Cache 存不存、预填充和解码分开跑还是混着跑,都由它指挥。我习惯叫它“AI 推理的智能交通指挥官”:每一条请求是一辆车,每一张 GPU 是一条道路,KV Cache 是车辆的记忆包,Dynamo 要做的是让所有车都选对路、少堵车、不绕远,而不是简单地“哪条路空就往哪开”。
这篇文章适合正在做大模型推理服务选型、被多卡利用率折磨、或者刚接触推理集群架构的朋友。我会从它要解决的问题入手,拆解核心机制,给出落地前的思考路径和踩坑建议,让你看完之后能判断:这套调度思路到底适不适合你的场景。
1. 为什么需要 Dynamo:AI 推理背后的效率困局
1.1 “加张卡”解决不了所有问题
做推理集群和做训练集群的思维惯性完全不同。训练时任务相对固定,数据流清晰,大家习惯用数据并行、张量并行把模型拆开,追求的是整体吞吐拉满。推理不一样,在线请求到达时间是随机的,每个请求的上下文长度、生成长度差异巨大,互相之间还可能共享对话历史。在这种动态负载下,单张卡的算力再强,也扛不住“局部热点”——一批请求同时涌向同一张卡,其他卡却闲着。
你大概率也见过这种场景:集群整体负载只有三成,但个别节点已经 OOM。问题不在卡的绝对性能,而在于请求被分配到了哪张卡、分配得是否均匀、分配策略是否考虑到了每张卡当前的“真实剩余能力”。加一张卡只是把原有的不均衡放大一遍,热点依旧存在,只是换了个地方热。
为了说明这个现象,我经常用高速路做类比。上下班高峰期,快速路匝道口总是排长队,但你绕到地面道路一看,很多车道其实空着。为什么?因为所有导航软件都在用同一套最短路径算法,把所有车都导到了同一条路上。推理集群的朴素负载均衡就是这套“最短路径算法”——只看当前哪张卡比较空闲,却不管这张卡是否适合接收这个请求。
1.2 KV Cache:决定请求去留的“会话锚点”
大模型推理时,每个请求的上下文要被转成一组 Key-Value 张量,也就是常说的KV Cache。这个缓存有多大?几百字节到几十 MB 不等,取决于上下文长度和模型头数。它有一个很有意思的特性:和请求是绑定的。同一个用户下一次发来“继续聊”时,新请求要依赖上一次的 KV Cache,才能接着往下生成。
问题就出在这里。如果前一个请求落在 GPU 0 上,它的 KV Cache 也留在 GPU 0 上,下一个延续请求却被调度到了 GPU 1,会发生什么?GPU 0 的缓存用了用不上,GPU 1 必须重新把历史上下文从头算一遍。显存多占了,算力多耗了,响应时间也肉眼可见地变长了。如果用户的对话很长、轮次很密,这个“缓存未命中”的代价会被不断放大,最后整个集群的体感就像一辆随时被导航带偏的货车,明明仓库里有货,非得回产地重新拉一趟。
Dynamo 把 KV Cache 当成一个全局可感知的路由依据。它维护着一张“哪张卡上存着谁的缓存”的地图,新请求进来时,优先调度到缓存所在的那张卡。这个行为看着简单,实际意义很大:缓存命中率一旦提升,实际吞吐和首 token 延迟都会有非常直观的改善。这也是它敢自称“智能交通指挥官”的第一个底气——它是带着记忆做调度的,不是盲猜。
1.3 Prefill 与 Decode:两个阶段的性格完全不同
再往深一层看,大模型推理天然分为两个阶段。Prefill(预填充)阶段处理输入上下文,计算密集,一次性要吃掉大量算力,但时间相对集中;Decode(解码)阶段逐 token 生成,每一步只算一个 token,计算量小但延迟敏感,整体占用时长可能占到整个请求的七八成。
把这两个阶段混在同一个推理引擎里跑,就像把所有车都赶进同一条不限速车道:重型卡车和轻型轿车互相干扰。长上下文请求的预填充一旦挤进解码批次,整批请求都得等它算完,尾部的生成延迟被拖得很严重;反过来,解码阶段的细碎请求又很容易打断预填充的大块计算,GPU 利用率上不去。
传统的单卡推理框架不区分这两个阶段,因为一张卡上无所谓分工。但到了多卡集群,这个混跑模式就成了效率黑洞。Dynamo 给出的思路是PD 分离,也就是把 Prefill 和 Decode 当成两种独立负载来调度,可能跑在不同显卡、不同实例上,甚至让它们按各自最合适的策略排队。这个思路在后面会详细拆,你只要先建立起一个印象:它把推理流程从“一锅乱炖”变成了“两条专用道各走各的”。
2. 智能交通指挥官的三大核心能力
2.1 全局 KV Cache 路由:让请求直达记忆所在的卡
Dynamo 的底座是一套全局路由与调度机制,它维护着一个集群态的 KV Cache 视图。当新请求进来,调度器不再像传统负载均衡那样只看“哪张卡负载低”,而是同时看三样东西:请求本身的上下文、哪些 GPU 上已经有这个上下文的缓存、以及这些 GPU 当前的余量状态。
假设你有 8 张卡,某个长会话用户的缓存分布在 GPU 2 上。按轮询策略,这个请求很可能会落到 GPU 5;但按 Dynamo 的路由逻辑,它更倾向于落到 GPU 2,因为这样可以直接复用缓存。只有当 GPU 2 确实放不下时,它才会考虑迁移或者重新计算,并且这一决策会基于成本评估来做——跨卡拷贝缓存的耗时、目标卡的显存余量、请求的紧迫度,都会被折算进去。
这项工作如果只做一次,收益有限。但在线服务的请求往往是连续且带状态的,用户一轮接一轮地追问、修改、续写。路由命中率一旦提上来,平均每个请求的重复计算量会明显下降。我自己做过一个比喻:这就像物流分拣中心有了历史快递地址库,每个包裹不再按随机分拣口扔,而是先查一下收件人上次的收货点在哪,直达路径显然比满仓乱转更高效。
2.2 PD 分离:给重计算和重带宽各自腾出专用道
PD 分离的核心逻辑是把 Prefill 和 Decode 拆开调度。Prefill 阶段对算力要求高,适合在大算力显卡上并行吃下长上下文;Decode 阶段对显存带宽要求高,每一步只需要小批量计算,但要求极低的延迟。
你可以把它理解成高铁站的进站通道和候车大厅:进站通道负责把人流快速推进站,候车大厅负责在站内稳定分散客流,两者场地功能完全不同。Dynamo 允许你为这两类阶段独立配置资源和引擎实例,比如用大算力卡做 Prefill 池,用大显存带宽卡做 Decode 池,两个池子之间通过内部通信协同工作。
这样做还有个额外好处:可伸缩性变得更细了。如果线上突然涌入大量新会话(全是 Prefill 密集),可以只扩容 Prefill 池;如果老会话更多(Decode 密集),就扩容 Decode 池。相比之前必须整体加副本才能扛压力,资源效率高出一截。
当然,PD 分离不是免费的。它引入了跨实例的状态传递,Prefill 算完的 KV Cache 要搬到 Decode 实例上,这本身有网络开销。Dynamo 的设计会在调度和通信层面尽量压缩这个开销,但对我们做技术选型的人来说,还是要有心理预期:它不是一个开箱即取的银弹,而是需要根据集群拓扑和业务负载调参的架构。
2.3 负载感知的细粒度调度:红绿灯配时终于合理了
除了 KV Cache 路由和 PD 分离,Dynamo 还做了一件事:把调度粒度从请求级细化到“请求 + 阶段级”,并且在每一步都综合考虑当前的集群状态。
传统调度框架常常只统计“这张卡正在跑多少个请求”,然后按数量分配。但请求之间差异极大,一个上下文 128K 的长对话和一段 20 个 token 的简短问答,完全不是一个量级。Dynamo 的调度会去估算每个请求的上下文长度、预期的输出长度、KV Cache 需求,再结合每张卡当前的显存余量、计算队列长度、甚至卡间的通信拓扑,最终决定请求的落点。这相当于交通指挥不再只看每个路口有几辆车,还会考虑每辆车是卡车还是轿车、目的地在哪里、哪条路最近不堵。
这种细粒度调度带来的直接收益是可预期性。你更容易知道某个请求大概率什么时候能出结果,队列里的长尾延迟也会被压下去。对于做在线服务的团队,这比单纯拉高吞吐数字更有价值。稳定性的提升,往往比峰值性能更影响用户体感。
3. 落地前想清楚的三件事
3.1 你的业务画像决定要不要用 Dynamo
Dynamo 不是万金油。我建议你先拿自己的业务对号入座,再决定要不要投入。
如果你的场景是短上下文、单轮问答、请求之间几乎没有会话延续,比如简单的翻译、短文本改写,那 KV Cache 路由的收益会非常有限。因为每个请求一来一回就结束了,缓存命中率上不去,全局路由带来的复杂度反而成了负担。
但如果你的场景是多轮对话、Agent 式任务、长文本分析、多模态上下文持续交互,用户会在一次会话里反复发出请求,共享同一个上下文,那 Dynamo 的路由收益就非常明显。尤其当业务里有大量几万 token 甚至更长的上下文时,一次缓存命中省下的重算开销,抵得上几百次短请求的成本。
另外还要看你的流量形态。如果突发高并发频繁且规模很大,细粒度调度和 PD 分离能让你在同样的卡数下扛下更多并发;如果你的负载平稳、请求量不大,那调度框架的收益会被管理成本抵消掉。先画像,再选型,别追概念。
3.2 它在技术栈里处在哪一层
很多同学第一次接触 Dynamo 时,会下意识把它和 vLLM、TensorRT-LLM 放在一起比较。实际上它们的定位完全不同。vLLM、TensorRT-LLM 是推理引擎,负责单卡或单节点内的模型推理计算;而 Dynamo 是分布式推理的调度编排层,负责在多卡、多节点之间决定请求怎么路由、阶段怎么分离、资源怎么分配。
用交通系统来类比:推理引擎是每一辆车的发动机,Dynamo 是交通指挥中心。没有发动机车跑不了,但没有指挥中心,再好的发动机也只会各跑各的,堵成一团。Dynamo 不会替代你的推理引擎,而是与它们配合,指挥它们工作。在落地时,你要评估的不是“要不要把 vLLM 换成 Dynamo”,而是“我现有的推理引擎是否可以被 Dynamo 统一调度起来”。
这种“指挥”能力的价值,在单卡场景为零,在两三张卡的小集群里也有限,只有当你到了多节点、多卡、请求来源复杂、会话延续密集的规模,它才真正值回票价。规模是前提,不要在小集群上为一个调度框架复杂化自己的运维。
3.3 我最建议的最小验证路径
如果你已经心动了,我自己比较推荐的验证路径是这样的:先保留现有推理引擎不动,只搭一个最小的调度测试环境,用两三个节点的集群做对照实验。一组走你现有的朴素负载均衡,一组挂上 Dynamo 做调度,然后回放真实的业务流量。
观察三个指标:缓存命中率、平均首 token 延迟、卡间利用率方差。这三个指标比单纯的吞吐更能反映调度质量。如果命中率没有明显变化,利用率方差还是很大,那说明你可能还没摸对配置;如果这三项都有可见改善,再考虑扩大范围。
另外提醒一点:在引入任何调度层之前,先把推理引擎自身的指标采集打通。调度需要数据做决策,如果每张卡当前跑多少个请求、占多少显存、有多少 KV Cache 剩余容量都拿不到,上层的“智能指挥”就是空中楼阁。数据越全,调度器的指挥才能越准。
4. 常见误区与调优心得
4.1 误区一:所有流量都走全局路由
全局路由好归好,但过度集中地依赖它也会出问题。路由决策本身有计算成本,每来一个请求,调度器都要做一次综合判断:查询 KV Cache 分布、检查各 GPU 状态、估算迁移代价。如果每秒有成千上万个短请求涌进来,并且每个请求带的历史信息极少,路由器的开销甚至可能超过缓存命中带来的收益。
我的建议是给流量分层:长会话、有状态的请求走全局路由;短会话、状态无关的请求走简单哈希或随机分配。这就像城市交通,不是每辆车都需要进指挥中心做路径规划——本地熟路的短途车,直接走常规路线就行了,真正需要实时导航的是远距离、跨区域的车辆。
4.2 误区二:PD 分离比例拍脑袋定
PD 分离虽好,但 Prefill 池和 Decode 池各分配多少算力、几张卡,这是需要实测的问题。比例设置得太偏 Prefill,高峰期解码吞吐跟不上,尾部延迟飙升;比例设置得太偏 Decode,新请求的输入迟迟处理不完,首 token 延迟变得很难看。
比较务实的做法是盯住一个混合指标:P95 端到端延迟。它同时受首 token 延迟和尾 token 速度影响,能综合反映两个池子是否协调。调整比例时,按一小步一小步来,比如先移动 10% 的资源,观察几小时,再决定下一步方向。切忌一口气大改大动,那样你根本分不清延迟变化是来自比例本身,还是来自负载波动的巧合。
4.3 调优心得速查表
下面这张表是我在做推理服务调优时经常用的自查清单,按优先级排列,建议你贴到墙上。
| 观察项 | 可能病因 | 应对方向 |
|---|---|---|
| 缓存命中率偏低 | KV Cache 路由策略未生效或缓存被频繁驱逐 | 检查请求路由是否真正考虑了会话 ID;调大缓存管理容量 |
| 首 token 延迟波动大 | Prefill 池资源不足或排队策略不当 | 扩容 Prefill 池;检查长上下文请求是否过度集中 |
| 尾部 token 速度慢 | Decode 池带宽饱和或批次过大 | 拆小 decode 批次;调整 PD 比例偏向 Decode |
| 卡间利用率方差大 | 调度粒度太粗或负载感知不及时 | 拉长监控窗口看趋势;细化调度决策频率 |
| 整体吞吐上不去 | KV Cache 重复计算严重或通信开销过大 | 优先解决缓存命中;检查跨节点调用频率 |
4.4 给新手的一句话心法
我见过太多团队拿到调度框架后的第一反应,是拼命调参数,希望找到一个神奇的配置能让集群起飞。但实际经验告诉我:调度框架的大部分收益在架构设计阶段就已经定死了。路由信息通不通、PD 分离的拓扑合不合理、监控数据全不全,这些才是决定性因素。参数调整只是锦上添花,不是起死回生的药方。
先把“请求会怎么走”画出来,再把“卡上有什么”摸清楚,最后才谈“参数怎么设”。顺序反了,后面再努力都像在一个没有红绿灯的十字路口反复修改信号配时——路口结构本身就没规划好,配时再精准也白搭。
从我个人接触到的实际案例来看,调度层带来的改善往往不是让你“从 80 分到 90 分”,而是让整个集群在复杂负载下仍然保持稳定——这恰恰是做在线服务最看重的事情。先把基础架构理清,再让指挥系统发挥作用,这条路走对了,后面每一步都会顺很多。