SOSP 2026 第一天上午的 Session 1A 坐满了人,这在我印象里是少有的事。以前系统顶会的系统论文多少有点“自嗨”属性,但 Model Serving at Scale 这个主题不一样,台下的听众除了做系统的,还有一大票做模型训练、做平台基建、做在线推理的工程师,大家关心的是同一件事:模型越来越大,在线请求越来越密,服务层到底怎么扛住,怎么把 GPU 吃满,怎么在延迟和成本之间找到平衡。
这个 Session 一共六篇论文,主题集中在推理服务的调度、KV Cache 管理、PD 分离和弹性扩缩容上。没有一篇是“我们做了一个新模型”那种,都是“我们解决了一个系统问题”的路子。我全程听下来最大的感受是:Model Serving 已经从“把模型跑起来”的阶段,正式进入了“像做数据库一样精细化管理”的阶段。
1. 这个 Session 在讨论什么:从论文总览看 Model Serving 的攻防战
1.1 叫“Scale”的 Session,题目里藏着三个战场
我先说个整体判断:Session 1A 的六篇论文,表面上各讲各的,但本质都在处理同一个矛盾——模型的显存占用和计算模式与在线服务的延迟要求之间的错配。
第一个战场是 Prefill 和 Decode 的解耦。有论文直接把 prefill 和 decode 拆到不同的 GPU 上跑,甚至不同的机器集群上跑,理由很简单:这两个阶段的计算特征完全不同。Prefill 是典型的计算密集型,矩阵乘占绝对主导,GPU 的算力利用率可以拉得很高;Decode 是访存密集型,每个 token 只生成一次,但每一步都要读取全部 KV Cache,算力利用率上不去,瓶颈在显存带宽。把两者混在一台机器上,要么 prefill 拖慢了 decode 的响应,要么 decode 的低利用率浪费了 prefill 的好算力。拆开之后,各自可以独立扩缩容、独立调优,代价是要处理跨节点的数据传输和调度一致性。
第二个战场是 KV Cache 的管理。有一篇论文的切入点是“paged attention 的路子被大家用滥了,但真的把 KV Cache 当成操作系统内存来管理了吗?”这问题问得挺狠。实际推理场景里 KV Cache 的分配粒度、生命周期、复用策略,比操作系统内存还要复杂。不同的请求有不同的长度,有的 prefix 完全一样可以共享,有的上下文很长但活跃度很低,还有 beam search 这类需要保留多个候选分支的场景。如果只是做固定块分配,碎片率会高得吓人;如果做得太细,管理开销又会吃掉性能收益。
第三个战场是 SLO 感知的调度。有一篇论文把话题拉到了“有效吞吐”这个概念上:你系统每秒能处理 1000 个请求没有意义,如果其中 40% 都超了延迟目标,那实际可服务的容量可能只有 600。这个视角我很认同。在线推理不是跑分,是 SLA 兑付,调度器必须在请求到达之前就预判它的延迟风险,优先处理那些可能“爆 SLO”的请求,同时保证整体资源利用率不降。
1.2 为什么这些论文会被 SOSP 接收:系统贡献大于模型贡献
SOSP 的接收标准向来不是“这个想法多新颖”,而是“这个系统问题有多难,你解决得有多彻底”。这六篇论文能进 Session 1A,核心在于它们都发现了一个真实的、且现有系统没有处理好的瓶颈,并且给出了系统层面的完整方案。
举个例子:有一篇做 PD 分离后网络调优的论文。别人看到的是“prefill 和 decode 分开了,问题解决了”,它们看到的是“分开了之后,中间要传 KV Cache,网络传输开销可能直接吃掉分离带来的收益,该怎么办”。它们做了一个压缩感知和数据预取方案,让 prefill 节点算完一部分就立刻把该传的数据编码发出去,decode 节点边收边解边算,把传输延迟隐藏在计算流水线里。这个贡献点足够“系统”,也足够硬核。
另一个例子是跨请求 KV Cache 共享。很多框架都支持 prefix cache,但大多停留在“这次请求和上次请求前缀一样就直接复用”的粗粒度层面。Session 里这篇把共享粒度推进到了 block 级别,并且用类似引用计数的机制管理 KV Cache 的生命周期。听起来是工程优化,但实现里涉及哈希索引、并发控制、显存回收和碎片整理,这就是标准的系统论文功底。
看完 Session 我最大的感慨是:这个领域已经过了“演示原型”“搭个 benchmark 证明提升 30%”的阶段,开始在逼真的大规模生产负载下做系统设计、故障恢复和多租户隔离,这是领域成熟的标志。
2. 几个印象最深的技术方向与背后逻辑
2.1 PD 分离:一致性优先还是利用率优先
PD 分离最直观的收益是资源隔离。在线对话类场景,decode 阶段的延迟直接影响用户体验;离线批处理或输出很长的生成任务,用户对前几个 token 的响应速度并不敏感。混跑时调度器数学上可以做“优先级调整”,但物理上 GPU 的计算资源是共享的,prefill 的矩阵乘和 decode 的访存必然会互相干扰。拆开之后,这个干扰从物理层面消失了,各跑各的。
代价如何?KV Cache 要从 prefill 节点传输到 decode 节点。如果 batch 很大、上下文又很长,传输的数据量是 GB 级别的。论文里他们测过,如果走普通 TCP 网络,传输时间甚至超过 decode 阶段本身的耗时,等于白拆。所以 PD 分离的可行性完全取决于网络和传输优化,而不是模型层能决定的事。
我做实际系统时的判断标准很简单:请求平均长度低于 2000 token、并发规模不大,PD 分离的收益为负;只有长上下文、高并发、且 SLO 要求严苛的生产场景,才值得付这笔传输成本。Session 里那篇论文的测量结果也验证了这个判断,他们给出的建议是“PD 分离不是默认选项,要按 workload 分布决定”。
2.2 KV Cache 的“内存学”:分页、压缩与置换
KV Cache 这几年地位变化很大,早期大家当它是“临时存储”,现在直接当“一等公民”来设计。原因是长上下文场景的爆发。上下文从 4K 涨到 128K 甚至 1M,KV Cache 占用的显存呈线性增长,不比模型权重小多少。权重是只读的,可以预加载、可以量化、可以多副本;KV Cache 是动态的,每个请求一份,生命周期只有几十秒,却要在毫秒级完成分配和释放。
Session 里那篇 block 级共享的论文,本质上就是把 KV Cache 的处理往操作系统内存管理方向推:块分配、引用计数、LRU 淘汰、碎片整理。它解决了什么问题?最典型的是多用户共享 prefix 的场景。比如一个企业知识库问答系统,所有请求的 prompt 前缀都是那段固定的系统提示词加用户文档,如果每个请求都重新算一遍这些前置 token,GPU 算力浪费极其严重。共享前缀后,同一个 block 可以被几十个请求同时引用,显存占用和计算量同时降下来。
KV Cache 量化也是讨论热点。把 cache 从 FP16 降到 FP8 甚至 INT8,显存直接减半,但要注意量化误差会随生成长度累积,到后面输出质量明显下降。论文里给的解法是混合精度:离当前生成位置近的 cache 用高精度,远的用低精度。这个思路我很赞同,因为影响生成质量的 cache 主要是近期窗口,早期的 token 在注意力计算中的权重被 softmax 摊薄了。
2.3 SLO 感知调度:从“吞吐最大”到“有效吞吐最大”
很多推理系统目前做的调度很简单:请求来了,往队列里一丢,GPU 空闲了就取一个执行。这种方式在负载均匀时没问题,但真实业务是潮汐性的,请求尖峰来的时候,排队时间可能直接超过 SLO 容忍上限。
Session 里有一篇论文把这个抽象为“带截止时间的作业调度”问题,但约束条件比 CPU 调度复杂得多:每个请求的 KV Cache 占用不同、延迟敏感度不同、共享 prefix 的亲和性不同。调度器还得考虑 GPU 内部的内存碎片,可能在拒绝一个有足够显存空间的请求之前,先快速扫描一遍可复用的 cache block。
它们提出的方案让我想起数据库里的 cost-based optimizer:对每个请求做代价估算,包括排队延迟、执行时间和资源需求,然后统一做规划。这个方向做起来很难,但一旦做出来,价值极大。在线推理系统的资源利用率通常不到 50%,不是因为 GPU 不行,而是调度器在保守地回避风险、牺牲吞吐来保延迟,如果能把有效吞吐从 50% 提到 70%,等于白捡了一倍硬件。
2.4 分布式推理的弹性与容错:多卡多机下的新瓶颈
单机扛不住超大模型时,就必须走张量并行或流水线并行。但这里有个隐藏问题:并行度越高,通信占比越大。张量并行每做一次计算就要做一次 all-reduce,模型规模很大的情况下,通信可能占据 50% 以上的时间。Session 里那篇多机推理论文的观察是:推理场景的负载模式和训练完全不同,训练是稳定的长运行任务,通信模式是规则可预期的;推理是动态到达、长短不一的请求,通信模式高度碎片化。针对碎片化通信做优化,是新的系统贡献空间。
另一个点是容错。训练任务挂了一台机器,用户感知不到;在线推理挂了一台机器,用户直接看到“请求失败”。Session 论文里给了个方案:把请求处理的中间状态(KV Cache、队列位置)复制到备用节点,主节点挂了直接切换,尽量做到用户无感。这个方向我觉得还没完全解决,但已经开始往正确的方向走了。
3. 从论文到生产:把 Session 里的想法落地时要面对的真问题
3.1 评估指标先对齐:TTFT、TPOT 与 Goodput,别被论文平均数骗了
论文里的“平均延迟降低 30%”经常是乐观的。实际生产中,单个请求的体验由两个指标决定:TTFT(首 token 时间)和 TPOT(单 token 生成时间)。前者决定“用起来爽不爽”,后者决定“答得快不快”。调度策略对这两个指标的影响是独立的:一个请求可能首 token 很快,但后续生成被其他请求挤占,整体体验照样差。
更麻烦的是,这类系统的负载是重尾分布。绝大多数请求很短,偶发几个超长请求会把系统拖垮。如果用平均延迟评估,短请求的快速掩盖了长请求的灾难;但用户不会去算平均延迟,他只会感受到“那个请求等了 30 秒”。所以我说论文里的平均数只能信一半,更多要去看 P99 甚至 P999 的表现。有篇论文在这个点上做得扎实,它们报告延迟分布时按输入长度分桶,单独展示长尾,一看就知道问题出在哪。
我在生产环境做容量评估时,用的核心指标是 Goodput:在 SLO 达标范围内每秒处理的有效请求数。一个系统如果吞吐很高但 40% 的请求超时,那有效吞吐只有 60%,比一个吞吐低但全达标的系统要差得多。做论文评述也好,做系统选型也好,建议先问一个问题:这个系统优化的核心指标是吞吐、TTFT、TPOT,还是有效吞吐?不同指标导向下,系统设计可能完全相反。
3.2 硬件与网络约束:NVLink、RDMA 与 PD 分离的取舍
PD 分离对网络的要求极高,因为 KV Cache 的传输量实在太大。多机场景下,最优路径是 RDMA,延迟微秒级,带宽也足;如果只有普通 TCP,传输时间会直接主导延迟。Session 里那篇论文给了一组实测数据:在 100Gbps 以太网上传 128K token 的 KV Cache,耗时约 50ms,看起来不多,但那是理论带宽利用率 100% 的理想值,实际跑上 80% 就不错了,还要加协议开销,用时奔着 100ms 去了。而 decode 阶段单 token 的延迟通常在 20~40ms,传输 100ms 意味着白白多出 2~4 个 token 的时间。
正因为这个原因,我看到很多实践中的 PD 分离并不是所有流量都拆,而是把长上下文和短上下文分开处理:短请求留在单体模式,长请求走 PD 分离。或者通过局部性调度把 prefill 和 decode 节点放在同一个机架内,走 NVLink 而不是以太网,传输开销可以降低一个数量级。论文里给的方案更激进,它们用压缩加流式预取,把 KV Cache 编码成紧凑格式边发边解。看起来复杂,但确实是解决长上下文场景的唯一出路。
硬件层面还有个很容易被忽略的点:KV Cache 占显存,显存不够时只能往 CPU 内存换,换入换出的代价是几十倍的访问延迟差。有的论文用“换出+预取”的思路,提前把未来可能用到的 cache block 换回显存,把换入换出的开销从“命中时的一次性惩罚”变成“流水线化隐藏”。思维上很漂亮,工程上实现难度不小。
3.3 可观测性与落地路径:论文系统缺的那块拼图
每篇论文的评估环节都会展示一堆指标提升图,但真正到生产落地时,第一个障碍不是性能,而是可观测性。论文环境里,负载是合成的,failure 是注入的,指标是拿到全程监控数据的;生产环境里,你不知道线上真实负载分布,不知道哪个用户触发了慢请求,不知道哪台机器的 GPU 掉进了降频状态,系统再聪明也无从发力。
Session 里有一篇论文让我眼前一亮,它们的系统自带“请求级 profiling”:每个请求延迟达标与否、在哪里排队、KV Cache 命中率是多少、prefill 和 decode 各耗时多久,全部能追踪到。有了这个数据,SLO 调度才能闭环:调度器不是盲目做决策,而是根据上一时段的真实表现动态调整参数。这种从“设计系统”到“运营系统”的思路转变,是生产级推理系统最稀缺的部分,比单个算法优化更值得关注。
落地路径也很重要。论文方案往往是整套设计耦合在一起,比如调度器要和 KV Cache 管理器和 PD 分离模块深度配合。如果用户只想要其中一部分优化,拆出来用就是噩梦。我做选型时会优先考虑模块边界清晰的系统,哪怕单模块性能不是最优,至少我可以分阶段演进:先上 KV Cache 共享,再改 PD 分离,最后做 SLO 调度。步子小,风险也可控。
4. 实操手记:我们在线上复现类似方案时的几点教训
4.1 踩坑一:动态 batching 参数不是越大越好
很多论文大力宣传连续批处理(continuous batching)的收益:请求到了就插入运行中的 batch,不用等当前 batch 跑完。理论上这能把 GPU 利用率拉满,但实践里 batch 开得越大,单个请求的生成速度就越慢。原因很简单:GPU 的算力是共享的,batch 从 8 涨到 64,单个 token 的生成延迟可能是原来的 3~4 倍。
如果你只盯着吞吐,这个损失无所谓;但如果你的业务对 TPOT 有明确上限,比如要求 50ms 一个 token,那 batch 超过 32 就可能大量违反 SLO。我们的做法是给连续批处理加一个动态上限:调度器实时测量当前平均 TPOT,超过目标值就暂停新请求进入,让已有请求先跑完。这其实是把论文里的 SLO 感知调度落到了最简单的形态——动态控制 batch size。
另一个细节是 preemption 的处理。连续批处理如果允许优先级高的请求抢占正在运行的请求,被抢的请求要么保存检查点后暂停,要么直接被丢弃。推理场景里 checkpoint 的成本比训练更高,因为 KV Cache 占显存,保存检查点的开销可能高达数十毫秒。我们的方案是不做请求级抢占,而是靠调度器预估完成时间来避免长请求霸占 GPU,短请求等待太久就用多个副本消化。靠调度预测代替抢占打断,简单且稳定。
4.2 踩坑二:KV Cache 量化带来的漂移不可忽略
论文里 KV Cache 量化通常只报 PPL(困惑度)变化,看起来损失很小,0.1 都不到。但生产场景评估的是生成质量,尤其是代码生成、数学推理这类对逻辑一致性要求很高的任务。量化后的 cache 在长上下文场景可能出现语义漂移,导致模型引用了错误信息或者逻辑断裂。这不能怪量化方法本身,而是评估指标不对:应该用任务级指标(比如 pass@k、准确率)而不是语言模型困惑度。
如果你确实想把 KV Cache 量化用起来,我建议做分层策略:靠近当前生成位置的最关键层保持高精度,其余层量化。Session 论文里的混合精度方案在这一点上给了很好的验证。另一个务实建议是量化后做质量回归测试,覆盖长上下文、多轮对话、检索增强三类典型负载,不能只跑一两个 benchmark。
4.3 踩坑三:弹性伸缩与长连接的心跳博弈
在线推理服务普遍用长连接维护客户端与推理实例之间的通道。弹性伸缩的常规路径是:负载高了,扩容新实例;负载低了,缩容旧实例。但缩容会切断长连接,正在途中的请求立刻失败。论文里描述的方法很多,但很少提到这个工程侧的致命细节。
我们的做法是把缩容分成两阶段:先摘流量,让负载均衡器不再往目标实例发新请求,同时等待存量请求跑完,设置一个上限等待时间;超时后强制断开。摘流量这个动作看起来简单,但负载均衡器是否有“连接排空”能力,决定你能不能优雅下线。如果连这个都没考虑,弹性伸缩的实际可用性会大打折扣。
有篇 Session 论文给了个不错的补充:缩容前先把该实例上的 KV Cache 共享信息广播给其他实例,让其他实例的 prefix cache 命中率提高,弥补新请求迁移的代价。这个想法在显存充足时收益不大,但在高负载切换时,能显著减少冷启动带来的延迟突刺。
5. 评审视角:这些方向谁最可能成为下一年度的默认实践
5.1 我会给出最强推荐的三个方向
第一个是 PD 分离。我认为它会被越来越广泛地采用,不是因为它听起来高级,而是它对资源利用率的提升是结构性的。当模型上下文越来越长,prefill 和 decode 的资源配比需求差距越来越大,固定比例混合的模式必然造成浪费。未来可能出现专业的 prefill 集群和 decode 集群,甚至按任务类型细分。相关的网络传输优化、KV Cache 编码压缩、跨节点调度协议都会变成标准组件。
第二个是 KV Cache 的跨请求共享与管理。只要多用户场景存在,prefix 共享就是一个无法绕过的基本需求。接下来大概率会出现一种 KV Cache 的专用管理框架,可能把方向从“按需分配”推至“主动缓存 + 复用预测”,类似操作系统的 page cache 预读策略。
第三个是 SLO 感知调度。它短期停留在实验阶段,长期会成为标配。当前在线推理系统的调度器多数只是“尽量不要超时”的启发式策略,做到了不去主动分析每个请求的资源需求。随着模型和服务形态越来越多样(不同任务类型、不同上下文长度、不同量化精度),启发式策略会越来越不够用,cost-based 调度几乎是必然路线。
这三个方向有个共同点:它们都不是“把性能指标刷高”,而是“在不确定、变化的负载下稳定地保证用户可感知的服务质量”。这恰恰是系统研究的价值所在。
5.2 我持保留态度的方向与理由
有一类方向我比较谨慎:所有试图从模型侧解决服务问题的方案。比如有一篇论文尝试用“动态提前终止”的方式加速生成——检测到模型已经“确定”答案就不再继续。这个思路在对话场景里很危险,因为用户感知的质量是“流畅自然的完整回答”,草率截断会造成明显的机械感,哪怕文本语义已经完整。
另外部分论文过度依赖特定硬件特性,比如 Hopper 或 Blackwell 架构上的 Tensor Memory Accelerator。这类方向受硬件迭代速度限制,很难在通用集群上快速铺开,且一旦芯片厂商支持不到位,系统论文假设的底层能力就不存在,整套方案就成了空中楼阁。我不是否认这类工作的价值,而是觉得它们应该和硬件路线图并行验证,而不是单独作为系统软件设计的基础。
还有一类是“把调度复杂度大幅提升但收益有限”的方案。调度器若要做全局最优规划,收集全局状态开销很大,计算规划本身又耗时,在请求已到达、延迟压力极高的情况下,复杂调度可能比简单启发式还慢。是否值得,要按具体 workload 分布评估。Session 里有一篇在这种“经验式调度 vs 优化式调度”的对比中做得比较诚实,它们给出的结论是:当请求长度分布方差较大时,优化式调度胜;当方差较小时,两者近乎持平。这才是负责任的研究态度。
写在最后的一点个人体会
Session 结束的时候,我翻了翻笔记,发现写得最满的不是某篇论文的技术细节,而是一个共性的变化:Model Serving 正在从“辅助系统”变成“一等系统”。过去大家把推理服务当成模型的外围配套,能跑就行;现在它有了自己的调度理论、内存管理机制、容错协议和可观测性体系,已经成为一个独立的系统工程分支。
我的实际体会是,批量做训练系统和在线推理系统的人,思维模式非常不一样。训练系统追求的是稳定地把一个大作业跑完,推理系统追求的是在不确定负载下持续兑现 SLO。后者更接近于做数据库或者做操作系统:你面对的不是一个任务,而是一群行为各异的请求;你的目标不是跑得最快,而是可预期、可信赖。Session 1A 的六篇论文,只是这个思路转变的开头。如果要从这些论文里挑出一句话记住,我觉得是“未来的推理服务,比拼的不是模型多强,而是谁能用一半的 GPU 资源,扛住双倍的线上压力,还保证人人都觉得‘很快’”。这才叫 Scale。