Blink:把 CPU 请出推理关键路径——SmartNIC 与 GPU 常驻内核的 CPU-Free 服务架构(2026)

9136 字
46 分钟
Blink:把 CPU 请出推理关键路径——SmartNIC 与 GPU 常驻内核的 CPU-Free 服务架构(2026)

AI 生成内容声明

背景:推理服务把 CPU 留在了每个 token 的关键路径上#

本文要讲的主角是 Blink,由瑞典 KTH(皇家理工学院)与 RISE 研究院的研究者于 2026 年 4 月发布在 arXiv 上的预印本(arXiv:2604.07609)。它的目标很激进:让主机 CPU 彻底退出大模型推理的稳态关键路径,把推理服务的”控制面”和”数据面”分别交给 SmartNIC(智能网卡,也叫 DPU)和 GPU 上的常驻内核。

要理解 Blink 为什么这么做,先得看清楚今天的主流推理服务栈(vLLM、SGLang、TensorRT-LLM)在每一个解码迭代里到底干了什么。

迭代级调度:CPU 被”钉”在了解码循环里#

Transformer 生成式推理是一个长生命周期、有状态的过程:每生成一个 token,都要把新的 KV 追加进缓存,决定下一个 token 用什么 batch 成员身份去计算。2022 年微软的 Orca 系统引入了 迭代级调度(iteration-level scheduling):不再把”一个请求”当作调度单位,而是把”一个解码迭代”当作调度单位,每个迭代都重新决定哪些请求共享这次 GPU 计算。这套思路后来被 vLLM、SGLang 等全部主流框架继承。

迭代级调度带来一个隐性的代价:每一次迭代结束,控制权都要交回主机 CPU。CPU 要做的事包括:

  1. 从已完成迭代的请求里收集输出 token,追加到各自的解码序列;
  2. 处理新到达的请求:准入、分配 KV cache 块、决定是否插入下一批;
  3. 更新 batch 成员集合,按新的请求组合重新组装输入;
  4. 调度下一次 GPU kernel 执行(哪怕是启动预捕获的 CUDA Graph)。

一句话:GPU 负责算,CPU 负责”每次算之前和算之后”的所有编排。vLLM 单个实例本身就是一个多进程架构(API server、engine core、每个 GPU 一个 worker),进程数量随并行策略扩张,主机侧状态又大又碎。

CUDA Graphs 缓解了其中一部分问题:把一串 kernel 捕获成一张图,启动开销从每次 kernel 的微秒级降到一次图启动的开销,但这只是摊销了 launch 本身。batch 成员更新、KV 块表管理、下一个图的选择与分发,仍然要在 CPU 上完成。所以论文里有一句很关键的话:即使开了 CUDA Graphs,调度器在每步解码之后仍然必须回到主机一次。

CPU 抖动如何变成 token 延迟#

因为 CPU 与 GPU 在每个迭代紧密耦合,主机侧任何扰动——被抢占、LLC 缓存行被逐出、TLB 缺页后页表遍历变慢——都会直接膨胀 ITL(Inter-Token Latency,相邻 token 间隔)。更糟的是这个代价是乘法累积的:一次解码的 GPU 计算本身只有几百微秒,CPU 侧如果因为干扰多花了几十微秒,对单步是 10% 的膨胀,但对一个输出 500 token 的请求,就是 500 次叠加,而且 GPU 在这期间是空转的。

更早的 profiling 研究已经指出,在快的加速器上,CPU 侧调度开销可以占到端到端推理延迟的 50%一项对 vLLM 等系统 CPU 调度开销的专门研究)。vLLM V1 引擎和 SGLang 的 overlapped scheduling 把主机侧工作和 GPU 执行做流水线重叠,正常工况下能把这笔税压下去,但重叠的前提是 CPU 侧工作能在 GPU 执行窗口内完成。一旦同机共置的租户抢占了共享的 LLC 和 TLB,主机侧工作超出 GPU 执行时间,超出的部分就全部显形为每个 token 的生成时间。

干扰实验:量化”CPU 拖后腿”有多严重#

论文用 vLLM v0.13 在 H100 上服务 Llama-3 8B,用 ShareGPT 对话轨迹(平均输入/输出 1019/463 token),干扰源是 pbzip2 压缩大文件,开 CUDA Graphs,跑出来的结果(论文 Table 1)非常触目惊心:

指标基线(无干扰)干扰 12 线程干扰 24 线程
吞吐(tok/s)7 4754 5541 961
平均 TTFT(ms)73.74 86516 552
P99 TTFT(ms)1506 36620 959
平均 TPOT(ms)13.013.614.8
P99 TPOT(ms)14.418.032.1
P99 ITL(ms)67.9110.6176.8
IPC1.531.080.72
LLC miss rate(%)7.043.271.6
LLC stall cycles4.5 亿25.9 亿50.4 亿
dTLB load misses600 万800 万1000 万
page walk 周期3.83 亿9.20 亿14.5 亿

24 线程干扰下,吞吐掉到原来的 26%(3.8× 衰减),P99 TTFT 从 150ms 膨胀到 20.9 秒(139 倍)。注意平均 TPOT 只从 13.0 涨到 14.8ms——看起来”每个 token 的平均生成速度没怎么变”,但 P99 TPOT 翻了一倍多、P99 ITL 涨到 176.8ms。平均数的平稳掩盖了尾部的灾难,而生产 SLO 恰恰是由 P99/P99.9 决定的。

论文用 perf 计数器把机制拆得很清楚,这是一个”两级放大”的干扰回路:

  1. 地址翻译放大了 LLC 竞争。基线状态下,页表遍历(page walk)占了全部 LLC stall 周期的 85%——Python 服务栈工作在碎片化的虚拟地址空间上,翻译开销天然就重。干扰出现后,TLB miss 总数只涨了 1.6 倍,但每次 miss 的代价暴涨:干扰进程频繁的内存操作(madvise、mprotect、munmap)引发 TLB 失效广播,强制重新翻译;同时页表项本身住在 LLC 里,干扰进程把共享 LLC 污染掉之后,本来命中缓存页表项的 walk 现在要一路走到 DRAM。结果 walk 周期涨了 3.8 倍,LLC stall 周期涨了 11.2 倍。
  2. 尾部延迟方差极大。即便在隔离状态下,主机编排本身也会引入抖动:论文实测 P99 ITL 与 P99 TPOT 差了 4.7 倍(67.9ms vs 14.4ms),干扰下 kernel 之间的调度间隙从约 1μs 膨胀到约 40μs(Nsight Systems 实测),几百个输出 token 一路叠加。

再用 PyTorch 逐操作 profile 一个 transformer 层的 forward(),能看到所有变慢的都在主机侧:注意力分发 +104%、cudaLaunchKernel +115%、KV cache 分发(reshape_and_cache_flash)+172%、aten::empty 等元数据操作 +81%,而 GPU 侧 kernel 执行时间纹丝不动(matmul 稳定在 0.41-0.42ms)。加速器不是变慢了,是被主机”饿”着。

为什么现有手段救不回来#

直觉上,数据中心有一整套成熟的干扰隔离工具箱:大页、CPU 绑定、缓存分区、调度优先级。论文逐一验证,结论是全都不够——这不是实现质量问题,是结构性问题。

巨页:几乎无效#

给 vLLM 换 2MB 大页:所有延迟和吞吐指标都在测量噪声范围内,dTLB miss 只降 16%——对以 Python 小对象和元数据为主的宿主机侧工作集,2MB 大页的 TLB 覆盖收益有限。给干扰进程分配 1GB 巨页也一样没用:巨页减少的是干扰进程自己的 TLB miss,不改变它在 LLC 里的足迹,P99 ITL 甚至略变差。

核心绑定:有效,但不现实#

把 vLLM 钉在专用物理核上(按 NVIDIA 认证系统配置指南的要求,每 GPU 至少 6 个物理核),消除 CPU 迁移和直接抢占,是论文评估过的最强单项缓解:干扰下吞吐只掉 16.3%,请求完成数 -17.3%,P99.9 ITL +30.3%。但代价是结构性的:

  • 一个 8×H100 节点需要 48 个专用物理核——占满双路 Xeon(每路 24 核),或一台高端双路 EPYC(每路 64 核)的 38%;
  • 这些核在两次解码迭代之间基本闲置,却不能租给其他租户——一旦租出去,干扰就回来了;
  • 核心绑定实际上把”共享机器”又变回了”专用机器”,消灭了共置的经济动机。

CAT 缓存分区:消除了 LLC 竞争,却没消除尾部延迟#

Intel Cache Allocation Technology(CAT)按核分配 LLC 缓存路(CLOS 与核绑定,所以必须以核心绑定为前提)。把 1 到 12 条缓存路逐步划给 vLLM:LLC miss rate 从 57.6% 一路降到 6.8%(降 8.5 倍),LLC stall 周期降 7.4 倍,但 P99 ITL 在所有配置下都是 53.4-55.6ms,波动不到 4%

机制上很有意思:CAT 不分区 TLB,所以 dTLB miss 数恒定在约 700 万;但 TLB miss 后的页表遍历需要访问页表项,页表项住在 LLC 里——给 vLLM 更多缓存路,页表项更容易留在 LLC 里,每次 walk 更短。这就是为什么 LLC miss 降了、延迟却不降:主导开销是主机侧调度抖动和 CUDA 分发本身,缓存分配管不着它。而且把 12 条路里划走 7 条,同 socket 上所有其他租户只剩 5 条路,缓存容量被压掉 2.4 倍——多 GPU 节点上每个 GPU 都要一份 7 路分区,缓存路数很快就耗尽,根本不可扩展。RDT 还有一堆操作层限制:CLOS 条目稀缺(每 CPU 9-15 个)且必须连续、上下文切换会覆盖 CLOS 分配、只针对 Intel 平台。

经济账:预留的 CPU 余量都是白花的钱#

为什么这个问题值得一个专门的系统去解决?因为当前的主流部署模式是一台机器只跑一个推理工作负载:为了 SLO 可预测,运营商宁可用专用机器,把 CPU 资源”闲置”着也不放别的租户进来。数据中心里成千上万台推理机器的 CPU 利用率极低,这笔资源不是”够用”,而是被政策性地浪费了。如果能做到”推理性能不随 CPU 竞争变化”,运营商就能把推理服务和 CPU 密集型任务共置,从同一台机器上多收一份租金。Blink 的评估里有一个数字可以感受下量级:一台 8×H100 节点按 NVIDIA 认证要求要留 48 个专用物理核给推理,占双路 EPYC 平台的 38%——把这些核还给租户,等于每台机器多出近四成的 CPU 容量可出售。

结论:CPU 在关键路径上这件事本身,就是病根#

所有缓解手段的共同结局是:要么无效,要么把机器变回专用。论文由此给出判断——要在共置场景下获得干扰免疫,唯一的路是把主机 CPU 从稳态推理回路里整个拿掉。注意这不是否定 vLLM 们的工程努力,而是说:只要调度决策必须经过 CPU,CPU 的微架构共享资源(LLC、TLB、内存总线)就必然成为攻击面。

Blink 的核心设计原则是一句话:主机 CPU 只负责”开机配资源”,不负责”运行时调度”。具体地说:

  • 初始化阶段(host-assisted):CPU 加载模型、编译 TensorRT 引擎、把各种形状的推理计算捕获成 CUDA Graph 并实例化。做完之后,CPU 退出关键路径,之后爱干嘛干嘛——可以被共置租户随便用。
  • 稳态阶段(DPU + GPU only):请求从网络进来,经 SmartNIC 上的 ARM 核处理,通过单边 RDMA直接写进 GPU 显存里的环形缓冲区;GPU 上一个常驻的调度内核自己完成批处理、调度、KV cache 管理和采样,把结果写回环形缓冲区;SmartNIC 读回 token、去 tokenize、用 SSE 流式回给客户端。全程 CPU 不参与。

论文 Figure 2 给出了整体架构:

Blink 架构:稳态下推理路径只经过 DPU 与 GPU,主机 CPU 闲置;空心圆标出单个请求从入站到出站的完整生命周期
Blink 架构:稳态下推理路径只经过 DPU 与 GPU,主机 CPU 闲置;空心圆标出单个请求从入站到出站的完整生命周期

这张图读法:上半部分是 DPU(BlueField-3 的 ARM 核),下半部分是 GPU。稳态路径里只有这两者。图中的编号圆点(1-13)是一次请求的生命周期:

  1. DPU 侧前端从网络收到客户端请求;
  2. 在 DPU 上完成 tokenize; 3-4. 通过本地”槽追踪器”在环形缓冲区里定位一个空闲槽位;
  3. 用单边 RDMA 把 token 序列直接写进 GPU 显存中的环形缓冲区;
  4. GPU 常驻调度内核轮询环形缓冲区,发现新请求; 7-8. 调度内核选择并启动预捕获的 CUDA Graph(prefill 或 decode);
  5. 在 GPU 上完成采样(Top-P + temperature);
  6. 把生成的 token 与状态更新写回环形缓冲区;
  7. DPU 侧 token 读取器通过 RDMA 读回结果;
  8. 去 tokenize;
  9. 经 SSE 流式返回客户端。

DPU 与 GPU 之间的唯一共享数据结构就是这块 GPU 显存里的环形缓冲区,所有协调都发生在它上面,因此不需要任何主机中介。

为什么拆给 DPU 而不是更强的 CPU#

一个很自然的问题是:为什么不用一个更强的主机 CPU,而非要引入 SmartNIC?论文给出的理由是能力的不对称

  • SmartNIC(如 BlueField-3,16 个 ARM Cortex-A78 核)在每核网络带宽上比服务器级 CPU(Xeon、EPYC)高 15-24 倍,在每核内存带宽上高 1.6-2.1 倍,非常适合做传输和请求管理;
  • 但它的核数太少,扛不住连续批处理那种”每个迭代都要做”的调度决策量。

所以 Blink 的分工是:DPU 管”慢而大量”的请求管理与网络 I/O,GPU 常驻内核管”快而关键”的调度与执行循环。主机 CPU 两边都不沾,从根上消失。

后端:GPU 常驻推理引擎#

后端是 Blink 最核心的部分,由四个子系统组成:常驻调度内核、设备端 CUDA Graph 启动、连续批处理引擎、无锁环形缓冲区。逐个拆。

常驻调度内核#

Blink 用一个 persistent kernel(常驻内核) 取代了主机驱动的解码循环:单个线程块、256 个线程,启动后永不退出。它跑一个无限控制循环:

  1. 扫描环形缓冲区,找新提交的 prompt;
  2. 用原子 CAS(compare-and-swap)认领这些槽位;
  3. 选择并启动对应的 CUDA Graph(prefill 或 decode);
  4. 轮询设备端输出缓冲区,等采样完成;
  5. 把生成的 token 和状态更新写回环形缓冲区。

因为调度器从不把控制权交还主机,token 关键路径上就没有 kernel 启动开销、没有 host-device 同步、没有 CPU 记账。这就是整个系统性能收益的最大来源:不是 kernel 变快了,而是”调度这个 kernel”的开销消失了

Persistent kernel 这个概念值得多说一句:普通 CUDA kernel 算完就退出,控制权回到 CPU;persistent kernel 则常驻 GPU,靠核内循环持续工作,只通过显存里的共享数据结构和外界通信。它在本博客前文《ExpertPlex》里也出现过——但那是把 MoE 推理的计算本身做成持久 kernel;Blink 更进一步,把调度逻辑本身做成持久 kernel,这是两个不同层面的”GPU 常驻”。

并行槽扫描:1-5μs 扫完 4096 个槽#

环形缓冲区有 4096 个槽位。调度内核的 256 个线程并行扫描互不相交的槽位区间,用原子 CAS 认领 pending 状态的槽,全程无锁、无跨块同步。完整扫一遍 4096 个槽只要 1-5μs——论文强调,prompt 的准入延迟因此主要由 RDMA 传输时间决定,而不是调度开销。

这里藏着一个关键的设计细节:扫描是”重叠”的。decode graph 异步执行期间,256 个线程同时扫描环形缓冲区找新请求,把扫描延迟藏在 decode 计算后面。

设备端 CUDA Graph 启动#

CUDA 13 起支持 device graph launch(设备端图启动):一个常驻内核(它自己也以 CUDA Graph 形式封装)可以直接从设备端把预捕获的图排队执行。这里给刚接触 CUDA Graphs 的读者补一段背景:一张 CUDA Graph 就是把一串 kernel 及其依赖关系捕获成一张有向无环图,启动一次图等价于按序启动所有 kernel,省掉逐个 launch 的开销。图的启动有三种方式:

  • Host launch(主机启动):CPU 调用 cudaGraphLaunch。每步都要 CPU 参与,是 vLLM 等系统默认的方式;
  • Tail launch(尾部启动):当前图的最后一个节点把下一张图入队,链式衔接。设备端就能”自己启动自己”,但每步仍有入队开销,且整个链依赖前一张图完成;
  • Fire-and-forget(发射后不管):父图执行中途,设备端把另一张图异步插入执行流,不等待它完成、也不接收回调。延迟最低,但正如后文所述,有 120 次上限约束。

Blink 用的是 fire-and-forget 模式,启动开销约 2μs,比主机侧启动(11-17μs,视图拓扑而定)快 5-8 倍,比 tail launch(约 5.5μs)快 2.7 倍。按每 512 个输出 token 算,fire-and-forget 相比主机启动能省 4.6-7.7ms——这还不是全部,更关键的是主机启动会把 CPU 重新引回关键路径,重新暴露在干扰下。

论文做了一个非常干净的对照实验(Figure 3):同一套编译好的 Qwen3-32B FP16 引擎、H100、batch 16,只改调度器放在哪一侧。CPU 常驻调度器每步把采样 token 经 PCIe 拷回主机内存、在 CPU 上重组 batch 再启动下一张图;GPU 常驻调度器免掉这步同步。四种负载配置下,CPU 路径的 makespan 慢 1.16-1.70 倍,短输出负载损失最大——因为每步的 PCIe 往返在短请求里占的比例更大。

归一化 makespan 对比:同一引擎下 CPU 常驻调度比 GPU 常驻调度慢 1.16-1.70 倍,短输出负载惩罚最大
归一化 makespan 对比:同一引擎下 CPU 常驻调度比 GPU 常驻调度慢 1.16-1.70 倍,短输出负载惩罚最大

120 次启动上限:一个不广为人知的硬限制#

Fire-and-forget 有一个很刁钻的约束:CUDA runtime 限制单个父图执行中的 outstanding fire-and-forget 启动次数为 120 次,超过后行为未定义。对”必须无限生成 token”的推理服务器,这是致命障碍——一个 512 输出 token 的请求就会耗尽启动预算。退回主机启动等于把 CPU 请回来;全程用 tail launch 则每步多付 2.7 倍启动开销,几百步累积起来可观。

Blink 的方案叫 window-based tail-launch recovery(窗口式 tail 启动恢复)

  • 调度器在共享内存里维护一个单调递增的启动计数器;
  • 每用 120 次 fire-and-forget 后,发一次 tail launch,原子地把当前图执行替换成一个全新实例;
  • 所有状态——环形缓冲区指针、KV cache 元数据、在途请求——都放在持久 GPU 内存里,图重新实例化后原样存活;新实例把计数器清零,从同一逻辑点继续调度循环。

效果:120/121 的迭代用最优的 fire-and-forget,一次 tail launch 摊到整个窗口上,每步解码摊销开销不到 0.03μs;生成 token 数没有上界。这个设计对”CUDA Graph 是有状态的、图切换可能丢状态”的常规认知是一次很漂亮的突破——把状态全部搬出图,图就只是无状态的执行壳

完成检测:纯设备端轮询#

Fire-and-forget 启动没有主机侧完成回调——父内核不会收到子图结束的通知。Blink 在设备端做轮询式完成检测:推理图执行前向并采样后,调度器轮询指定的输出缓冲区,直到看到新 token 出现。prefill 阶段轮询”token 提取缓冲区”(首个输出 token 出现即表示 prefill 完成),decode 阶段轮询每步的提取缓冲区。轮询成本是每迭代几次共享内存 load,相比推理计算可以忽略,而且保住了”稳态无主机参与”的不变量。

连续批处理与内联 prefill#

Blink 实现的是 FCFS(先来先服务)连续批处理,调度策略与 TensorRT-LLM、vLLM、SGLang 保持一致——论文刻意这么做,是为了让评估差异只反映”去掉 CPU”的架构收益,而不是调度策略优势。

要”不停顿地接纳新请求”,调度器实现了 pause-and-resume(暂停-恢复)批处理 + 重叠环扫描:decode graph 异步执行时,256 线程并行扫描环形缓冲区找 pending prompt;找到候选后,满足三个条件才暂停:

  1. 重叠扫描期间检测到 pending 的 prefill 请求;
  2. 有空闲 batch 槽位(考虑本步会完成的槽位);
  3. 有足够的 fire-and-forget 窗口余量,能容纳”prefill 图 + 恢复后的 decode”。

三条件齐备,调度器在当前步结束后暂停在途 decode,执行新到达请求的 prefill 图,把新请求合并进 decode batch,重启解码循环——全部发生在单次持久内核调用内,零主机往返。新请求在一个解码步的延迟内被接纳,TTFT 有界,decode 吞吐不受损。

环形缓冲区与槽状态机#

环形缓冲区是 DPU 与 GPU 之间唯一的共享结构,也是单边 RDMA 的读写目标。结构上是固定数量的槽位 + 共享的输入/token 竞技场(arena)。每个槽记录请求元数据(prompt 身份、token 计数、生成进度)和 token 竞技场里的偏移。槽的生命周期是一个状态机:

empty → prefill_pending → prefill_processing → decode_processing → decode_completed → empty
↕ decode_paused(支持抢占与批处理切换)

所有权与状态迁移全部用原子 CAS,布局与更新规则刻意避免中间拷贝、容忍良性竞争,并用内存屏障保证 RDMA 可见的更新按预期顺序对外可见。这些细节在分布式场景里很重要:RDMA 写和 GPU 读之间没有操作系统帮你做一致性,全靠原子操作和 fence 纪律。

CUDA Graph 缓存与 O(1) 选择#

推理计算用 TensorRT 引擎预编译。初始化阶段,主机对(batch size, sequence length)的稠密网格逐格捕获 CUDA Graph 并实例化为设备端可启动形式;所有图复用同一套为最大形状预分配的设备缓冲区,避免每张图重复占内存。关键的数字:TensorRT 捕获的图每张只占 2-3MB(PyTorch 系的图动辄几百 MB),所以 650-1000 张图的缓存只要 2-4GB 显存,可以做很细的形状匹配而不吃光显存。

运行时,调度器用一张预计算的查找表按 (batch, sequence length) 做 O(1) 选择,选最贴合形状的 prefill 图;查不到的任意组合用最大形状的兜底图。采样(Top-P + temperature)被捕获在每张图内部,所以从注意力到 next-token 选择的整个前向在单次设备端启动内完成,无主机往返。

前端:DPU 侧的控制与数据面#

前端跑在 BlueField-3 的 16 个 ARM Cortex-A78 核上,管请求从入站到 token 交付的完整生命周期:请求追踪器维护每请求状态(槽位分配、token 计数、完成状态),同时跑一个薄的 OpenAI 兼容 HTTP 服务(SSE 流式)。因为前后端解耦,这层接口以后也可以放到独立网关上。

单边 RDMA 数据通路#

前端用单边 RDMA直接读写 GPU 显存里的环形缓冲区——“单边”意味着数据搬运由网卡硬件完成,对端(GPU 侧)不需要软件参与,也不需要 CPU 中介。出站的 prompt 和入站的结果分别暂存在 DPU 本地缓冲区里,把控制元数据和批量 token 流量隔开,互不干扰。突发到达时,前端合并多次传输以摊销 RDMA 开销。

槽追踪器:不在提交前全量扫描#

每次提交前都通过 RDMA 全量扫描 4096 个槽找空位,代价太大。槽追踪器在 DPU 本地维护一个空闲槽可用性缓存,定期用一次批量 RDMA 读刷新;再用”提示式”环形扫描,摊还 O(1) 找到空槽,减少单次提交的 RDMA 开销。

token 读取器:TTFT 优先的轮询#

后台 token 读取器持续轮询环形缓冲区找生成的 token。每个轮询周期发一次 RDMA 读刷新槽位元数据(64KB),然后对比每个活跃槽的”生成计数”与本地状态,检测新输出。新槽进”紧急槽”、优先扫描,保证第一个 token 在一个轮询间隔内取回——这是压低 TTFT 的关键一环。自适应轮询在 token 延迟与 RDMA 流量之间取平衡:突发时限制单周期工作量、用大的 RDMA 任务池避免完成队列饱和,并设专门的进度线程处理完成事件。

ARM 上的高效 tokenizer#

tokenization 通常被认为是小活,但在 DPU 上做就成了微架构挑战。Blink 的实现细节相当讲究:

  • 合并规则放在64 字节对齐的扁平哈希表里,每条 L1D 缓存行打包 4 个键值对;
  • 符号节点 16 字节对齐,让短词的工作集落在两条缓存行内,避免堆间接跳转;
  • 正则预切分用 ARM NEON SIMD 做字节分类,每周期处理 16 字节;
  • 所有请求态都在预分配的线程局部缓冲区,请求路径上零堆分配。

效果(Figure 4):在 BlueField-3 的 A78 核上,输入 10-2048 token 时比 HuggingFace tokenizer(vLLM/SGLang 用的)快 8-19.7 倍,且全程优于 llama.cpp——尽管 ARM 核主频更低。DPU 没有成为 tokenization 瓶颈。

tokenization 延迟对比:BlueField-3 ARM 核上的 Blink 比 Xeon 上的 HuggingFace 快 8-19.7 倍
tokenization 延迟对比:BlueField-3 ARM 核上的 Blink 比 Xeon 上的 HuggingFace 快 8-19.7 倍

模型兼容性:为什么 MoE 模型收益最大#

常驻调度器把推理图当作不透明计算:填输入张量、启动图、读输出缓冲区。因此只要 TensorRT 能编译的模型都能跑——稠密 Transformer、MoE、encoder-decoder 都只需一次编译,调度器、环形缓冲区、RDMA 数据通路一行不改。新的注意力机制、量化方案,乃至 chunked prefill、prefix caching、投机解码等服务层优化,都和 Blink 的架构正交(第 7 节有具体集成路径)。

评估中一个非常突出的现象是 MoE 模型收益最大:Qwen-3 30B-A3B(30B 总参数、3B 激活)上,Blink 相对 TensorRT-LLM 的饱和吞吐高出 37%,而 Qwen-3 32B 稠密模型只有 8%。论文给了两个原因,第二个特别有洞察力:

  1. MoE 的算力-编排比不利:30B-A3B 每个 token 只激活 3B 参数,解码步在 GPU 上飞快完成——计算量和小稠密模型相当——但每步的 CPU 编排成本(调度器迭代、host-device 同步、batch 重组)是固定的。CPU 开销占总步时间的比例大得多,去掉它的收益自然成比例放大。可以用一个简单的模型理解:设一步解码时间 Tstep=Tgpu+ThostT_{\mathrm{step}} = T_{\mathrm{gpu}} + T_{\mathrm{host}},其中 TgpuT_{\mathrm{gpu}} 是 GPU 计算时间、ThostT_{\mathrm{host}} 是主机编排时间,则去掉主机编排后的加速比为:
speedup=Tgpu+ThostTgpu=11f,f=ThostTgpu+Thost\text{speedup} = \frac{T_{\mathrm{gpu}} + T_{\mathrm{host}}}{T_{\mathrm{gpu}}} = \frac{1}{1 - f}, \quad f = \frac{T_{\mathrm{host}}}{T_{\mathrm{gpu}} + T_{\mathrm{host}}}

ff 是主机开销占比。稠密大模型上 TgpuT_{\mathrm{gpu}} 大、ff 小,加速比趋近 1;MoE 上 TgpuT_{\mathrm{gpu}} 小、ff 大,加速比显著大于 1。论文的实测序列(8% → 37%)正好对应这个规律。

  1. MoE 的专家路由是”数据依赖但不形状依赖”:选哪些专家取决于每个 token 的隐藏状态,但无论路由结果如何,所有张量维度都固定。TensorRT 的 MoE 插件在固定大小缓冲区内部完成 gating、token 到专家的分发和 gather,整个前向(含 MoE 层)可以捕获成单张静态形状的 CUDA Graph。设备端图启动因此可以无主机干预地执行 MoE 模型;而 CPU 主导的基线系统即使引擎本身能自主运行,每个解码步仍要交一次”编排税”。

评估:隔离、干扰与能耗#

实验配置:单张 H100(96GB HBM3),双路 Xeon Gold 6336Y(共 96 核),256GB DDR5,ConnectX-6 200Gbps 网卡;Blink 前端跑在独立的 BlueField-3 DPU 上,经 200Gbps RDMA 连接。四款模型:Llama-3 8B、Phi-4 15B、Qwen-3 32B(稠密)和 Qwen-3 30B-A3B(MoE)。基线:TensorRT-LLM v1.1.0(TensorRT v10.14,与 Blink 用完全相同的引擎)、vLLM v0.13.0、SGLang v0.5.8,全部推荐生产配置 + CUDA Graphs;chunked prefill、prefix caching、CPU offload 一律关闭(Blink 尚未实现这些)。负载是 ShareGPT v3 轨迹(guidellm 工具驱动),13 档到达率 1-32 req/s,每档 60 秒。

隔离运行是 CPU 中介系统最好的情况——独占全部主机资源。即便如此,在 Blink 定义的”未饱和工作范围”(Llama-3 8B 为 λ≤12 req/s,Phi-4 15B 为 λ≤7,Qwen-3 32B 为 λ≤2,MoE 为 λ≤4)内取几何平均:

模型指标BlinkTRT-LLMvLLMSGLang
Llama-3 8BP99 TTFT (ms)653.8880.01309.61747.1
Llama-3 8BP99 TPOT (ms)15.117.724.230.7
Llama-3 8B饱和吞吐 (req/s)11.8710.809.127.88
Phi-4 15BP99 TTFT (ms)1109.41453.81683.72874.1
Phi-4 15BP99 TPOT (ms)25.029.834.547.9
Phi-4 15B饱和吞吐 (req/s)6.726.426.055.58
Qwen-3 32BP99 TTFT (ms)9481.39621.410862.411413.0
Qwen-3 32BP99 TPOT (ms)113.4115.2133.7123.3
Qwen-3 32B饱和吞吐 (req/s)2.001.971.881.85
Qwen-3 30B-A3BP99 TTFT (ms)1397.54814.78919.211839.8
Qwen-3 30B-A3BP99 TPOT (ms)35.565.890.9120.8
Qwen-3 30B-A3B饱和吞吐 (req/s)4.853.612.912.62

四款模型里 Blink 在三个上全面最优,在 GPU 强绑定的 Qwen-3 32B 上与 TensorRT-LLM 基本持平(这种模型主机侧本来就没多少延迟可挖)。差距最大的是 MoE:基线 P99 TTFT 高 3.45-8.47 倍、P99 TPOT 高 1.85-3.40 倍。与 TRT-LLM 的对比是”同引擎”的:两边跑完全一样的 TensorRT 引擎,TTFT 差距(1.31-3.45 倍)只能来自编排方式——这是整个论文最有说服力的一组数字。

TTFT 优势有两个来源:常驻调度器 1-5μs 认领新请求(CPU 系统每步要付数十到数百微秒的调度与分发延迟),以及 prompt 经单边 RDMA 零拷贝直达显存(基线都要先经过主机 DRAM)。

超过饱和点之后,Blink 的吞吐平台也最高:Llama-3 8B 平台 11.96 req/s(比 TRT-LLM 高 9%),Phi-4 15B 6.86(+6%),Qwen-3 32B 2.13(+8%),MoE 5.07(+37%)。P99 均值看不出的差异在更深的分位数上显形:饱和负载下 Qwen-3 32B 的 P99.9,基线 TTFT 高 4-8%、TPOT 高 15-48%。

干扰运行才是 Blink 的主场。在 90 个主机核上共置 pbzip2(45 线程压缩 50GB 文件)+ Ninja 编译 LLVM(45 并行任务),只给推理留 6 核:

模型系统P99 TTFT 膨胀比P99 TPOT 膨胀比饱和吞吐保留率
Llama-3 8BBlink1.001.001.00
Llama-3 8BTRT-LLM18.8411.100.38
Llama-3 8BvLLM11.127.350.44
Llama-3 8BSGLang8.435.770.48
Phi-4 15BBlink0.920.981.01
Phi-4 15BTRT-LLM10.666.170.41
Phi-4 15BvLLM7.144.740.47
Phi-4 15BSGLang3.823.150.47
Qwen-3 30B-A3BBlink1.140.970.99
Qwen-3 30B-A3BTRT-LLM4.909.190.28
Qwen-3 30B-A3BvLLM2.023.040.54
Qwen-3 30B-A3BSGLang1.983.960.45

Blink 的膨胀比全部落在 0.92-1.14 之间(测量方差内),饱和吞吐保留 99-102%;基线普遍膨胀一个数量级、吞吐保留率掉到 0.28-0.64。MoE 模型上最惨烈:TRT-LLM 的 TPOT 膨胀 9.19 倍、饱和吞吐从 3.61 req/s 崩到 1.01 req/s——干扰下整台机器实际”死亡”。平台保留率方面,Blink 保留 99-100%,基线只有 32-64%,干扰下 Blink 的平台吞吐比基线高 1.69-4.08 倍。

四款模型在隔离与干扰下的吞吐曲线:Blink 平台不变,基线崩塌
四款模型在隔离与干扰下的吞吐曲线:Blink 平台不变,基线崩塌

四款模型在隔离与干扰下的 P99 TTFT 曲线:Blink 两线几乎重合,基线尾部急剧抬升
四款模型在隔离与干扰下的 P99 TTFT 曲线:Blink 两线几乎重合,基线尾部急剧抬升

能耗:用智能电表测整机墙侧功耗(Blink 额外计入 BlueField-3 的功耗,按 0.5s 间隔采样)。每 token 能耗公式:

Etoken=PavgΔTNE_{\mathrm{token}} = \frac{P_{\mathrm{avg}} \cdot \Delta T}{N}

其中 PavgP_{\mathrm{avg}} 是平均墙侧功率、ΔT\Delta T 是基准时长、NN 是成功处理的 token 数。四个系统墙侧功率都在 1.1-1.4kW 区间,所以每 token 能耗与吞吐近似成反比。隔离下 Blink 每 token 363-1306 mJ,比各模型最省电的基线低 13.7-48.6%(MoE 上最显著:607 vs TRT-LLM 的 1180 mJ/tok);干扰下基线能耗膨胀 69-182%,Blink 最多膨胀 21%,绝对能耗比最优基线低 41.4-70.7%。

隔离与干扰下四款模型的每 token 能耗对比
隔离与干扰下四款模型的每 token 能耗对比

局限与未解决的问题#

Blink 把”CPU 干扰免疫”这件事做到了极端,但它的边界同样清晰:

  • 单 GPU 原型,无多卡扩展实现。论文给出了扩展路径而非实现:每张 GPU 实例化一个常驻调度器,图之间插入 GPU 原生通信原语(NCCL 集合通信、或经 IBGDA 的 GPU 发起 RDMA),MoE 的 all-to-all 用 GPU 发起的 dispatch 避免 NCCL CPU proxy 开销。这些机制都在 GPU 上执行,能保住 CPU-free 关键路径,但”完整实现与评估留作未来工作”。
  • 暂不支持 chunked prefill、prefix caching、投机解码。论文认为这些优化能自然映射到常驻调度器上:调度器本来就在跟踪每请求进度与 KV cache 状态,可以增量 prefill;paged KV cache 提供可复用块,可以在调度器内部放一棵 GPU 常驻的前缀树;投机解码就是调度器先跑草稿再验证。但基准对比中这些功能被刻意关闭(“Blink 尚不包含这些优化”),意味着真实世界的差距可能比论文数字更窄——反过来,这也意味着 Blink 的架构优势是在”大家都不开高级优化”的公平前提下测出来的。
  • 要求模型装进 GPU 显存。模型放不下 HBM 时的 CPU/DRAM offload 场景,主机 CPU 不仅回到调度路径,还回到数据搬运路径——每 token 都要动态路由专家、在主机内存和显存之间迁移权重,干扰问题会更严重。论文指出扩展方向是让 DPU 的 RDMA 引擎直接管理专家迁移,把权重搬运移出主机内存总线。这对 MoE 尤其重要,因为 MoE 总参数量远超激活参数量。
  • 硬件依赖。需要 BlueField-3 级 DPU、ConnectX 网卡、CUDA 13 的 device graph launch——这是 NVIDIA 生态特定方案,其他平台没有对应物。
  • 实现规模。GPU 后端约 1.6 万行 CUDA/C++(CUDA 13.1 + TensorRT 引擎),DPU 前端约 1.7 万行 C/C++(DOCA 3.2 SDK),共约 3.3 万行系统代码。论文称发表后将开源,目前尚未放出。
  • 单点故障与运维。调度器变成 GPU 上的无限循环,一旦它崩溃或死锁,没有 CPU 兜底——容错、热升级、可观测性都是工程上待解的问题(论文未讨论)。

与既有 SmartNIC 工作的关系也值得厘清:Lynx 让 SmartNIC 替代 CPU 编排 GPU 网络服务,但只处理人脸识别、LeNet 这类一次性推理;SplitRPC 把推理负载从网卡直送显存,但编排仍在 CPU 上;Conspirator 把 ML 控制面搬上 SmartNIC ARM 核,但针对分布式训练的任务级调度;OS2G 用 DPU 直连 GPU 做训练存储 I/O。它们各自验证了 Blink 的某一块积木(DPU 到 GPU 的直传、SmartNIC 控制面),但没有一个处理自回归推理最麻烦的部分:token 级连续批处理、跨长会话的 KV cache 状态管理、逐 token 流式。Blink 是第一个把整条自回归推理生命周期重构掉 CPU 的系统。

小结#

Blink 的核心贡献不是某个 kernel 变快了,而是回答了”推理服务栈的控制面到底应该住在哪”:长期住在 GPU 上,短期住在 SmartNIC 上,而不是住在 CPU 上。它的设计决策链可以压缩成四句话:

  1. 主机 CPU 的微架构共享资源(LLC、TLB、页表)是干扰放大器,只要调度经过 CPU,共置必然受害——这是动机;
  2. 单边 RDMA + GPU 显存环形缓冲区,让数据平面彻底绕开主机内存层次,这是数据通路;
  3. 常驻调度内核 + 设备端 CUDA Graph 启动(配合窗口式 tail launch 恢复突破 120 次上限),让控制平面住在 GPU 上,这是控制通路;
  4. DPU 的每核网络带宽优势让它天然适合请求管理与 tokenize,这是分工。

代价是专用硬件、3 万行系统代码、以及尚不完整的高级优化支持;收益是隔离状态下 P99 TTFT 最高降 8.47 倍、吞吐最高升 2.1 倍、每 token 能耗降 48.6%,干扰状态下性能几乎不衰减,而基线崩塌一到两个数量级。当数据中心运营商为了共置收益而被迫给每台推理机器预留 CPU 余量的时候,Blink 给出的答案是:让 GPU 自己开自己的机器

参考资料#

  1. Blink: CPU-Free LLM Inference by Delegating the Serving Stack to GPU and SmartNIC(arXiv:2604.07609,KTH & RISE,2026 年 4 月)
  2. Blink 论文 HTML 全文(含全部图表)
  3. NVIDIA CUDA 编程指南:CUDA Graphs(含 device graph launch 与 fire-and-forget 模式)
  4. NVIDIA Developer Blog:Enabling Dynamic Control Flow in CUDA Graphs with Device Graph Launch
  5. Orca: A Distributed Serving System for Transformer-Based Generative Models(OSDI’22,连续批处理与迭代级调度)
  6. Efficient Memory Management for Large Language Model Serving with PagedAttention(SOSP’23)
  7. vLLM V1: A Major Upgrade to vLLM’s Core Architecture(vLLM Blog)
  8. SGLang v0.4: Zero-Overhead Batch Scheduler, FP8 Cache, and More(LMSYS Blog)
  9. Can Scheduling Overhead Dominate LLM Inference Performance?(CPU 调度开销研究)
  10. Taming Throughput-Latency Tradeoff in LLM Inference with Sarathi-Serve(OSDI’24)
  11. DistServe: Disaggregating Prefill and Decoding for Goodput-Optimized Large Language Model Serving(OSDI’24)
  12. NVIDIA-Certified Systems Configuration Guide(每 GPU 至少 6 个物理核的要求来源)
  13. DeepEP: An Efficient Expert-Parallel Communication Library(GPU 发起 RDMA / IBGDA)
  14. GuideLLM: Evaluate and Enhance Your LLM Deployments(负载生成工具)

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Blink:把 CPU 请出推理关键路径——SmartNIC 与 GPU 常驻内核的 CPU-Free 服务架构(2026)
https://pinghaoyang.com.cn/aigc/posts/blink/
作者
平昊阳
发布于
2026-08-18
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
平昊阳
乘长风,破巨浪, 展鸿图于未央!
--
总访问量
--
访客数
公告
欢迎来到我的个人博客!欢迎关注交流吖!
更多相关公告,见
社交-留言」。
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
站点统计
文章
66
分类
16
标签
93
总字数
477,284
运行时长
0
最后活动
0 天前

文章目录