大模型推理服务化与连续批处理优化

日期:2026-07-16

一、项目背景

我们当时接手的是一个典型的企业自托管大模型推理场景:业务侧把客服问答、文档摘要、代码辅助等流量都打到了内部 GPU 集群上,模型以 7B/13B 级别的对话模型为主,少量 34B 级别的长文本理解任务。最初我们用单机单卡、一次只处理一个请求的朴素部署方式,问题很快暴露出来。

第一,整体吞吐上不去。一个请求的 decode 阶段 GPU 算力利用率长期在 30% 以下,相当一部分时间花在等待显存搬运和 kernel 启动开销上,大量 SM 处于空闲。第二,长尾请求拖慢整体。少数几百上千 token 的长生成请求占住显存和算力,短请求被迫排队,P99 延迟被严重拉长。第三,GPU 利用率低且分布不均,高峰期卡满、低谷期几乎空转,资源预算却已经花出去了。

我们意识到,问题不在于模型本身,而在于"把 GPU 当成一台慢速 HTTP 服务来用"的部署范式。要真正把一张卡的价值榨出来,必须把推理做一次彻底的服务化改造,引入现代推理框架的连续批处理与分页 KV 缓存机制。这是我们这个项目里最核心的一笔投入。

二、落地场景

我们采用的 X 技术平台在模型服务化层提供了基于 vLLM / TGI 的推理服务化能力,并在算力调度监控层用 Prometheus + Grafana 统一采集吞吐、延迟与利用率。落地时主要覆盖三类场景:

一是高并发短请求场景,例如智能客服的实时问答,单请求生成长度多在 128 token 以内,但并发峰值可达数百;二是长上下文理解场景,如合同与研报的摘要、长文档问答,输入可能达到 8K–32K token,生成也较长;三是混合流量场景,白天以短请求为主、夜间跑批量摘要,对弹性扩缩容提出要求。

技术上我们围绕三个点展开:用张量并行(tensor parallel)把大模型切到多卡,用连续批处理(continuous batching)把到达时间错开的请求动态拼到同一个 batch 里做 decode,用分页注意力(pagedattention)管理 KV 缓存以避免显存碎片化。最终以推理服务化的形态交付到私有云集群和信创环境两套底座上。

三、关键技术挑战与解决思路

挑战一:连续批处理与 KV 缓存碎片化。 朴素静态 batching 必须等一个 batch 内所有请求都生成完才能换下一批,导致短请求被长请求拖死,且每个请求预先分配连续 KV 缓存,长尾请求预留过多显存而浪费。我们的做法是切换到 vLLM 的连续批处理:请求的每一步 decode 都按"当前完成即让出位置"的原则动态组批,并采用 pagedattention 把 KV 缓存切成固定大小的 block 分页管理,像操作系统虚拟内存一样按需分配、共享和回收。实测下来,同等显存下并发上限几乎翻了一倍。

# 连续批处理 + 分页 KV 缓存的启动参数示意
--max-num-seqs 256            # 同时调度的最大序列数
--block-size 16              # 每个 KV cache block 的 token 数
--gpu-memory-utilization 0.90 # 显存占用上限,留一点余量给碎片
--enable-prefix-caching       # 开启前缀缓存,复用 system prompt 的 KV

挑战二:动态批大小与显存管理。 批太大显存溢出、批太小利用率低,且请求长度分布高度倾斜。我们让框架按 --max-num-seqs--max-model-len 联合约束并发上限,再用 --gpu-memory-utilization 把可用显存比例交给框架自适应分配 KV 池;同时通过前缀缓存复用公共 prompt 的 KV,减少重复显存占用。我们还把请求按输入长度做了粗粒度分流:超长输入走专属实例,避免拉低短请求的整体批效率。

案例片段(已脱敏):一次压测中,固定 batch_size=32 的静态方案在混合流量下频繁 OOM;切到连续批处理并把 --gpu-memory-utilization 从 0.85 调到 0.90、--max-num-seqs 设为 256 后,单卡并发从约 90 提升到约 210,长请求不再阻塞短请求,P99 由 4.2s 降至 1.8s。

挑战三:长请求优先级与抢占(preemption)。 当显存不足、新请求又涌入时,框架默认用抢占机制把低优先级请求的 KV 换出到 CPU 再重算,代价是延迟尖刺。我们结合业务语义做了区分:实时客服走高优先级队列、几乎不被抢占;夜间批量摘要允许被抢占以腾出资源。同时把 --max-num-seqs 与排队超时结合,超过阈值的请求直接快速失败并触发网关侧限流与回退,避免雪崩。

四、效果数据

改造在私有云集群(A10/单卡 24G 规格为主)的 13B 模型上完成,以下为脱敏示意值:

指标改造前改造后说明
吞吐(tokens/s,单卡)约 380约 1150连续批处理提升约 3 倍
P99 延迟约 4.2s约 1.8s长尾请求不再阻塞短请求
GPU 利用率(decode 阶段)约 31%约 78%SM 空闲时间大幅下降
单卡并发请求数约 90约 210分页 KV 缓存提升并发上限
长请求抢占重算占比约 3%仅夜间批量为被抢占主体

案例片段(已脱敏):Grafana 监控看板文字摘要——改造后单卡吞吐曲线由改造前的"锯齿状、均值约 380 tokens/s"变为"平稳高位、均值约 1150 tokens/s";GPU 利用率(decode)从长期 31% 提升到 78% 且不再随请求长度剧烈波动;P99 延迟分布从 4.2s 收敛到 1.8s,长尾被显著削平。

五、可复用经验总结

第一,连续批处理是提升自托管推理吞吐的关键杠杆,远比单纯堆卡来得划算;它把"等齐 batch"变成了"来一个塞一个",GPU 几乎不再空转。第二,KV 缓存的页面化管理决定了并发上限,分页注意力 + 前缀缓存能同时改善显存效率和重复计算。第三,显存利用率不要设到 100%,留 5%–10% 给碎片和突发,否则抢占与 OOM 会反复出现。第四,把业务优先级映射到抢占策略,实时流量和批量流量分池部署,比在单实例里调参更省心。第五,网关的限流信号应反向驱动底座弹性扩缩容,形成算力—流量联动闭环,避免高峰期排队、低谷期空转。

回过头看,这个项目最大的收益不是某个参数,而是把"推理即服务"的工程方法论在团队里落地了:可观测、可压测、可弹性。后续我们把这套配置沉淀为模板,新模型上线当天即可复用,交付周期明显缩短。