27届大模型面试准备(五十四):大模型推理成本与吞吐调优实战——从连续批处理到 PD 分离

📅 2026/8/25 13:30:53
27届大模型面试准备(五十四):大模型推理成本与吞吐调优实战——从连续批处理到 PD 分离
27届大模型面试准备五十四大模型推理成本与吞吐调优实战——从连续批处理到 PD 分离引言为什么能跑和跑得划算是两回事A25 讲过推理服务化的基础组件PagedAttention、连续批处理、投机解码A30 讲过全栈性能优化。但面试官真正想听的不是名词罗列而是给定一块卡、一个 SLA、一个成本上限你怎么把吞吐和延迟同时压到最优。本篇是工程实战深化的第二讲把推理成本拆成算力、显存、带宽三本账给出可落地的调优杠杆并重点讲清近年最关键的架构演进——Prefill 与 Decode 分离PD 分离。读完本篇你应当能对着白板画出请求从进来到出答案的成本曲线并指出每一个拐点对应哪个调优开关。单请求延迟构成自回归解码 Latency Prefill_time Decode_time Prefill_time ≈ (prompt_len img_tokens) × 算力 / 并行度 Decode_time ≈ output_len × (每步耗时) 每步耗时 ≈ max(算力瓶颈, 显存带宽瓶颈) # 解码是 memory-bound一句话点题prefill 是 compute-bound吃算力decode 是 memory-bound吃显存带宽。这两个阶段的天性不同决定了它们不该被同一个调度器用同一种方式对待——这正是 PD 分离的根本动机。第一节 三本账算力、显存、带宽1.1 算力账FLOPs一次前向的算力消耗与 token 数、模型参数量近似成正比。prefill 阶段一次处理整个 prompt算力集中爆发decode 阶段每步只算一个新 token但每个 token 都要读一遍全部权重算力反而不是瓶颈。1.2 显存账KV CacheKV Cache 是显存的主要占用者。粗略公式KV_bytes ≈ batch × seq_len × 2(K,V) × n_layers × d_model × 2(bytes,FP16)举例13B 模型、d_model5120、40 层、FP16单条 4K 长度序列的 KV 约2 × 4096 × 2 × 40 × 5120 × 2 ≈ 5.4 GB。这意味着一块 24GB 的卡光 KV 就吃掉近四分之一剩下要装权重和激活。所以能并发多少请求几乎由 KV Cache 容量决定。1.3 带宽账Decode 的命门decode 每生成一个 token都要把全部权重从显存读到计算单元一次。这个权重大小 ÷ 显存带宽决定了每步的理论下界耗时。因此量化W8A8、W4直接缩小权重体积 → 每步读的字节更少 → decode 更快更大的 batch 把读权重摊到更多 token 上 → 算力利用率更高batch 内并行 decode。成本杠杆对照 账本 主要优化杠杆 作用阶段 算力 prefix cache 命中、投机解码 prefill / decode 显存 PagedAttention、KV 量化、prefix 复用 全程(决定并发数) 带宽 weight 量化、大 batch、PD 分离 decode(主)第二节 连续批处理把等待变成吞吐2.1 静态批处理的浪费早期推理把请求凑成一个固定 batch等最慢的请求生成完才释放整批。结果一个长请求拖住整批短请求空等GPU 利用率低得可怜。这就是静态批处理的 vacancy 问题。2.2 连续批处理continuous batching核心思想不按请求批而按step 里的 token批。每解码一步调度器把所有还在生成的请求的当前 token 聚成一个动态 batch有请求结束了立刻塞进新请求不留空位。这样 GPU 始终满载吞吐可提升数倍。静态批处理: [ReqA ReqB ReqC ReqD] 全部生成完才进下一批 ReqA 早结束 - 空等 - 利用率低 连续批处理: step1: [A_t B_t C_t D_t] step2: [A_t B_t C_t D_t] (D 结束了, 但 slot 立刻被新请求 E 占) step3: [A_t B_t C_t E_t]实现关键在 PagedAttentionA25 详述KV Cache 被切成固定大小的 block像虚拟内存一样按需分配、可按请求拼接从而支持变长、可动态增删的批。没有它连续批处理的碎片问题会拖垮显存。第三节 PD 分离把 prefill 和 decode 拆成两个工厂3.1 为什么要分离prefill 是算力密集型、可大 batch 并行decode 是带宽密集型、必须低延迟响应。把它们塞在同一块卡上会出现prefill 的大 batch 把 decode 的延迟抖上去的互相干扰。PD 分离Prefill-Decode Disaggregation把两类实例分开部署P 实例prefill专吃算力大 batch 处理 prompt 图像 token算完把 KV Cache 传给 D 实例D 实例decode专吃带宽小 batch 低延迟自回归生成从 P 实例接收已算好的 KV 起步。传统合设(混部): [Req] - [同卡: prefill decode 抢资源] - 延迟互相干扰 PD 分离: [Req] - [P 实例: 大batch prefill] --KV 传输-- [D 实例: 低延迟 decode] - answer3.2 KV 传输是分离的代价PD 分离引入了KV 在 P、D 之间传输的新开销。若 P、D 不在同一节点要走网络NVLink/IB/RDMAKV 体积可能高达数 GB长上下文。工程上常用KV 传输压缩 流水线 overlap来掩盖P 实例算完一段 KV 就流式发给 DD 边收边开始 decode不等全量到齐。3.3 分离带来的调度自由度分离后P 和 D 可以独立扩缩容对话类流量 decode 占比高就多扩 D摘要类流量 prefill 占比高就多扩 P。还能做prefill 队列削峰——把突发的大 prompt 在 P 集群排队消化不影响在线 decode 的尾延迟。这正是大规模服务里 PD 分离越来越成为标配的原因。维度合设混部PD 分离资源干扰强prefill 抖 decode弱各管各的扩缩容灵活性低绑定高P/D 独立尾延迟稳定性中高系统复杂度低中多 KV 传输适用规模中小流量大流量/高低峰差异大第四节 量化对成本的杠杆不止是省显存4.1 W8A8 与 W4 的取舍权重量化A19 详述 GPTQ/AWQ在 serving 里最直接的好处是每步读的字节变少。W8A8 几乎无损、decode 提速明显W4如 GPTQ/FP4提速更猛但可能掉点需要校准。对成本敏感、且任务容错度高的场景摘要、分类、草稿生成W4 很划算对精度敏感的生成任务优先 W8A8。4.2 KV Cache 量化常被忽视KV Cache 量化如 INT8/FP8 存 KV能直接放大可并发序列数因为它压的是显存账里最大的一块。很多团队只量化权重忘了量化 KV等于只做了一半。在长上下文场景KV 量化带来的并发提升往往比权重量化更显著。# KV Cache 量化示意存储时用低精度计算时反量化classKVCacheQuant:def__init__(self,bits8):self.scaleNonedefquantize(self,kv_fp16):# 按 token 维度做 per-token 对称量化amaxkv_fp16.abs().amax(dim-1,keepdimTrue)scaleamax/(2**(self.bits-1)-1)kv_q(kv_fp16/scale).round().clamp(-127,127).to(torch.int8)returnkv_q,scale# 存 int8, 省一半显存defdequantize(self,kv_q,scale):returnkv_q.float()*scale# 计算前还原第五节 容量压测与 SLA 设计调优要打到靶上5.1 先定义好的标准调优前必须先定 SLATTFT首 token 延迟对应 prefill、TPOT每输出 token 延迟对应 decode、端到端延迟、以及可接受的 P99。没有 SLA 的压测是盲目的。5.2 阶梯加压找拐点从单并发开始逐步加压记录吞吐与 P99 延迟曲线找到延迟开始陡增的并发数——那就是该配置的真实容量。超过拐点后应当触发限流或排队而不是硬扛硬扛只会让所有请求都慢。加压阶段观察到的现象对应调优动作低并发延迟低、GPU 利用率不足提高 max_batch榨算力中并发吞吐上升、延迟平稳健康区维持拐点附近P99 陡增限流/排队或加 D 实例过载OOM / 超时雪崩KV 量化、PD 分离、降级5.3 成本换算成钱最终要把每千次请求成本算出来显存占用决定需要的卡数吞吐决定单位时间能服务的请求数二者相除即单请求成本。面试官常问怎么把推理成本降一半标准答案不是某个银弹而是量化压权重KV量化压显存PD分离稳延迟连续批处理提利用率的组合拳并量化每一步的收益。第六节 一次真实调优复盘把前面所有杠杆串起来光讲杠杆容易面试里真正加分的是给你一个现场你怎么排。下面用一段工程复盘把全篇串起来你可以直接当作案例讲。背景某在线问答服务单卡 A100 80G 部署 13B 模型SLA 要求 TTFTP2s、TPOTP80ms目标把单请求成本压到原来的 60%。初始配置是合设 FP16 静态批处理实测单卡 QPS 仅 2.1且 P99 TPOT 经常突破 200ms。第一步定位瓶颈。打 tracing 发现 decode 阶段每步耗时稳定在 ~70ms且 GPU 显存带宽利用率接近打满、算力利用率仅 35%。结论decode 是 memory-bound且静态批处理让 GPU 大量时间空等——两本账同时出问题。第二步上连续批处理 PagedAttention。把静态批改成连续批max_batch 调到 32。结果 QPS 直接到 5.8TPOT P99 降到 95ms。这一步几乎零精度代价收益最大。第三步权重 W8A8 量化。decode 仍是带宽瓶颈量化把每步读的权重减半TPOT P99 降到 62msQPS 到 7.4。精度评测掉分在 0.5% 以内业务可接受。第四步KV Cache INT8 量化。长上下文请求占比高KV 是显存大头。量化 KV 后单卡可并发序列数从 18 提到 34QPS 到 9.1且 OOM 不再发生。第五步PD 分离削峰。上线后观测到摘要类长 prompt会周期性把在线对话的 TTFT 抖高。把 prefill 拆到独立 P 集群、KV 走 NVLink 流式传输在线对话 TTFT P99 从 1.8s 稳到 1.2s且不再受批量摘要任务干扰。最终QPS 从 2.1 提升到 9.1约 4.3 倍单请求成本降到约 23%远低于 60% 目标全部 SLA 达标。复盘结论调优不是都上了就好而是按瓶颈账→杠杆→验证的顺序逐层打每一步都有可观测的收益归属。调优路径实际生效顺序 静态批FP16 ──①连续批PagedAttention── QPS 2.1→5.8, TPOT 200→95ms ──②W8A8 权重量化────────── TPOT 95→62ms, QPS→7.4 ──③KV INT8 量化─────────── 并发 18→34, QPS→9.1, 无OOM ──④PD 分离削峰─────────── TTFT P99 1.8→1.2s, 稳定这个案例的面试价值在于它展示了先量后调、按账归因、逐步验证的工程方法论而不是堆名词。面试官听到我先打 tracing 看是算力还是带宽瓶颈再决定上哪招印象会明显不同。第七节 排障延迟突增的三条主线其一TTFT 变长先看 prefill 是否被大图/长 prompt 拖住检查 prefix cache 命中率若命中率低多半是 system prompt 被改或缓存键漂移。其二TPOT 变长生成变慢decode 是带宽瓶颈检查是否 batch 过大导致每步排队、或权重量化没生效也可看是否误用了高精度。其三吞吐上不去但 GPU 不满典型等数据——KV 传输PD 分离或 RPC 序列化成了瓶颈或连续批处理的调度有锁竞争。定位要靠端到端 tracing而不是猜。第八节 五个常见调优误区误区一只量化权重忘了 KV。很多团队把 W8A8 当作降本全部但长上下文场景下 KV Cache 才是显存主占不量化 KV 等于只做了一半并发上不去、成本降不下来。误区二把连续批处理当成银弹。连续批能提吞吐但它不解决prefill 抖 decode的延迟干扰也不解决带宽瓶颈。重载场景里光有连续批、不配合 PD 分离和量化尾延迟照样崩。误区三盲目堆 max_batch。batch 不是越大越好。超过拐点后每步排队时间超过并行收益TPOT 反而上升且显存压力陡增易 OOM。正确做法是用阶梯压测找到拐点再留 20% 余量。误区四用平均延迟代替 P99 定 SLA。平均好看、长尾崩溃是 serving 最常见的假健康。面试官最爱追问你的 P99 是多少务必把尾延迟当一等公民。误区五调优不量化收益。每上一招就该记录 QPS、TPOT P99、成本的变化否则无法判断这招值不值。复盘里那种逐层打靶点的思路比一次性全上更显专业。面试速答本篇可直接背的 3 句prefill 是 compute-bound、decode 是 memory-bound二者天性不同这是 PD 分离和所有批处理优化的根本出发点。连续批处理按每步 token而非整个请求组批配合 PagedAttention 消除碎片是吞吐翻倍的基石。成本三本账算力prefix/投机、显存PagedAttention/KV量化/复用、带宽权重量化/大batch/PD分离调优要按 SLA 的 TTFT/TPOT 拐点打靶不是盲目堆配置。高频追问清单为什么 decode 阶段量化权重能加速而 prefill 阶段主要看算力请用带宽瓶颈解释。PD 分离后KV 在 P、D 之间怎么传同节点和跨节点分别用什么连续批处理下一个超长请求会不会饿死短请求怎么做公平调度KV Cache 量化掉点比权重量化更敏感还是更不敏感为什么如果 SLA 要求 P99 TPOT 50ms你会先调哪个参数给出排查顺序。混合精度部分层 FP8、部分 FP16在 serving 里怎么落地风险在哪