NVIDIA Dynamo 源码阅读(二):分布式运行时如何组织服务与请求

Dynamo 的推理组件能够跨进程、跨节点组合,核心依赖 lib/runtime。这一层不理解模型,也不关心 token 的语义;它提供的是一套分布式组件模型:服务如何命名、实例如何注册、客户端如何发现、请求如何流式传输。 本文基于 Dynamo 提交 27f09d5。 一、运行时的核心抽象 源码从 DistributedRuntime 开始。它持有运行时配置、服务发现实现、网络管理器和关闭信号,并向上提供 Namespace。 对象关系可以简化为: DistributedRuntime └── Namespace("dynamo") ├── Component("frontend") │ └── Endpoint("generate") ├── Component("router") │ └── Endpoint("generate") └── Component("worker") └── Endpoint("generate") × N instances 这四层各有不同职责: Runtime:进程级资源和生命周期; Namespace:隔离一组服务; Component:表示逻辑服务角色; Endpoint:表示可调用接口及其多个实例。 Endpoint 名字相同不代表只有一个服务器。每个 Worker 可注册自己的 instance,客户端通过 discovery 得到动态实例集合。 二、服务发现保存什么 lib/runtime/src/discovery 定义了发现层。一个 Endpoint 注册时,系统不仅记录地址,还附带实例、组件和元数据。客户端查询的关键维度是: (namespace, component, endpoint) -> [instance...] 在裸机模式中,注册与租约可由 etcd 支持;Kubernetes 模式使用 DynamoWorkerMetadata CRD 和 EndpointSlice。运行时把发现后端抽象掉,上层 Router 不需要分别实现 etcd watcher 与 Kubernetes watcher。 ...

2026年8月26日 · 2 分钟 · Hellokitty

NVIDIA Dynamo 源码阅读(三):KV-aware Router 如何选择 Worker

普通负载均衡只关心哪个 Worker 更空闲。LLM 推理还需要回答另一个问题:哪个 Worker 已经缓存了当前请求的最长前缀?如果忽略缓存局部性,相同 system prompt、文档或多轮会话会在不同 GPU 上反复 Prefill。 Dynamo 的 KV-aware Router 将缓存命中与运行负载放进同一次决策。本文基于提交 27f09d5,重点阅读 lib/kv-router 与 lib/llm/src/kv_router。 一、路由问题如何形式化 设请求 token 被按固定 block size 切成若干块: [t0 ... t15] [t16 ... t31] [t32 ... t47] [剩余 token] B0 B1 B2 每个完整块计算链式哈希。Router 维护如下关系: B0 -> {worker 1, worker 3} B1 -> {worker 1} B2 -> {worker 1} 如果新请求具有相同前三块,Worker 1 的重叠长度最大。但它可能已经非常繁忙,因此最终决策不是简单的最长前缀匹配,而是 locality 与 load 的权衡。 二、为什么使用链式 block hash compute_block_hash_for_seq 不会孤立地哈希每个 token 块,而是把前一个块的 hash 纳入下一个块。这使相同内容出现在不同前缀后时不会被错误视为同一缓存位置。 ...

2026年8月26日 · 2 分钟 · Hellokitty

NVIDIA Dynamo 源码阅读(四):Prefill/Decode 分离与 KV 传输

Prefill 与 Decode 使用同一个 Transformer,却具有不同资源特征。Prefill 面向长序列并行计算,关注首 token 延迟;Decode 每轮只处理少量 token,受显存带宽和迭代调度影响。把两者固定绑在同一副本上,资源比例只能随实例一起扩缩。 Dynamo 的 disaggregated serving 将两阶段放到不同 Worker 池,并用直接 KV 传输连接起来。本文基于提交 27f09d5。 一、为什么要做两次路由 解耦请求包含两个独立选择: Frontend | v 选择 Prefill Worker ----> 计算输入 KV | | |<---- transfer metadata--+ | v 选择 Decode Worker <==== 直接搬运 KV | v 逐 token 生成 -> Frontend -> Client Prefill Worker 的选择偏向输入前缀命中与 Prefill 排队;Decode Worker 的选择偏向持续生成负载、可用 KV 容量和传输拓扑。将二者合成一次普通负载均衡,会丢失阶段差异。 ...

2026年8月26日 · 2 分钟 · Hellokitty

NVIDIA Dynamo 源码阅读(一):数据中心级推理栈的整体架构

NVIDIA Dynamo 不是另一个 vLLM 或 TensorRT-LLM。它不负责重新实现 Attention、Continuous Batching 或模型执行,而是把多个推理引擎实例组织成一个可路由、可拆分、可扩缩的服务。 这一区分决定了阅读源码的入口:不要从 CUDA kernel 开始,而应先找到请求如何跨过 Frontend、Router、Prefill Worker 和 Decode Worker,以及服务发现、事件传播、KV 传输分别位于哪一层。 本文基于 Dynamo 提交 27f09d5,仓库版本为 1.5.0。 一、Dynamo 解决的不是单卡执行问题 单个推理引擎已经能完成一次生成:接收 token、执行 Prefill、循环 Decode、管理本机 KV Cache。规模扩大后,系统出现新的问题: 同一前缀可能被多个副本重复 Prefill。 Prefill 与 Decode 的算力和延迟特征不同,固定配比容易浪费 GPU。 Worker 上下线后,路由器必须快速获得最新拓扑。 KV Cache 不仅存在于显存,还可能分布在主存、SSD 或其他节点。 不同后端有不同请求格式与 KV 传输协议,但上层服务不应被绑定。 Dynamo 把这些问题放在推理引擎之上: 控制面 Discovery / Planner / Metrics | v Client -> Frontend -> Router -> Inference Worker | | | | +---- KV Events+ | +------ 流式响应 ----------> KV 数据面(按需) Prefill Worker ======> Decode Worker NIXL / backend connector 请求平面回答“请求发给谁”;KV 数据面回答“缓存如何移动”;控制面回答“哪些实例存在、负载怎样、是否扩缩容”。三者分开,是 Dynamo 架构最重要的设计。 ...

2026年8月26日 · 2 分钟 · Hellokitty

Mini-SGLang 源码阅读(五):模型层、Tensor Parallel 与自定义 Kernel

前四篇已经解释请求如何到达 Scheduler、KV Cache 如何管理,以及 Engine 怎样执行一个 Batch。最后还剩一个问题:几十亿参数怎样分布到多张 GPU,并在每层计算后重新组合? 本文先推导 Tensor Parallel 的基本原理,再分析 Mini-SGLang 的 Layers、Models、Distributed、MoE 和 Kernel 模块。源码基于提交 9a91cfa。 一、为什么需要 Tensor Parallel 如果模型权重或 KV Cache 放不进单张 GPU,最直接的方法是把不同层放到不同 GPU,也就是 Pipeline Parallel。但自回归 Decode 每轮 token 很少,流水线容易出现气泡,而且跨 stage 传递激活会增加延迟。 Tensor Parallel 把同一层的矩阵切到多张 GPU,让所有 GPU 同时计算同一批 token: 同一 Transformer Layer GPU 0:处理部分权重 GPU 1:处理部分权重 GPU 2:处理部分权重 GPU 3:处理部分权重 ↓ collective 组合为完整层输出 它需要更频繁的 GPU 间通信,但能共同承载单层权重,并保持每个 rank 的执行进度一致。 二、Column Parallel Linear 考虑线性层: Y = XW 按输出维切分权重: ...

2026年8月25日 · 3 分钟 · Hellokitty

Mini-SGLang 源码阅读(四):Engine、Attention Backend 与 CUDA Graph

Scheduler 决定本轮执行哪些请求,Engine 则负责把这个决定变成 GPU 计算。它连接模型、KV Cache、Attention backend、CUDA Graph、Tensor Parallel 和采样器,是 Mini-SGLang 的执行核心。 本文先解释 Attention backend 与 CUDA Graph 的基本原理,再分析一次 Engine.forward_batch()。源码基于提交 9a91cfa。 一、GPU 推理不只有矩阵乘法 一次 Transformer forward 包含许多 GPU 操作: Embedding -> RMSNorm -> QKV Linear -> RoPE -> 写入 KV Cache -> Attention -> Output Linear -> Residual -> MLP / MoE -> LM Head -> Sampling 大模型 Prefill 中矩阵较大,GPU 容易被计算填满;Decode 中每个请求通常只有一个 query token,大量小 kernel 的 CPU launch 开销会变得突出。 ...

2026年8月25日 · 3 分钟 · Hellokitty

Mini-SGLang 源码阅读(三):Paged KV Cache 与 Radix Prefix Cache

KV Cache 是在线 LLM 推理中最重要的状态。它避免 Decode 每轮重新计算全部历史 token,却也通常成为显存容量和并发数的主要限制。 本文先解释 KV Cache、分页管理和前缀复用的基本原理,再阅读 Mini-SGLang 的 MHAKVCache、CacheManager 与 RadixPrefixCache。源码基于提交 9a91cfa。 一、为什么需要 KV Cache 自回归 Attention 在第 t 步需要当前 Query 与位置 0...t 的 Key、Value 做注意力。如果每轮都重新计算历史 K、V,生成 n 个 token 会重复执行大量投影计算。 KV Cache 将每层历史 K、V 保存下来: 第 1 轮:计算 K0,V0,保存 第 2 轮:只计算 K1,V1,读取 [K0,K1] 第 3 轮:只计算 K2,V2,读取 [K0,K1,K2] 缓存大小大致为: 2 × 层数 × token 数 × KV head 数 × head_dim × 元素字节数 其中 2 表示 Key 和 Value。长上下文、大 batch 和高精度都会快速放大显存消耗。 ...

2026年8月25日 · 3 分钟 · Hellokitty

Mini-SGLang 源码阅读(二):Scheduler、Continuous Batching 与 Chunked Prefill

在线 LLM 调度器要回答的不是“下一个运行哪个进程”,而是:这一轮把哪些请求、哪些 token 放入同一个 GPU batch,并确保显存、KV Cache 和计算预算都不超限。 本文先建立 Continuous Batching、Chunked Prefill 与 Overlap Scheduling 的理论模型,再阅读 Mini-SGLang 的 Scheduler 实现。源码基于提交 9a91cfa。 一、调度器面对三种资源 LLM 请求至少消耗三类资源。 第一是计算量。Prefill 的计算大致随输入 token 数增长,Decode 每个请求每轮只增加一个 token。 第二是 KV Cache。一个请求即使本轮只计算一个 token,也必须继续持有全部历史 K、V。 第三是 batch 槽位和 CUDA Graph 形状。请求数、总 token 数和序列长度都会限制可执行 batch。 因此 Scheduler 需要同时维护两个预算: 本轮计算预算:最多处理多少新 token 长期缓存预算:这些请求最多还会占多少 KV 页 只看当前空闲页是不够的。如果 Prefill 阶段把缓存全部吃完,已经进入 Decode 的请求可能无法继续生成。 二、Continuous Batching 的状态划分 Mini-SGLang 将请求分成两个主要集合: waiting queue:尚未完成 Prefill,等待进入 GPU running batch:已经 Prefill,正在逐 token Decode 传统静态 batch 的生命周期以“整批”为单位;Continuous Batching 的生命周期以“请求”为单位。某个请求完成后立即离开,空出的槽位可以接纳新请求。 ...

2026年8月25日 · 3 分钟 · Hellokitty

Mini-SGLang 源码阅读(一):一次 LLM 请求如何穿过推理引擎

大模型推理框架并不只是执行一次 model.forward()。在线服务面对的是持续到达、长度不同、生成进度不同的请求,它必须同时解决文本编解码、动态批处理、KV Cache、GPU 执行和流式返回。 Mini-SGLang 把这些问题压缩在一套相对紧凑的代码中。本文先不进入具体优化,而是建立阅读后续源码所需的整体模型:一次请求如何从 HTTP 文本进入系统,经过 Prefill 和多轮 Decode,最后以流式文本返回。 本文基于 Mini-SGLang 提交 9a91cfa。 一、推理为何分成 Prefill 和 Decode 输入 prompt 包含多个 token。模型第一次执行时,需要同时处理全部输入 token,并为每一层生成 Key、Value。这一阶段称为 Prefill。 输入: [t0, t1, t2, t3] 计算: 同时处理多个位置 产物: 最后位置的 logits + 四个位置的 KV Cache 接下来每轮只生成一个 token。已有 token 的 K、V 不应重复计算,只需读取缓存并计算新 token: 已有: [t0, t1, t2, t3] 第 1 轮 Decode:输入 t3,生成 t4 第 2 轮 Decode:输入 t4,生成 t5 第 3 轮 Decode:输入 t5,生成 t6 因此两阶段的计算形态不同:Prefill 计算量大、输入长度不等;Decode 单次计算小,但会循环很多轮。现代推理引擎通常分别为两者设计调度与 Attention kernel。 ...

2026年8月25日 · 3 分钟 · Hellokitty

vLLM 与 Mooncake 对接源码解读:Prefill/Decode 分离中的 KV Cache 如何跨节点传输

深入分析 vLLM 内置 MooncakeConnector:从代理拆分请求、Scheduler 元数据、GPU KV Cache 注册,到 Mooncake Transfer Engine 通过 RDMA 将 Prefill KV 直接搬到 Decode 节点。

2026年8月24日 · 9 分钟 · Hellokitty