一台GPU推理服务器面对的往往不是一个请求,而是同时到达的大量用户请求。对于传统图像分类、目标检测等任务,批处理比较容易理解:把多个输入组成一个batch,一次送入神经网络,让GPU的大量计算单元同时工作。但到了大语言模型推理阶段,情况完全不同。每个用户的输入长度不同,生成速度不同,结束时间也不同,而且每个请求都要维护自己的KV Cache。此时,把几个请求简单拼成一个固定大小的batch并不能解决问题,现代LLM推理系统真正关心的是如何让GPU在不同请求不断进入、生成、结束的过程中持续保持较高计算密度,同时又不让单个请求因为等待批次而产生过高延迟。
GPU批处理首先解决的是计算资源利用率问题。现代GPU拥有大量CUDA核心、Tensor Core以及巨大的显存带宽,如果一次只处理一个很小的请求,实际计算规模可能不足以让这些硬件资源充分工作。尤其在大语言模型Decode阶段,每生成一个token都需要进行一轮模型计算。单个请求的每一步计算规模相对有限,而多个请求同时处于生成阶段时,可以把它们组织起来进行批量矩阵运算,使同一套模型计算单元同时服务多个sequence。
但这里不能把批处理理解成“10个请求原来需要100毫秒,现在合并以后只需要10毫秒”。这不是GPU推理的实际工作方式。GPU可以并行执行大量线程,但10个请求并不意味着总计算量凭空减少。批处理主要提高的是硬件利用率和单位时间完成的请求或token数量,而不是把10份工作简单压缩成原来的十分之一。实际吞吐量取决于模型规模、输入输出长度、GPU计算能力、显存带宽、KV Cache容量以及推理框架的调度方式。
对于大语言模型,还必须把Prefill和Decode分开理解。Prefill阶段处理用户输入的prompt,需要一次性计算大量token,并建立对应的KV Cache。这一阶段矩阵计算规模较大,更容易把GPU计算能力充分利用起来。Decode阶段则是一轮一轮生成新token,每一步通常只针对当前生成位置进行计算,同时读取此前保存的KV Cache。Decode更容易受到显存带宽、KV Cache访问以及请求数量的影响。
这也是为什么LLM推理中的“批处理”比传统机器学习推理复杂得多。假设服务器同时有20个用户,其中有些请求刚刚进入Prefill阶段,有些已经生成几十个token,有些已经生成几百个token,还有几个请求即将结束。如果采用传统固定batch,系统可能必须等待一整批请求准备完成,然后一起执行;其中某些请求已经结束,其他请求却还没有完成,就会产生大量GPU计算资源浪费。
Dynamic batching试图解决这个问题。系统根据短时间窗口内到达的请求动态组成batch,而不是要求请求数量始终固定。例如服务器在几十毫秒级别的调度窗口内收集多个请求,然后一起执行。这样能够减少单请求执行造成的GPU空闲,但也引入了一个直接的代价:为了等待其他请求加入batch,先到达的请求必须多等一段时间。因此batching本质上一直在处理吞吐量和延迟之间的矛盾。
现代LLM推理系统进一步采用Continuous Batching,也就是连续批处理。它与传统意义上的“每批请求同时开始、同时结束”完全不同。一个请求生成完毕以后可以立即退出当前batch,同时新的请求可以被调度进来。GPU执行的是一个不断变化的请求集合,而不是一个固定不变的batch。
Continuous Batching的价值就在这里。假设GPU当前正在处理32个请求,其中一个请求已经生成结束,传统固定batch可能需要等待其他请求完成才能重新组成下一批,而连续批处理可以直接释放该请求占用的KV Cache资源,并把等待队列中的新请求加入调度。这样GPU可以在请求不断进入和退出的情况下保持较高的工作密度。
这也是现代推理框架设计中调度器的重要性越来越高的原因。GPU并不是自己决定“下一批处理谁”。服务器需要在CPU侧维护请求队列、token预算、KV Cache使用情况、请求优先级、最大并发数以及不同阶段的执行状态,然后决定下一轮GPU计算应该安排哪些sequence。
对于专业部署,batch size也不是越大越好。batch增大通常可以提高吞吐量,但每增加一个活跃请求,就可能增加KV Cache的显存占用。如果GPU显存已经被模型权重、KV Cache、CUDA runtime、临时workspace以及其他运行时数据占满,继续增加batch就可能导致OOM,或者迫使系统降低并发能力。
KV Cache是LLM高并发推理中最关键的显存资源之一。模型权重通常在模型加载完成以后长期驻留在GPU显存中,不会因为来了一个新的用户请求就重新从SSD读取一遍。每个请求则拥有自己的上下文状态,Transformer注意力层在推理过程中产生的Key和Value需要保存下来,后续生成token时继续使用。因此,并发请求越多、上下文越长,KV Cache占用的显存就越大。
KV Cache通常可以近似按照模型层数、KV heads、head dimension、缓存数据类型以及token数量计算。一个请求有10万token,并不意味着系统只需要给模型准备10万个token的输入空间;如果同时有多个长上下文请求,KV Cache会按照活跃sequence分别增长。于是,大模型推理的并发上限经常不是单纯由“GPU有多少Tensor Core”决定,而是受到显存容量和KV Cache管理能力的直接限制。
这也是PagedAttention等技术出现的重要原因。传统连续内存管理容易出现显存碎片,而且不同请求的KV Cache增长速度不同,很难提前准确分配一块完整的连续空间。分页式KV Cache管理则把缓存划分成较小的block,由调度系统动态分配和回收,从而提高显存利用率。像vLLM这类推理系统采用这种思路,使高并发长上下文推理更加容易管理。
这里还需要纠正一个经常出现的说法:批处理并不是让多个请求“共享activation”。每个请求的输入、隐藏状态和KV Cache具有自己的语义状态,不能因为进入同一个batch就随意共享。能够被所有请求共同复用的是已经驻留GPU显存中的模型权重,以及某些框架级别可以利用的共享资源。批处理的主要收益来自把多个请求的计算组织成更适合GPU执行的大型矩阵运算,而不是把不同用户的数据简单合并成一份中间结果。
对于高并发推理,显存带宽同样重要。Decode阶段每生成一个token,都需要读取大量模型权重以及对应的KV Cache。如果GPU计算单元等待数据,继续增加Tensor Core数量也未必能带来相同比例的吞吐提升。因此,大模型推理经常呈现明显的memory-bound特征。不同GPU之间的差异不仅在于FP16、BF16或FP8的理论计算能力,也在于HBM容量、HBM带宽、缓存层次结构以及互联能力。
量化可以进一步改变这个平衡。FP16或者BF16模型转换为INT8、FP8甚至更低精度以后,模型权重占用的显存减少,显存读取的数据量也可能降低,从而允许更大的batch或者更高并发。但量化并不等于“计算速度一定翻倍”。实际性能取决于GPU是否具有对应低精度Tensor Core路径、推理框架是否能够有效使用该数据类型,以及量化格式、kernel实现和模型结构是否匹配。
对于多GPU推理,还需要区分GPU内部批处理和GPU之间的模型并行。一个超大模型可能无法放进单张GPU,于是需要Tensor Parallel、Pipeline Parallel或者其他分布式策略,把模型计算分布到多个GPU。此时NVLink、NVSwitch、PCIe以及网络互联就开始影响整体性能。GPU之间需要交换激活值、部分计算结果或者其他状态,互联带宽和延迟可能成为新的瓶颈。
但不能简单地说“使用NVLink就能提高GPU批处理效率”。如果模型可以完整放进单张GPU,系统瓶颈又在HBM带宽或者KV Cache管理,那么增加NVLink并不会自动改善性能。NVLink主要解决的是GPU之间的数据交换问题。多GPU推理真正需要观察的是通信量、通信频率、GPU拓扑、NCCL通信效率以及计算和通信是否能够重叠。
网络也会影响高并发推理,但它通常不是每一次GPU计算的直接瓶颈。请求首先通过负载均衡器或者API Gateway进入推理服务,然后经过tokenization、请求排队、调度,再进入GPU。对于分布式推理集群,网络可能成为GPU之间或者服务器之间通信的瓶颈;对于单机单GPU推理,真正需要优先分析的往往是GPU计算、HBM带宽、显存容量和KV Cache,而不是NVMe SSD的IOPS。
模型文件加载到GPU同样容易被误解。模型通常在服务启动阶段从本地SSD、网络存储或者容器镜像读取,然后经过CPU内存和数据解析,再传输到GPU显存。这个过程主要影响服务启动和模型切换时间。模型一旦常驻GPU,正常推理请求并不会因为每来一个用户就重新读取175B参数模型。因此,不能把“每秒1000个请求”和“SSD必须每秒读取1000份模型”联系起来。真正随并发增长的是请求状态、KV Cache以及推理计算量。
高并发服务器还必须处理请求长度差异带来的“长度不均衡”。如果一个batch中有的请求只有几十个输入token,而另一个请求拥有几万token,那么简单的固定batch可能造成调度效率下降。不同框架会通过continuous batching、chunked prefill、token budget以及调度优先级等机制进行控制。Chunked Prefill尤其适合避免一个超长prompt长期占据GPU计算资源,使已经进入Decode阶段的请求出现明显的inter-token latency上升。
因此,衡量一个AI推理服务器是否高效,不能只看GPU utilization一个百分比。GPU利用率很高并不一定意味着用户体验好。如果调度器为了追求吞吐量不断扩大batch,可能导致请求排队时间增加;反过来,如果过度追求低延迟,把batch压得很小,GPU又可能无法形成足够大的计算规模。
实际生产系统通常同时观察Time to First Token,也就是TTFT,Inter-Token Latency,也就是ITL或生成阶段的token间隔,以及tokens per second、requests per second、队列等待时间、GPU利用率、HBM带宽利用率、显存使用量和KV Cache使用量。对于在线服务,P95和P99延迟往往比平均延迟更有价值,因为真正影响用户体验的通常是尾部请求,而不是那个“平均表现很好”的请求。
这也解释了为什么一个GPU服务器在实验室里跑单请求时可能非常快,到了生产环境反而表现不同。单请求测试通常能够获得较低的TTFT和较高的单请求生成速度,但并不能说明它能够同时服务几百个用户。随着并发增加,KV Cache开始占用大量显存,调度器开始扩大batch,Prefill和Decode之间产生竞争,显存带宽逐渐成为瓶颈,最终吞吐量可能进入平台期,而延迟继续上升。
反过来,追求极限吞吐也不能无限增加batch。当GPU已经接近计算或显存带宽上限以后,继续增加请求只会增加排队时间。如果KV Cache接近显存容量,系统甚至可能因为缺少可分配缓存空间而拒绝新请求或者降低并发。因此,生产环境通常需要设置最大并发数、最大上下文长度、最大batch token数以及调度策略,而不是简单规定“batch size=64”。
AI推理服务器的性能,本质上是一个调度问题、内存问题和计算问题共同作用的结果。GPU批处理解决的是把多个独立请求组织成更适合GPU并行执行的计算工作,使昂贵的GPU计算资源和显存带宽得到更充分利用;Continuous Batching进一步解决请求不断进入和结束以后,固定batch产生的等待和GPU空洞问题;Paged KV Cache则解决高并发长上下文情况下显存分配和碎片化问题。三者并不是同一个概念,却共同构成现代LLM推理服务的重要基础。
对于实际部署,最有效的优化路径也不是简单地“买一张更大的GPU”。应该先判断瓶颈到底位于哪里:如果GPU计算单元利用率低,需要看batch和kernel执行;如果HBM带宽接近极限,需要分析模型权重和KV Cache读取;如果显存快耗尽,需要检查KV Cache、上下文长度和并发;如果TTFT很高,需要分析Prefill和排队;如果ITL明显变差,需要检查Decode调度和GPU资源竞争;如果多GPU扩展后吞吐提升很小,则应该进一步检查PCIe、NVLink、NVSwitch以及NCCL通信。
GPU批处理真正解决的,从来不是一个简单的“把多个请求放进一个数组”问题。它解决的是如何把具有不同到达时间、不同输入长度、不同生成长度和不同显存需求的任务,持续组织成GPU能够高效执行的工作流。对于传统深度学习推理,这个问题已经重要;对于今天的大语言模型服务,它几乎已经成为整个推理系统设计的核心。最终决定一台AI服务器能服务多少用户的,不只是GPU型号,而是模型大小、精度、KV Cache、批处理策略、调度算法、显存带宽以及请求延迟目标之间能否形成合理的平衡。
AI 推理服务器如何同时处理大量请求,GPU 批处理机制到底解决了什么问题
喜欢这篇报道?
使用下面的功能,方便以后继续阅读和分享 MNewsTV
关于文章收藏
收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。
删除收藏请进入「我的收藏」进行管理。
捐助(Paypal): https://www.paypal.me/observeccp 订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP