【infra之路】vLLM之Continuous Batching
continuous batching——和 PagedAttention 并称 vLLM 两大法宝。你其实已经摸到门口了之前测 batch 吞吐时,你做的就是批处理,但那是静态的;continuous batching 是动态的。理解两者的差别,就懂了 vLLM 高吞吐的另一半来源。先回到问题——静态批处理(你之前做的那种)在真实场景下浪费在哪。问题:静态批处理的等齐浪费回忆你测 batch 那个实验:你把 16 个请求凑成一批,一起开始、一起跑完。这在实验里没问题,因为所有请求都是同时给的、生成同样长度。但真实的推理服务完全不是这样:请求是陆续来的——用户们在不同时刻发请求,不会刚好同时到。每个请求生成的长度差异巨大——有人问句话答 20 token,有人让写文章答 800 token。静态批处理(传统框架的做法)在这种现实下有两个严重浪费:浪费一:等齐才开始。凑一批要等够数量。先到的请求得干等后面的请求凑齐了才能一起开始——前面的人白白等待,延迟变高。浪费二:等慢的才结束(最致命)。一批一起跑,但有的请求 20 token 就答完了,有的要 800 token。静态批处理必须等整批里最慢的那个跑完,才能释放这批、开始下一批。于是那个答 20 token 的请求,早早就完成了,却要陪着那个答 800 token 的一直占着位置空转到最后。GPU 的算力和显存,都被这些已完成却走不了的请求白白占着。打个比方:静态批处理像拼车非要坐满、且所有人到终点才让下车——先上车的等坐满才发车,先到站的也不能下,必须等最后一个人到了目的地,全车才一起清空。极度浪费座位。方案:continuous batching —— 动态进出continuous batching(连续批处理,也叫 in-flight batching)的思路:不要批的概念了,改成一个动态的、随时进出的池子。核心机制:vLLM 的调度器在每一步生成(每生成一个 token 的迭代)都重新审视这个池子——谁完成了,立刻踢出去、释放它的位置(和 KV cache 块)。那个答完 20 token 的请求一结束,马上离开,不用陪跑。有空位了,立刻把排队的新请求塞进来。池子里腾出位置,等待的新请求马上加入,一起参与接下来的生成。也就是说,这个批是时刻变化的:每一步都可能有请求离开、有请求加入,GPU始终保持满载,不会有已完成却占着位置或等齐才开工的浪费。回到拼车比方:continuous batching 像网约车随上随下——有人到站立刻下车空出座位,路边等车的立刻上来补位,车子始终坐满高效运转,没人陪跑、没人空等。为什么这是 vLLM 高吞吐的关键把两个浪费都消除了:没有等齐才开始(新请求随时加入),没有等最慢的才结束(完成的立刻释放)。GPU 的利用率被拉满——还记得你测 batch 时看到的吗?GPU 喂得越满,吞吐越高。continuous batching 就是想方设法让 GPU每一刻都被喂满,而不是像静态批处理那样大量时间在等。两大法宝是怎么配合的(关键)这里有个精妙之处,把 PagedAttention 和 continuous batching 串起来了——continuous batching 能这么灵活地随时进出,恰恰依赖 PagedAttention。为什么?因为请求要能随时加入、随时释放,它的 KV cache 显存就必须能灵活地、按需地、非连续地分配和回收。如果还是静态批处理那种预留连续大块的方式,一个请求走了留下一个特定大小的连续空洞,新请求未必塞得进去(又是外部碎片问题)。而 PagedAttention 把 KV cache 切成了统一的小块、按需分配回收——请求一结束,它的块立刻释放进池子,新请求随时能凑块加入。PagedAttention 提供了灵活的显存管理,continuous batching 才能实现灵活的请求调度。两者是配套的。这就是为什么 vLLM 的两大法宝总是一起出现——一个管显存怎么高效分配(PagedAttention),一个管请求怎么高效调度(continuous batching),后者建立在前者之上。vLLM 的两大法宝你现在都拿下了而且最关键的是你理解了它俩怎么配合——这是很多人答不全的点。多数人能说出PagedAttention 管 KV cache、continuous batching 提吞吐但说不清两者的依赖关系。你现在能讲调度的灵活性建立在显存管理的灵活性之上——PagedAttention 把显存变得能灵活分配回收continuous batching 才能让请求灵活进出。这一层把两个法宝串成了一个有机整体面试讲出来很有深度。把推理线的理论脉络收一下你会看到它们是层层咬合的KV cache(模块一推理为什么吃显存)→PagedAttention(怎么高效管这块显存)→continuous batching(在高效显存管理之上怎么高效调度请求)→ 都指向同一个目标:把 GPU 喂满、把显存用尽换取最大吞吐。而这又接回阶段二那条总主线——“瓶颈在数据/资源的管理不在算力”。你这一路的知识是真的在复利。