先记住这个答案
prefill阶段对输入序列做并行矩阵乘法,计算量大,算力容易饱和,是compute-bound;decode阶段每次只算一个新token,但权重和KV cache的搬运量远大于有效计算,受限于HBM带宽,是memory-bound。混合运行时,长输入prefill会抢占算力,使decode短请求的每token延迟抖动。分离部署让prefill实例选用高算力卡、decode实例选用高带宽卡,并按各自负载弹性伸缩,通常在高并发且输入长度差异大的场景收益明显。
- prefill算力饱和,decode带宽饱和,不可用同一吞吐指标
- 分离部署需权衡KV cache传输开销与阻塞缓解收益
- 输入长度差异大且并发适中时,分离收益最明显
机制:算力密集与带宽密集的由来
prefill阶段对prompt中的每个token并行计算,自注意力和MLP全部展开成大体量矩阵乘法,输入token越多,权重复用次数越高,单位权重流经时算出的FLOPs也随之增加。以7B模型为例,处理2000 token时矩阵乘规模远大于权重一次性搬运量,所以现代GPU的峰值算力首先成为天花板。
decode阶段每轮只生成一个token,每层的矩阵操作退化为向量乘,计算量约2倍参数量,但必须把权重和对应的KV cache从HBM读到片上寄存器。实际每次读取的权重就有约14GB(以7B模型fp16计),加上KV cache后数据量远超有效计算量,算术强度低于1,执行时间完全取决于显存带宽,GPU算力大量空闲。
场景:8卡混合队列尾延迟失控
假设一台8卡A100(单卡312 TFLOPS,带宽2 TB/s)服务7B模型,批大小为24,其中2个请求输入2000 token,22个请求输入100 token。若混在一个动态批里,长prefill会优先占用算力,时间片可达数十毫秒,期间decode请求的每个token都被阻塞,原本几毫秒的步骤被拉成几百毫秒,P99尾延迟直接冲出SLO。
改为分离部署:将其中2张卡专门跑prefill,将生成的KV cache经CPU内存发送给其余6张卡做decode。短请求在decode池内连续调度,不再受长输入拖累,整体吞吐反而提升。此时多付出约几十毫秒的cache传输代价,但换来尾延迟稳定,对输入长度差异大且长请求占比不超负荷的场景是净收益。
失效边界:何时不应分离
当请求输入普遍很短(几十token)、并发波动又大时,短prefill本身不足以长时间霸占算力,分离带来的额外实例和KV cache传输开销往往得不偿失。此时单池并用分块prefill可能更简单,因为短prefill不会造成长时间阻塞。
另一个失败场景是prefill队列拥塞而decode空闲,由于实例无法互相借用算力,造成资源漏斗。此时需要给prefill实例设置并发上限或引入分块prefill提前释放部分token,否则分离部署后整体延迟反而高于混合方案,需谨慎设计请求路由和队列策略。
容易答错的地方
- 把decode也当作算力瓶颈
- 有人误以为decode也是计算密集,因而给decode实例也配高算力低带宽卡。实际decode执行时间主要被显存带宽限制,算力闲置不产生收益,高带宽中等算力卡(如L40S)往往更划算。
- 认为分离部署一定更好
- KV cache传递需要额外网络和访存,输入短或请求稀疏时,传输延迟可能超过阻塞节省的时间。判断应基于实际负载中prefill与decode的算力比和传输比,不能无条件套用分离架构。
面试官还会怎么问?
如何判断一个请求是prefill主导还是decode主导?
以算术强度为指标:若输入token数远大于生成token数,prefill耗时占主导;反之更倾向decode延迟。实际操作中用arith强度计算当批的FLOPs/字节,若低于某阈值则属带宽敏感。
分离部署时KV cache如何高效传输?
一般通过高速NVLink或RDMA将张量直接从一个GPU拷贝到另一个GPU的显存,需要统一寻址或分块传输。传输带宽远低于板内HBM,所以只适合KV cache较小(如上下文长度在几百token级别)的情况,对超长上下文需压缩或重计算。
分块prefill与分离部署是互斥的吗?
不互斥。分块prefill是把长prefill切成小片插入decode批次中,避免整块占住GPU;分离部署则是物理隔离两类负载。两者可配合,当prefill实例拥塞时,可把长输入分发到少量实例并切块,再让decode实例稀疏取cache。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。