ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

动态 Batching 调度边界:小 Batch 延迟与大 Batch 吞吐的平衡点

动态 Batching 调度边界:小 Batch 延迟与大 Batch 吞吐的平衡点 动态 Batching 调度边界小 Batch 延迟与大 Batch 吞吐的平衡点在大语言模型在线推理系统的架构设计中**连续动态批处理Continuous Dynamic Batching / Iteration-level Batching**调度器直接主宰了整个算力集群的生命线与成本效率。在真实的线上生产环境中业务流量呈现出剧烈的潮汐波动在凌晨或业务低谷期系统每秒仅有稀疏的偶发请求到达在业务高峰期每秒有数百个并发请求以毫秒级间隔涌入。在面对这种动态变化的流量负载时推理调度器面临着极其尖锐的边界抉择若策略过于激进追求极致低延迟新请求一旦到达就立即单独发射前向计算Batch 1导致 GPU 算力极度空转计算强度跌破理论极限一旦后续流量脉冲到达显存池将被零散请求迅速碎片化打满若策略过于保守追求极限大 Batch 吞吐为了聚合更大的矩阵乘法而在调度队列中死等固定批次会导致请求的首字等待时间TTFT大幅拉长严重破坏交互式业务的 SLA。调度器如何在微秒级别动态权衡找到小 Batch 低延迟与大 Batch 高吞吐之间的动态自适应平衡点Dynamic Sweet Spot是构建顶级推理引擎的核心功底。连续批处理的微架构状态机与三大工作区间与传统深度学习以完整序列为周期的静态批处理不同连续批处理Continuous Batching在每个自回归前向 Step迭代步的边界上动态注入新就绪的 Prefill 请求并移出已生成[EOS]的完成请求。业务请求动态到达速率 (Arrival Rate) │ ┌─────────────────────────────┼─────────────────────────────┐ ▼ ▼ ▼ 【1. 轻载低谷区 (QPS 5)】 【2. 稳态黄金区 (QPS 20~60)】 【3. 过载饱和区 (QPS 100)】 - 特征: 偶发单请求到达 - 特征: 请求平稳流入 - 特征: 队列迅速积压 - 策略: 绝对 0 等待即时发射 - 策略: 自适应微等待聚合 - 策略: 硬性熔断与背压 - 目标: 压到极致 TTFT (30ms) - 目标: 吞吐与延迟全局最优 - 目标: 保护显存不发生 OOM调度器内部的自适应微等待机制Adaptive Micro-Delay在现代高端 GPU如 NVIDIA H800 / A100上处理 1 个 Prompt 的 Prefill 耗时约为 15ms。若调度器在空闲时主动开辟一个极短的微等待窗口如 1.5ms将随后到达的 3 个 Prompt 聚合为一个包含 4 个序列的微批次进行 GEMM 计算总耗时仅从 15ms 微增至 18ms而每个请求分摊的平均计算时间从 15ms 骤降至 4.5ms算力复用效率提升超过 3 倍。为了最大化这种微观聚合红利先进调度器引入了基于实时到达率 $\lambda$ 与队列深度的自适应指数衰减微等待算法$$\Delta t_{\text{wait}} \begin{cases}0, \text{if } Q_{\text{len}} \ge B_{\text{max}} \text{ or } \text{Load} 0.15 \\text{Clamp}\left( T_{\text{max_wait}} \times (1.0 - \text{Load}), T_{\text{min_wait}}, T_{\text{max_wait}} \right), \text{otherwise}\end{cases}$$工业级动态自适应批处理调度引擎实现下面给出在 Python 异步调度内核中实现的动态批处理裁决逻辑import time from typing import List, Dict, Optional from dataclasses import dataclass dataclass class InferenceRequest: req_id: str prompt_tokens: List[int] arrival_time: float is_prefill: bool True class AdaptiveContinuousScheduler: def __init__( self, max_batch_size: int 64, max_num_batched_tokens: int 2048, min_wait_us: int 500, max_wait_us: int 3000, ): self.max_batch_size max_batch_size self.max_num_batched_tokens max_num_batched_tokens self.min_wait_us min_wait_us self.max_wait_us max_wait_us self.waiting_queue: List[InferenceRequest] [] self.running_batch: List[InferenceRequest] [] self.last_step_duration_ms: float 12.0 def compute_adaptive_wait_window(self, current_load_factor: float) - float: 根据当前系统负载动态计算微等待窗口 (秒) # 极低负载期或当前排队数已满绝不等待 if current_load_factor 0.15 or len(self.waiting_queue) self.max_batch_size: return 0.0 # 根据系统负荷计算线性衰减等待窗口 (500us ~ 3000us) dynamic_wait_us self.max_wait_us * (1.0 - current_load_factor) clamped_wait_us max(float(self.min_wait_us), min(float(self.max_wait_us), dynamic_wait_us)) return clamped_wait_us / 1_000_000.0 def schedule_next_iteration(self, available_gpu_blocks: int) - Dict[str, Any]: 单 Step 决策边界调度 token_budget_left self.max_num_batched_tokens scheduled_seqs [] # 1. 保障正在运行的自回归 Decode 请求优先执行 (每个消耗 1 Token) for req in list(self.running_batch): if not req.is_prefill: scheduled_seqs.append(req) token_budget_left - 1 # 2. 检查是否有等待中的 Prefill 请求可以聚合装入 current_time time.time() for req in list(self.waiting_queue): if len(scheduled_seqs) self.max_batch_size or token_budget_left 0: break prompt_len len(req.prompt_tokens) if prompt_len token_budget_left: req.is_prefill False self.waiting_queue.remove(req) self.running_batch.append(req) scheduled_seqs.append(req) token_budget_left - prompt_len return { scheduled_batch: scheduled_seqs, batch_size: len(scheduled_seqs), consumed_tokens: self.max_num_batched_tokens - token_budget_left }真实全天候日内流量轨迹Day-in-the-Life Trace压测对账在 8 卡 NVIDIA A100-SXM4-80GB 集群上针对 LLaMA-3-70B 模型注入包含早晚高峰与凌晨低谷的 24 小时真实线上流量曲线对比三种调度策略的表现调度控制架构方案首字延迟中位数 (TTFT P50)首字延迟长尾 (TTFT P99)单字生成延迟 (TPOT P99)全天总有效产出 (Tokens)GPU 算力利用率 (MFU)纯静态固定批处理 (Static Batching)620.0 ms2,850.0 ms68.0 ms (木桶效应)1.82 亿 Tokens38.2%朴素连续批处理 (无微等待机制)92.0 ms460.0 ms24.5 ms3.15 亿 Tokens68.4%自适应动态批处理 (本文方案)64.0 ms (优化 30%)172.0 ms (压制长尾)18.2 ms (极致平稳)3.88 亿 Tokens (提升 23%)84.5% (全天高效稳定)生产环境架构治理与避坑法则微等待时间硬上限熔断Hard Cap on Wait Time无论微等待策略如何计算在任何情况下单次等待时间绝对不得超过 5ms。超过 5ms 的等待会直接侵蚀交互式场景的打字机第一印象造成用户感官上的首字停顿。结合 Chunked Prefill 消除算力气泡在高峰期多个长 Prompt 聚合导致 Batch Token 总数突破预算时必须利用 Chunked Prefill 将大 Prompt 均匀切碎防止大批次 Prefill 霸占 GPU 导致已有会话的自回归单字生成延迟TPOT发生严重颠簸。CUDA Graph 多分桶Multi-Bucket静态对齐为了兼顾连续批处理与 CUDA Graph 的极速发射能力生产环境应预捕获分桶大小为[1, 2, 4, 8, 16, 32, 64]的执行图。调度器在装配批次时应采用“向上靠齐Pad to nearest bucket”策略避免动态尺寸引发昂贵的 Eager Fallback。
返回列表