AI AI infra · 推理侧
书库 第 1 章
AI infra · 推理侧

第 3 章 batching:总吞吐涨了,单条为什么更慢

先备检查:一条 8K 请求的缓存多大?权重多大?A100 的带宽是多少?
先修:第 1–2 章 · 深度:L1 · 预计阅读:25 分钟
一句话:batch 摊薄的是权重读取,不是任何一条请求的等待。

14 条请求,一条一条跑要多久

第 2 章算出来,80GB 卡配 7B、8K,最多并 14 条。假设每条输出 512 token。

一条一条跑:生成一个字要读 13 GiB 权重加 4 GiB 缓存,共 17 GiB,除以 2,039 GB/s 约 8.3 毫秒。512 个字就是 4.3 秒。14 条乘下来 60 秒。

十四条一起跑:权重只读一遍,缓存各读各的,一步读 13 + 56 = 69 GiB,约 34 毫秒,但这一步同时给 14 条各出一个字。

总时间 512 × 34 毫秒 ≈ 17 秒。吞吐从 120 token/s 涨到 411 token/s,三倍半。

单条的出字间隔,从 8.3 毫秒变成 34 毫秒,慢了四倍。

秘密只有一句

每生成一个 token,GPU 都必须把全部权重从显存搬一遍。这个动作躲不掉,但可以共享。

读一次 13 GiB,服务一条请求是浪费,服务十四条就是把成本摊成十四分之一。

batching 不改任何一条请求的计算量。它只是让同一次读取,多喂几条。

把每一步读多少列出来

部分batch 1batch 4batch 14
权重13 GiB13 GiB13 GiB
缓存4 GiB16 GiB56 GiB
每步读取17 GiB29 GiB69 GiB
每步耗时8.3 ms14.2 ms34 ms
单条 TPOT8.3 ms14.2 ms34 ms
总吞吐120 token/s281 token/s411 token/s

看第一行和最后一行。权重不动,吞吐涨;缓存跟着涨,延迟也跟着涨。

batch 从 1 到 4,吞吐涨 2.3 倍;从 4 到 14,只再涨 1.5 倍。加得越多,边际收益越小。

收益停在哪里

两个上限,谁先到谁说话。

容量上限:batch 再加,56 GiB 的缓存就撑爆了。装不下的时候,多出来的请求去排队,或者触发抢占。

收益上限:batch 14 时权重只占每步读取的 19%,已经接近可以忽略。再加 batch,每步耗时几乎按倍数涨,吞吐基本不动,延迟继续涨。这时候 batching 已经没用了,只是在拿延迟换一个不存在的吞吐。

所以 batch 不是越大越好,加到"权重不再是大头"就够。

尾延迟从哪里来

平均值好看,不代表没人难受。

队列里二十条,一次只能跑十四条。剩下六条要等前面跑完,这段等待全算进它们的首字时间。

前面的请求跑得快,第六个等的人可能只多等半秒;前面有两条 4K 输出的,他等三秒。平均值还是 1.2 秒。

压测只报平均延迟,等于把这批人藏起来。P99 才是有人真的在等的证据。

什么时候 batching 不管用

只有一个人在用时,batch=1,没有东西可以摊薄。

prefill 阶段也不怎么吃这套。那是算力瓶颈,拼 batch 只是把更多 token 塞进同一次矩阵乘,收益远小于 decode。

显存已经贴顶时更危险。再拼就是抢占,被扔掉的请求要重算 prefill,代价可能比省下的那点吞吐还大。

经验:先分清是没拼上,还是拼满了

吞吐上不去,先看两个数:running 和 waiting。

running 小、waiting 大,说明容量不够,请求在排队。这时候该省显存:量化、缩短上下文、换 GQA 模型。

running 到顶、GPU 利用率接近 100%,说明带宽或算力吃满了。这时候该换硬件,或者砍负载。

两种情况的解法相反,判断错了就是白花钱。

练习

六道题,先闭卷,再翻 ANSWERS.md。

  1. batch=4 时每步读多少 GiB?TPOT 多少?总吞吐多少?
  2. 为什么 batch 从 1 加到 8,总吞吐涨了,首字延迟却可能更差?
  3. 一条请求的输出从 512 涨到 2K,batch 的收益会变大还是变小?
  4. 找错:"batch 越大,服务越快。"
  5. running 一直很小、waiting 一直在涨,你该先改什么?给出两个方向。
  6. 用 llama.cpp 的 -np 或 vLLM 的并发参数,batch 1、4、8 各压一次,记录吞吐、TPOT、P99。

这一章就记一句

batching 让多条请求共享一次权重读取:权重只读一遍,缓存各读各的。batch 从 1 到 14,吞吐涨三倍半,单条出字间隔慢四倍。收益停在"权重不再是读取大头"那个点。

真只记一句:吞吐和延迟是同一个旋钮的两端,batch 就是那个旋钮;调它之前,先说清你要的是总产能还是单条体感。

下一章解决一个 batching 自己带出来的问题:二十条请求长短不一,谁先跑、谁等着、显存不够时扔掉谁。