在高吞吐 LLM 推理场景中,当单请求压力达到 3000 tokens/s 时,调度层的设计直接决定了系统能否在延迟敏感型应用与成本优化之间取得平衡。本文从 Prefill-Decode 两阶段特性出发,探讨连续批处理(Continuous Batching)与动态抢占调度的工程化实现,并给出可直接落地的参数配置与监控要点。
一、Prefill 与 Decode 的资源竞争本质
LLM 推理请求包含两个截然不同的计算阶段。Prefill 阶段需要并行处理整个输入 prompt,属于计算密集型操作;Decode 阶段则逐个生成输出 token,受限于内存带宽而非算力。这种本质差异导致两者在资源需求上存在根本性冲突:Prefill 需要大量算力但内存占用相对可控,Decode 则需要频繁访问 KV Cache 但计算密度低。
在 3k tokens/s 的压力下,这种冲突被放大。当系统选择优先处理新到达请求的 Prefill 时,正在 Decode 的现有请求会遭遇「生成停顿」(Generation Stall)—— 即由于 Prefill 占用了 GPU 计算资源,Decode 被迫等待,导致 Time-Between-Tokens(TBT)指标飙升。Sarathi-Serve 的研究表明,这种停顿在某些场景下可长达数秒,严重违反交互式应用的延迟 SLO。
反之,若优先保障 Decode 的低延迟,则 Prefill 被推迟,导致 Time-To-First-Token(TTFT)恶化,用户感知到的「首字延迟」增加。传统静态批处理(Static Batching)试图通过等待批次内所有请求完成来规避这一问题,但这会造成严重的 GPU 利用率浪费 —— 当批次中某些请求已生成结束符(EOS)时,其占用的显存位置无法立即被新请求复用。
二、连续批处理:迭代级调度的核心机制
连续批处理(Continuous Batching),也称为迭代级调度(Iteration-level Scheduling),是解决上述困境的关键技术。与静态批处理在请求级别管理批次不同,连续批处理允许请求在每次模型前向传播(iteration)后动态进出批次。
具体而言,当某个请求在 iteration $t$ 生成 EOS token 后,系统可在 iteration $t+1$ 立即将新的等待请求加入批次,无需等待其他请求完成。这种机制配合 vLLM 提出的 PagedAttention 技术,通过将 KV Cache 分配从「预分配连续缓冲区」改为「按需分页分配」,将显存碎片率控制在 4% 以下,从而支持更大的并发批次。
然而,单纯的连续批处理并未解决 Prefill-Decode 冲突。当新请求加入时,若直接执行完整 Prefill,仍会导致 Decode 停顿。Sarathi-Serve 提出的 Chunked-Prefill 机制对此进行了优化:将长 prompt 切分为多个小块(chunks),每个 chunk 与正在进行的 Decode 请求合并为一个混合批次(Hybrid Batch)执行。由于 Decode 阶段的算术强度较低,GPU 存在计算余量,可在不显著增加 Decode 延迟的前提下,逐步完成 Prefill 计算。
三、Token 预算与无停顿调度
实现高效连续批处理的核心在于 Token 预算(Token Budget) 的设定。Token 预算定义了每个 iteration 可处理的最大 token 数量,直接决定了 TBT 的上界。
在严格延迟 SLO(如 TBT < 50ms)场景下,建议将 Token 预算设为 512;在宽松 SLO 场景下,可提升至 2048。预算的确定需考虑以下因素:
-
Tile Quantization 效应:GPU 矩阵运算以固定大小的 tile 为单位并行执行。若批次 token 数不是 tile 尺寸的整数倍(通常为 256 的倍数),部分线程块将执行无效计算。因此,实际配置的 Token 预算应向上取整至 256 的倍数。
-
Chunk 开销权衡:过小的 chunk 会增加 attention 计算的 KV Cache 重复读取次数。实验表明,chunk size 为 2048 时线性层开销接近零,但 TBT 约束可能迫使使用更小的 chunk。
基于 Token 预算,无停顿调度(Stall-free Scheduling) 算法的工作流程如下:
- 首先将所有正在 Decode 的请求加入批次(每个请求贡献 1 个 token)
- 若有正在进行的 Prefill 请求,计算其下一个 chunk 大小,确保不超过剩余预算
- 在剩余预算允许范围内,按 FCFS 顺序接纳新请求的 Prefill chunks
- 执行混合批次的前向传播
- 更新各请求状态,移除已完成请求,重复步骤 1
这种调度策略确保 Decode 请求不会因 Prefill 而停顿,同时最大化 GPU 利用率。
四、动态抢占与优先级分层
在 3k tokens/s 的极端压力下,仅靠连续批处理可能仍无法满足所有请求的延迟要求。此时需要引入 动态抢占(Dynamic Preemption) 机制。
抢占的核心思想是:当高优先级请求(如实时对话)到达时,可暂停低优先级请求(如批量文档生成)的执行,释放其占用的 KV Cache 和计算槽位。被抢占的请求状态被保存至 CPU 内存或分布式存储,待高优先级请求完成后再恢复执行。
抢占调度需解决三个关键问题:
1. 抢占粒度决策
抢占可在请求级别或 chunk 级别进行。请求级抢占简单但粒度粗,可能导致大量已计算 token 的浪费;chunk 级抢占更精细,但实现复杂度高。建议采用 chunk 级抢占,配合 chunked-prefill 机制,将浪费控制在单个 chunk 范围内。
2. KV Cache 迁移开销
抢占涉及将请求的中间状态(KV Cache)从 GPU 显存迁出。对于长序列,KV Cache 可能占用数 GB 显存,迁移延迟不可忽视。优化策略包括:
- 仅迁移被抢占请求的 KV Cache,保留未受影响请求的状态
- 使用 CPU 内存作为交换空间,而非直接写入磁盘
- 对于多轮对话场景,考虑保留最近 N 轮对话的 KV Cache 在显存中,仅迁移更早的历史
3. 优先级策略设计
建议采用多级优先级队列:
- P0(实时级):延迟敏感型交互请求,TTFT 目标 < 100ms,TBT 目标 < 20ms
- P1(标准级):普通对话请求,TTFT 目标 < 500ms,TBT 目标 < 100ms
- P2(批处理级):文档生成、代码补全等可容忍较高延迟的请求
调度器优先服务 P0 队列,仅在 P0 为空时处理 P1,以此类推。当 P0 请求到达时,可抢占 P1/P2 请求的资源。
五、可落地参数配置
基于上述分析,针对 3k tokens/s 单请求压力场景,给出以下可直接应用的参数配置:
5.1 Token 预算与 Chunk 设置
| 延迟要求 | Token 预算 | Chunk Size | 适用场景 |
|---|---|---|---|
| 严格(TBT<50ms) | 512 | 256 | 实时对话、语音交互 |
| 标准(TBT<100ms) | 1024 | 512 | 通用聊天、问答 |
| 宽松(TBT<200ms) | 2048 | 1024-2048 | 文档生成、代码补全 |
5.2 抢占阈值
- 抢占触发条件:P0 队列非空且 GPU 利用率 > 90%
- 最大抢占深度:单次调度周期内最多抢占 2 个低优先级请求
- KV Cache 迁移超时:超过 50ms 则放弃抢占,改为排队等待
5.3 内存管理
- PagedAttention Block Size:16 tokens(平衡内存效率与碎片率)
- 预留显存比例:总显存的 5% 用于动态分配缓冲
- CPU 交换空间:配置 32GB+ 用于 KV Cache 溢出
六、监控指标与告警策略
生产环境需建立以下监控体系:
核心指标
- TTFT P99:目标 < 500ms,告警阈值 1s
- TBT P99:根据 SLO 等级设定,通常 < 200ms
- Batch Size 分布:监控是否存在长期低 batch size 运行
- Preemption 频率:每分钟抢占次数,异常升高时触发告警
- KV Cache 命中率:低于 95% 时检查内存配置
关键告警规则
- 连续 3 个周期 TBT P99 超过 SLO 的 2 倍 → 触发扩容
- Preemption 频率 > 10 次 / 分钟 → 检查优先级配置是否合理
- GPU 利用率 <60% 但队列深度> 100 → 检查 batching 配置
七、总结
在 3k tokens/s 的高吞吐压力下,连续批处理与动态抢占调度的设计需要在吞吐与延迟之间寻找精细平衡。通过 Chunked-Prefill 避免生成停顿,通过 Token 预算控制延迟上界,通过多级优先级与抢占机制保障关键请求的响应速度,配合 PagedAttention 的内存优化,可在单 GPU 上实现数倍于静态批处理的吞吐量,同时将尾延迟控制在可接受范围内。
实际部署时,建议从标准延迟配置起步,根据实际 workload 的 prompt 长度分布和延迟要求,逐步调整 Token 预算与抢占策略。监控体系的建立同样关键,只有持续观测 TTFT、TBT 与 preemption 频率,才能确保调度策略在生产环境中稳定运行。
参考来源
- Sarathi-Serve: Taming Throughput-Latency Tradeoff in LLM Inference with Chunked-Prefills (arXiv:2403.02310)
- Anyscale Blog: Achieve 23x LLM Inference Throughput & Reduce p50 Latency with Continuous Batching
- vLLM: Efficient Memory Management for LLM Serving with PagedAttention (SOSP 2023)
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。