日期:2026-08-21
我们这套大模型推理服务刚上线时,显存利用率和尾延迟像跷跷板两头跑。请求是零散进来的,高峰期一拥而上,批次太小显存喂不饱,吞吐量上不去;为了提吞吐我们拉长批处理窗口,结果长尾请求在队列里多等几百毫秒,P99 直接飙到三四秒,线上业务投诉"偶尔特别慢"。调了快两周,要么吞吐差,要么尾延迟炸,始终找不到平衡点。问题出在我们把"批处理窗口"当成一个静态参数去拍,而不是当成跟着负载动态变的开关。
我们落地的方案是让批处理窗口随负载自适应,同时用双约束把尾延迟收住。具体四块。一是动态批处理窗口,系统按当前请求到达速率和排队深度动态决定等待时长,忙时短等快发、闲时稍等长凑批。二是最大批尺寸限流,不管窗口等多久,批尺寸到上限立刻发射,防止一个慢窗口把显存和延迟同时拖爆。三是长尾请求打标,对已经在队列里等待超过阈值的请求打标,优先排入下一批并优先排空。四是尾延迟监控看板,P99、P999 和批尺寸分布同屏,方便我们判断是窗口问题还是后端问题。
动态窗口最难的不是算法,是"等多久"的阈值怎么定。我们第一版用固定等待二十毫秒,结果发现闲时二十毫秒能凑出大批次,忙时二十毫秒里只来两三个请求,批次小吞吐照样差。改成"目标批尺寸加最大等待"双目标后,系统优先凑到目标批尺寸,等不到才到时间发射,闲忙都能自适应。最大批尺寸我们起初设得偏高,想着尽量喂饱显存,结果某次突发大请求把批尺寸堆到上限,单批计算时间拉长,队列里其他请求全被拖成尾延迟,P99 反而更高。把上限下调约三成后,批计算时间可控,尾延迟才真正收敛。
长尾打标这块有个细节:打标太早会把所有请求都标成"优先",等于没打标。我们把阈值设成"等待时间超过当前 P50 的两倍",只对真正排得久的请求打标,优先排空才有效。上线后我们观察到一个反直觉的现象,加了优先排空,平均吞吐几乎没降,但 P99 掉了快一半,说明之前的长尾主要是少数请求在队列里被反复延后,而不是整体算力不够。
方案稳定后,平均吞吐按 tokens 每秒算,相比固定窗口最优配置提升约三成。P99 尾延迟从最高约 3.8 秒降到约 1.1 秒,P999 从约 6 秒降到约 2 秒以内。显存利用率在高峰批次下保持在约八成,没有因为限流被浪费。批处理命中率(达到目标批尺寸才发射的比例)在忙时约九成,闲时约六成,整体符合预期。长尾请求优先排空后,排队超过一秒的请求占比从约百分之四降到约百分之零点六。
案例片段(已脱敏): 推理侧配置:dynamic_batch.target_size = 32,max_wait_ms = 20,hard_cap = 48,tail_mark_ratio = 2.0(等待超 P50 两倍打标)。某分钟到达速率 1800 req/s,窗口在 12 至 20ms 间波动,平均批尺寸 34,命中目标批尺寸比例 0.91。监控记录:该分钟内打标请求 41 个,全部排入下一发射批且优先计算,其 P99 等待 0.9s,未打标请求 P99 等待 1.2s,整体 P99 1.05s。
监控看板这块我们花了不少功夫,因为调窗口最怕"黑盒调参"。我们把批尺寸分布、等待时间分布、P99 与 P999、显存占用四张图同屏,每次改参数都能立刻看到尾延迟和吞吐怎么动,避免了凭感觉拍。印象深的一次线上抖动:某天 P99 突然从 1.1 秒跳到 2.5 秒,我们第一反应是窗口配置被改了,看板一拉发现批尺寸分布没变,但单批计算时间变长,顺着查是某个新上线的模型在同样的批尺寸下计算更重,把批尺寸上限临时下调后尾延迟收回。这个排查如果没看板,可能要翻半天日志。还有个经验是闲时别为了凑批硬等,我们设了最大等待二十毫秒,闲时等不到目标批尺寸也发射,吞吐略降但尾延迟稳,这个取舍对用户体验更友好,也比追求极致吞吐实在。
还有一点容易被忽视,批处理窗口和模型本身的算力特性强相关。我们后来给不同模型打了"批友好度"标签,有的模型批尺寸上去吞吐线性涨,有的模型批大了反而因为显存带宽瓶颈吞吐不增反降。标签打上之后,窗口策略按模型分别配置而不是全局一套,批友好度低的模型用更小的硬上限,避免为了凑批反而拖累它自己。这个细分让我们在整体尾延迟不退化的情况下,把集群总吞吐又往上顶了一截。回过头看,批处理调优没有银弹,得结合负载形态、模型特性和硬件瓶颈三件事一起看,单看一个维度永远调不平。
批处理窗口调优,我现在的结论是别把它当静态参数,负载本身在变,窗口就得跟着变,固定值永远顾此失彼。双约束比单约束稳得多,目标批尺寸管吞吐、最大批尺寸管安全边界,两者缺一都会出问题,我们上限设高那次就是典型的"为了吞吐牺牲边界"翻车。长尾打标这个手段性价比很高,但它的前提是阈值要卡准,打太早等于没打。我们当时纠结过要不要直接上更复杂的连续批处理(continuous batching),后来评估发现现有框架改造代价大,先用动态窗口加打标顶住了,说明很多时候先把简单杠杆拉满,比急着上重方案更划算。