外观
推理服务系统:Clipper / Orca / Nexus 等
模型部署的本质一半是「把模型变小」,另一半是「把服务跑稳跑快」——后者就是推理服务系统的领域。这篇精读按时间线走一遍四篇关键论文:TensorFlow Serving(范式定义者)、Clipper(低延迟服务层)、Orca(迭代级调度,连续批处理前身)、Nexus(GPU 分片与多租户)。读完你会发现,今天 Triton、KServe、vLLM 里的每个特性,都能在 2016-2022 的论文里找到出处。
先读 服务化与推理 API 与 LLM 推理 建立概念底座。
总览表
| 系统 | 年份/会议 | 核心贡献 | 今天谁继承了它的思想 |
|---|---|---|---|
| TensorFlow Serving | 2016 系统 / 2017 论文(NIPS ML Systems Workshop) | 模型版本管理、热加载、动态批处理、gRPC——「模型服务框架」范式的定义者 | NVIDIA Triton、KServe、TorchServe |
| Clipper | 2017 / NSDI | 通用预测服务层:缓存、延迟感知批处理、自适应模型选择 | 模型网关/路由、批处理调度器、AB 实验系统 |
| Nexus | 2019 / SOSP | GPU 集群推理引擎:把 DNN 拆成片段执行、时间片调度、多租户共享 | GPU MIG、Triton 多模型并发、PD 分离(prefill/decode 拆分) |
| Orca | 2022 / OSDI | 迭代级调度 + 选择性批处理,让 LLM 批处理真正跑起来 | vLLM、TGI、TensorRT-LLM 的连续批处理 |
一、TensorFlow Serving:范式定义者(Olston et al., 2016/2017)
一句话贡献
第一个产品级模型服务框架:把「模型即服务」的组件——servable 版本管理、热加载、动态批处理、gRPC 接口——固化成可复用范式,定义了一个沿用至今的分层架构。
背景与动机
2015 年前后,Google 内部每个模型上线都靠手工脚本:Flask 起个服务、版本一换全量重启、并发一高就崩。TensorFlow Serving 的目标是把「模型上线」变成「配置一个 servable」:模型路径即版本,新版本写好配置、热加载,流量自动切过去,还能回滚。
方法核心
- Servable 与版本管理:servable 是「可服务的模型实例」,每个 servable 有版本号(模型导出路径编码版本);Manager 维护多版本并存,查询时按
(servable, version)寻址。 - 热加载与优雅切换:新版本加载完成后原子切换,旧版本按引用计数回收,服务不中断。
- 动态批处理(dynamic batching):请求先入队,按「批大小阈值 + 最长等待时间」聚合成 batch 再推理——吞吐与延迟之间的旋钮。
- 接口:gRPC(Protobuf),支持多种框架(论文里是 TensorFlow,架构上可扩展)。
text
客户端 → gRPC
→ 预测请求(servable, version, input)
→ Servable Manager(版本选择 / 热加载)
→ 动态批处理器(攒批:max_batch_size / batch_timeout)
→ 模型执行(GPU/CPU)关键结果
论文侧重架构与工程而非 benchmark:核心结论是「模型查找与推理的热路径被认真优化,避免了朴素实现里的性能坑」,并支撑了 Google 内部多租户托管服务 TFS²。它的最大贡献是定义问题:版本、批处理、热加载,从此成为「服务框架」的必要组件清单。
局限
- 单一框架锁定(TensorFlow 模型);多框架混部要等后来的 Triton。
- 早期是单机设计,跨机扩展、弹性伸缩不是它的主场。
对今天的启示
- Triton 直接继承了版本管理、动态批处理、gRPC,并把「多框架后端」做成核心卖点,见 Triton 实战。
- KServe 把「版本 = 部署配置」演进成 K8s 原生资源(灰度、回滚声明式完成)。
- 面试高频题「为什么需要模型版本管理」的答案就在这篇论文里。
二、Clipper:通用低延迟预测服务层(Crankshaw et al., NSDI 2017)
一句话贡献
在应用和 ML 框架之间加一层通用服务层:用缓存、延迟感知自适应批处理、模型选择三件套,让预测服务在满足延迟目标的前提下提高吞吐与鲁棒性——「模型服务平台」而非「单个模型服务」。
背景与动机
TensorFlow Serving 解决「一个模型怎么服务」;Clipper 问的是更大的一层:当一个应用要调用多个模型、或同一功能有多个候选模型时,谁来当统一入口? 它的目标是「应用只写一次调用逻辑,底层模型怎么部署、怎么选、怎么批,全由服务层管理」。
方法核心
- 缓存(caching):相似/相同查询命中缓存直接返回,跳过推理——对图像检索、推荐这类高频重复查询,收益巨大。
- 延迟感知自适应批处理(adaptive batching):不设死批大小,而是以「满足延迟目标(如 P99 < 100ms)」为准动态调整批大小与等待时间。
- 自适应模型选择(adaptive model selection):同一功能维护多个精度/速度不同的模型,按当前负载与延迟预算动态路由——负载低用高精度模型,负载高切换到快模型(多臂老虎机式的在线学习)。
- 模块化架构:应用层(客户端库)→ 模型选择层 → 查询管理(缓存/批处理)→ 模型执行层,各层可插拔。
关键结果
- 在 4 个 benchmark 数据集上,延迟约束下吞吐与鲁棒性均优于朴素部署。
- 与 TensorFlow Serving 对比:达到相当的吞吐与延迟,同时额外支持模型组合与在线学习(缓存/模型选择带来精度与鲁棒性增益)。
- 关键指标是延迟目标达成率:Clipper 的调度目标不是「平均延迟」而是「P99/尾延迟达标」,这与今天 SLO 驱动的容量规划完全一致。
局限
- 针对单请求快速推理(分类、检索),不针对 LLM 的自回归长任务。
- 模型选择需要一组「不同精度/速度」的候选模型,不是所有场景都有。
对今天的启示
- 模型网关与路由:Clipper 的模型选择就是今天 LLM 网关(model gateway)、多模型路由、A/B 分流的思想源头。
- 延迟目标达成率:今天 容量规划 和 可观测性 的核心指标 P99/SLO,Clipper 在 2017 年就把它做成了调度器的优化目标。
- 缓存:LLM 时代的「前缀缓存」是同一个思想在新形态下的重演(见 vLLM 论文)。
三、Nexus:GPU 集群推理引擎(Shen et al., SOSP 2019)
一句话贡献
把 GPU 集群的 DNN 推理服务做成「拆片段 + 时间片」的调度问题:不整模型跑完,而是把 DNN 拆成片段按需调度、多个视频分析应用共享 GPU,在延迟约束下把吞吐推到接近最优。
背景与动机
视频分析(实时对象检测、行为识别)是 2019 年 AWS 的大规模推理场景:几十上百路摄像头、每路一个「应用」持续处理视频流。如果每路应用独占一块 GPU,成本爆炸、利用率极低。Nexus 的目标:让一个 GPU 集群高效地服务大量并发视频分析应用,同时满足每个应用的低延迟 SLO。
方法核心
- DNN 片段执行:不把整张图交给 DNN 一次跑完,而是把视频流切成「帧块」,DNN 按**片段(fragments)**粒度在 GPU 上执行——这样多个应用可以交错共享 GPU,而不是排队抢整卡。
- 帧处理单元(Frame Processing Unit):以帧块为基本调度单位,支持时间片分片——GPU 在一个时间片内处理应用 A 的片段、下一片处理 B。
- 抢占式调度:高优先级应用可抢占低优先级应用的资源,保证延迟 SLO。
- 帧共享/去重:多个应用分析同一路视频时,共享特征提取的计算结果。
关键结果
| 指标 | 数字 |
|---|---|
| 吞吐(16 GPU,99% 时间满足延迟约束) | 请求处理速率比同期 SOTA 高 1.8-12.7x |
| 利用率(长时间多应用部署) | 保持在最优利用率的 84% 附近 |
| SLO(100-GPU 集群) | 仅 0.27% 的请求违反延迟 SLO |
局限
- 面向流式视频分析的 DNN(CNN 类),不是 LLM 的自回归生成(后者要等 Orca)。
- 片段执行需要对模型/算子做切分支持,工程成本高。
对今天的启示
- GPU 时间片/显存分片:Nexus 的「把 GPU 切成可调度的片」就是今天 MIG(Multi-Instance GPU)、Triton 多模型并发、以及 K8s 上 GPU 共享调度(如 time-slicing)的思想前身。
- 片段执行:LLM 时代的 PD 分离(prefill/decode 分离部署)、chunked prefill,本质是「把一次大计算拆成片段、更细粒度地调度 GPU」——Nexus 开了这条路。
- 多租户 SLO 保障:为「一个集群跑很多个模型服务」提供了可量化的评估框架(SLO 违反率)。
四、Orca:迭代级调度(Yu et al., OSDI 2022)
一句话贡献
针对 Transformer 生成模型的迭代级调度:把批处理的调度粒度从「请求」降到「迭代」,配合选择性批处理,让 LLM 服务吞吐量级提升——连续批处理(continuous batching)的发明者。
背景与动机
2022 年,GPT-3 类模型刚进入在线服务,但传统推理框架(基于 request-level scheduling)在 LLM 上表现极差:一次请求要跑几十上百次迭代(每次生成一个 token),而框架只能整批等最慢的请求:
- 批内先完成的请求不能提前返回,GPU 在等「短板」;
- 新请求必须等当前 batch 全部结束才能进来;
- 结果:GPU 利用率低、尾延迟差、吞吐被批量机制锁死。
方法核心
- 迭代级调度(iteration-level scheduling):调度器只在**每次迭代(生成一个 token)**之后重新决定 batch 组成——完成的请求立即出队,新请求立即入队,batch 永远装满。
- 选择性批处理(selective batching):不是所有算子都适合批处理。Orca 只对「显存/带宽密集、批处理收益大」的算子(矩阵乘类)做批处理,而对自回归特有的逐 token 算子保持独立执行——避免把不友好的算子强行批在一起拖慢整体。
- 支持分布式扩展(模型并行),面向百亿/千亿参数模型。
关键结果
| 指标 | 数字 |
|---|---|
| 吞吐(GPT-3 175B,同延迟水平) | 比 NVIDIA FasterTransformer 高 36.9x |
| 延迟 | 相对 FasterTransformer 显著降低(批内不再互相拖累) |
| 机制影响 | 迭代级调度成为此后所有 LLM 推理引擎的标配 |
为什么 36.9x 这么夸张
不是因为 Orca 的算子比 FasterTransformer 快,而是因为调度机制:FasterTransformer 用固定 batch 等最慢请求,Orca 让 batch 始终满、GPU 始终在算。机制层面的差异可以轻松量级碾压算子层面的优化——这也是「系统论文的价值常在调度而不在算子」的最佳案例。
局限
- KV Cache 仍按连续显存预分配,显存碎片问题未解决——这正是 vLLM 的 PagedAttention 补上的最后一块拼图(见 vLLM 论文)。
- 调度策略偏简单(FCFS 类),没有优先级/抢占的精细设计。
对今天的启示
- 连续批处理是 vLLM、TGI、TensorRT-LLM 的吞吐基石,也是 vLLM 实战 里
max_num_seqs等参数的背后原理。 - 选型经验:调度粒度决定了服务的吞吐天花板,算子优化是在天花板内抠细节。
- Orca → vLLM 的演进是一条完整的知识线:调度解决「满载」,显存管理解决「装得下更多请求」,二者叠加出 2-4x 甚至更高。
五、串联起来看
text
TFServing(2016) Clipper(2017) Nexus(2019) Orca(2022)
定义「服务框架」 定义「服务层」 定义「GPU 分片」 定义「LLM 调度」
版本/批处理/gRPC 缓存/批处理/模型选择 片段执行/时间片/抢占 迭代级调度/选择性批处理
│ │ │ │
▼ ▼ ▼ ▼
Triton/KServe 模型网关/路由 MIG/Triton 并发 vLLM/连续批处理
+ vLLM:把批处理 + 调度 + 显存管理在 LLM 时代合流对今天最直接的结论:你部署里遇到的「多模型怎么共卡」「批处理怎么调」「LLM 吞吐为什么差」三个问题,分别在这四篇论文里能找到第一性原理的答案。
延伸阅读
- PagedAttention:vLLM 系统论文 —— Orca 调度 + 显存分页的集大成者
- 服务化与推理 API —— 服务框架的概念底座
- NVIDIA Triton 多模型服务 —— TFServing 范式在今天的工程形态
- vLLM 大模型推理服务 —— 连续批处理的落地配置
- 并行与分布式推理 —— 单机装不下时如何多卡协同
- 性能优化与容量规划 —— 延迟目标达成率的现代工程方法
参考资料
- TensorFlow-Serving: Flexible, High-Performance ML Serving(arXiv 1712.06139)
- Clipper: A Low-Latency Online Prediction Serving System(arXiv 1612.03079,NSDI 2017)
- Nexus: A GPU Cluster Engine for Accelerating DNN-based Video Analysis(SOSP 2019)
- Orca: A Distributed Serving System for Transformer-Based Generative Models(OSDI 2022)