当前位置: 首页 > news >正文

大模型推理服务的批处理与动态 Batch 调度:从逐条推理到吞吐量优化

大模型推理服务的批处理与动态 Batch 调度:从逐条推理到吞吐量优化

一、推理服务的吞吐量瓶颈:GPU 利用率的隐性浪费

大模型推理服务的核心瓶颈不是单次请求的延迟,而是 GPU 利用率。在逐条推理模式下,每个请求独立送入 GPU 计算,Batch Size 为 1,GPU 的并行计算能力大量闲置。以 A100 GPU 为例,Batch Size 1 时 GPU 利用率通常不足 20%,而 Batch Size 8-16 时可提升至 70% 以上。

批处理(Batching)是提升推理吞吐量的关键手段:将多个请求合并为一个 Batch 送入 GPU,利用矩阵运算的并行性摊薄计算开销。但批处理的引入带来新的挑战:请求到达时间不同,需要等待凑批,增加了尾延迟;Batch 内请求的序列长度差异导致 Padding 浪费;动态流量下 Batch Size 的最优值持续变化。动态 Batch 调度系统需要在吞吐量与延迟之间找到动态平衡点。

二、动态 Batch 调度的核心机制

flowchart TD A[请求到达] --> B[请求队列] B --> C[Batch 调度器] C --> D{调度策略} D -->|时间窗口到期| E[组装当前队列所有请求] D -->|队列长度达到上限| F[组装最大 Batch] D -->|最长等待超时| G[立即发送已有请求] E --> H[Padding 与注意力掩码] F --> H G --> H H --> I[GPU 推理] I --> J[结果拆分与返回] subgraph 连续批处理 Continuous Batching K[迭代级调度] K --> L[每步重新评估 Batch] L --> M[已完成序列让出位置] M --> N[新请求填入空位] end C --> K

静态批处理(Static Batching)在凑满 Batch 后一次性推理,Batch 内所有序列必须等待最长序列完成才能返回。连续批处理(Continuous Batching)在每次迭代(生成一个 Token)后重新评估 Batch:已完成的序列立即让出位置,新请求填入空位,显著降低平均等待时间。

三、工程实现:基于 vLLM 的动态 Batch 推理服务

# dynamic_batch_server.py — 动态 Batch 推理服务 from fastapi import FastAPI from pydantic import BaseModel import asyncio import time from typing import List, Optional from vllm import LLM, SamplingParams from vllm.entrypoints.openai.api_server import init_app app = FastAPI() class InferenceRequest(BaseModel): prompt: str max_tokens: int = 256 temperature: float = 0.7 top_p: float = 0.9 priority: int = 0 # 0=普通, 1=高优先级 class InferenceResponse(BaseModel): text: str tokens: int latency_ms: float # vLLM 引擎初始化:启用 Continuous Batching llm = LLM( model="Qwen/Qwen2.5-72B-Instruct", tensor_parallel_size=2, # 2 卡并行 max_num_seqs=64, # 最大并发序列数 max_num_batched_tokens=32768, # 单 Batch 最大 Token 数 gpu_memory_utilization=0.90, # GPU 显存利用率上限 enable_prefix_caching=True, # 启用前缀缓存,复用 System Prompt ) # 推理端点:vLLM 内部自动管理 Batch 调度 @app.post("/v1/completions", response_model=InferenceResponse) async def completions(request: InferenceRequest): start_time = time.monotonic() sampling_params = SamplingParams( max_tokens=request.max_tokens, temperature=request.temperature, top_p=request.top_p, ) # vLLM 的 add_request 自动进入 Continuous Batching 队列 outputs = llm.generate( prompts=[request.prompt], sampling_params=sampling_params, use_tqdm=False, ) latency_ms = (time.monotonic() - start_time) * 1000 output = outputs[0] return InferenceResponse( text=output.outputs[0].text, tokens=len(output.outputs[0].token_ids), latency_ms=latency_ms, )
# batch_metrics.py — Batch 调度指标监控 from prometheus_client import Histogram, Gauge, Counter import time from functools import wraps # 核心指标定义 BATCH_SIZE = Histogram( 'inference_batch_size', 'Batch 大小分布', buckets=[1, 2, 4, 8, 16, 32, 64] ) QUEUE_LENGTH = Gauge( 'inference_queue_length', '等待队列中的请求数' ) INFERENCE_LATENCY = Histogram( 'inference_latency_ms', '推理延迟分布', buckets=[50, 100, 200, 500, 1000, 2000, 5000] ) GPU_UTILIZATION = Gauge( 'gpu_utilization_percent', 'GPU 利用率' ) TOKENS_PER_SECOND = Gauge( 'inference_tokens_per_second', '每秒生成 Token 数' ) def track_batch_metrics(func): @wraps(func) async def wrapper(*args, **kwargs): # 记录队列长度 QUEUE_LENGTH.set(get_current_queue_length()) start = time.monotonic() result = await func(*args, **kwargs) latency = (time.monotonic() - start) * 1000 INFERENCE_LATENCY.observe(latency) return result return wrapper # 动态 Batch Size 调优:基于延迟 SLO 调整最大 Batch class AdaptiveBatchController: def __init__(self, latency_slo_ms: float = 500): self.latency_slo_ms = latency_slo_ms self.max_batch_size = 16 self.min_batch_size = 1 def adjust(self, current_p99_latency: float): """根据 P99 延迟动态调整最大 Batch Size""" if current_p99_latency > self.latency_slo_ms * 1.5: # 延迟超标,减小 Batch Size self.max_batch_size = max( self.min_batch_size, self.max_batch_size - 2 ) elif current_p99_latency < self.latency_slo_ms * 0.5: # 延迟充裕,增大 Batch Size 提升吞吐 self.max_batch_size = min(64, self.max_batch_size + 2)

四、动态 Batch 调度的边界与权衡

Padding 浪费:Batch 内不同序列长度差异导致短序列需要 Padding 到最长序列的长度,浪费计算资源。vLLM 的 PagedAttention 通过虚拟内存管理减少 Padding 浪费,但极端长度差异(1:10 以上)仍会显著影响有效吞吐。建议对请求按长度分桶,相似长度的请求组成同一 Batch。

凑批延迟:等待凑批的时间增加了请求的尾延迟。在低流量时段,凑批等待可能成为延迟的主要来源。解决方案是设置最大等待时间(如 50ms),超时后即使 Batch 未满也立即发送,避免无限等待。

KV Cache 显存竞争:Batch 内所有序列的 KV Cache 共享 GPU 显存,长序列消耗大量显存,可能挤占其他序列的空间。vLLM 的 PagedAttention 按需分配 KV Cache 页,但显存不足时仍需拒绝新请求。需根据模型大小与 GPU 显存合理设置max_num_seqs

流式输出的兼容性:Continuous Batching 与流式输出(SSE)存在天然矛盾:流式要求 Token 级别的即时返回,而 Batching 需要等待整个迭代步完成。vLLM 通过迭代级调度解决了这一问题——每个 Token 生成后立即返回,同时维护 Batch 状态。

五、总结

动态 Batch 调度是大模型推理服务吞吐量优化的核心手段。Continuous Batching 通过迭代级调度实现"完成即让位",显著降低平均等待时间。工程落地的关键在于:PagedAttention 减少 Padding 浪费、自适应 Batch Size 控制器基于延迟 SLO 动态调优、最大等待时间避免凑批延迟、按长度分桶优化 Batch 内序列长度一致性。推理服务的优化不是单一维度的调参,而是在吞吐量、延迟与显存利用率三个目标间的持续权衡。

http://www.jsqmd.com/news/1002805/

相关文章:

  • 华大HC32F460JETA点灯踩坑记:为什么我的LED不受控制?附官方库延时函数详解
  • 2026年广州温度传感器热电偶与测温方案甄选:K型、J型、PT100铂电阻及非标定制评估 - 品牌发掘
  • DistroAV网络视频传输终极指南:告别复杂布线,开启多设备无线直播新时代
  • Android原生个人信息页组件:矢量图标动态着色+点击按压反馈
  • 2026年嘉兴挖机出租哪家好?5家本地专业机械租赁商推荐 - 本地品牌推荐
  • Zig编程中的参数传递策略
  • 慢慢来,坚持走更远
  • FigmaCN浏览器扩展深度解析:基于DOM实时监测的中文界面本地化方案
  • SOON模型:深度学习在S2S天气预报中的物理约束与优化
  • 012、UART高级应用:多机通信、流控制、环形缓冲区与FIFO管理
  • 2026年电线电缆回收行业观察:哪家更靠谱?真实企业实力与案例深度解析 - 优质品牌商家
  • 2026年小区换热站怎么选?五大供应商多维评测与实战案例解析 - 优质品牌商家
  • 济南GEO优化服务商专业榜:2026年6月企业选型盘点与靠谱机构梳理 - 外贸老黄
  • 深入探讨C++中的指针与偏移量
  • 芯片编程烧写烧录座口碑厂家究竟有何独到之处?
  • 计算机视觉:视觉 Transformer 的注意力机制与工程优化,ViT 架构的深度解析
  • 改扩建项目如何处理老旧图纸?从扫描件到可设计CAD的AI流程
  • 2026年 塑料检查井厂家推荐:市政排水与高环刚度井筒管品牌深度解析 - 品牌发掘
  • 2026年浅层砂过滤器行业观察:技术迭代与供应商能力全景分析 - 优质品牌商家
  • Android App接入腾讯地图SDK实现高精度定位与地图渲染
  • Tauri+Rust实战:“与编译器搏斗”的四周,我们踩了五个大坑
  • ArduPilot飞控GPS模块选型与配置实战:从NMEA到RTK,手把手教你避开那些坑
  • 你以为抓到了 Alpha,其实抓到的是 Beta——板块归因模块完整解剖
  • 别再瞎调XGBoost了!用Optuna搞定这10个核心参数,Kaggle老手都这么干
  • 从“能用”到“稳定”:FPGA+ADS1256高精度数据采集系统的电源、时钟与PCB布局实战经验谈
  • 一个用户名搜遍3000+网站——开源情报工具Maigret深度体验
  • 别再只盯着PLL原理了!手把手教你用ADI的ADF4351芯片搞定一个低相位噪声的2.4GHz信号源(附环路滤波器计算)
  • 告别“人工搬砖”!实测实在Agent:自研大模型智能体如何重构业务自主规划流程?
  • 深度学习正则化策略:从 Dropout 到 DropPath,训练稳定性与泛化能力的工程保障
  • NxShell:革命性的跨平台SSH客户端,全面提升远程服务器管理效率