尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

vLLM 请求调度完整指南:高峰期如何把 GPU 压在“刚好满载“

vLLM 请求调度完整指南:高峰期如何把 GPU 压在“刚好满载“ vLLM 请求调度完整指南高峰期如何把 GPU 压在刚好满载【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm本文带你深入 vLLM 的请求调度系统看一个请求如何从排队走到出结果连续批处理Continuous Batching与分块预填充Chunked Prefill如何平衡吞吐与延迟KV CacheKV 缓存注意力计算中保存的历史键值向量的块如何分配与驱逐以及显存挤爆时的交换与抢占机制最后附调参速查。一次请求的 30 秒旅程想象周五上午十点你的推理服务同时涌入 200 个请求。有人问一个一句话的问题有人贴进十万字的合同。调度器Scheduler每个推理步骤决定这批算谁的核心组件就站在这条流量洪水的总闸口它的工作类似机场塔台谁先登机、谁靠边等、谁被请下飞机都由它一拍板。请求在队列里排号请求进入引擎后第一件事是进入等待队列waiting queue。vLLM 的 V1 引擎提供两种排队策略见 vllm/v1/core/sched/request_queue.py先进先出FCFS默认策略按到达时间排号公平且可预测优先级队列基于堆实现的优先级队列priority 数值小的优先同优先级回到先来先服务被调度器选中后请求的状态从 WAITING 翻到 RUNNING如果中途被抢占则进入 PREEMPTED 状态回到等待队列等资源再战。经典的 V0 版本还有 SWAPPED 状态KV Cache 被换到 CPU 内存V1 把这条路径从核心调度循环中剥离交由 KV 卸载机制处理。状态定义可以直接在 vllm/v1/request.py 的RequestStatus枚举里看到WAITING、RUNNING、PREEMPTED 之外完成态被细分成 FINISHED_STOPPED遇到停止符、FINISHED_LENGTH_CAPPED达到最大长度、FINISHED_ABORTED用户取消等方便上层精确统计为什么结束。预填充与解码两次心跳请求被选中后经历两个计算阶段预填充Prefill一次性处理完整 prompt。计算密集像复印整本文档GPU 利用率拉满解码Decode逐 token 生成。每次只算一步但要把整个 KV Cache 读进显存访存密集像逐字朗读调度器每步schedule()做的事本质上就是回答三个问题哪些 RUNNING 请求继续跑、等待队列里哪些新请求能挤进来、挤不进来时踢走谁。调度入口在 vllm/v1/core/sched/scheduler.py核心逻辑全部围绕这一步的 token 预算还剩多少、KV 块还剩多少展开。让 GPU 始终刚好满载连续批处理航班随到随登传统静态批处理像火车八点发车八点没到站就别想上车。连续批处理则像滚装船装卸——某条船完成卸货新船立即顶上去批次永不发车等待。vLLM 的实现里批次不是一次性圈定的每个推理步骤调度器都会重新审视RUNNING 里谁完成了、waiting 里谁能补位。请求 A 在第 37 步生成完最后一个 token请求 D 在第 38 步就拿到它的行位和刚释放的 KV 块。这正是下图里 Block Table块表记录每个请求的 token 存在哪些 KV 块中逐帧变化的含义D 加入、A 离开行列始终排得满满的。分块预填充长文档分段落印真正的大麻烦是预填充一篇 3 万 token 的合同如果整块塞进 GPU所有正在解码的请求会跟着卡十几秒。分块预填充Chunked Prefill把长 prompt 切成多段、每步只算一段就是为此设计的分段落印。调度器每步的预算由max_num_batched_tokens封顶这一步所有请求合计最多处理这么多 token预填充的分片和解码的单 token 竞争同一份额度。一个 3 万 token 的 prompt 会被拆成若干分片穿插在解码步骤之间消化。相关的两个进阶旋钮在 vllm/config/scheduler.pymax_num_partial_prefills允许同时半程预填充的请求数默认 1调大可让多个长文档并行消化long_prefill_token_threshold长预填充的 token 阈值超过才按长请求管理避免短请求也被分片拖累一句话总结权衡批越大吞吐越高但单请求延迟越高分块预填充用长文慢咽换来了解码不掉线是延迟敏感服务聊天、Agent 工具调用的默认姿势。KV Cache 的经营学块大小与 block_size 的权衡KV Cache 是 LLM 推理的显存大头每个 token 的每层注意力都要存一份 K 向量和 V 向量长上下文下轻松吃掉几十 GB。vLLM 的管理思路类似酒店经营不卖整层楼只卖房块Block——每个块固定容纳block_size个 token常见 16分配、复用、回收都按块进行请求的块表只记你的 token 在哪些块。块大小是个经典权衡块小装填更细碎、内存更省但块表更长、管理开销更高块大管理省但每个请求的最后一块平均浪费一半容量且前缀缓存的命中粒度变粗多组 KV Cache 张量如混合注意力模型如何铺在块上可以看 vllm/v1/core/kv_cache_manager.py 的设计文档配图水印机制永远留几个空房如果 GPU 块被分配得一滴不剩下一步新请求一来就可能触发连锁驱逐甚至抢占。vLLM 用水印watermark预留的缓冲块数留后路watermark_blocks watermark × 总块数见 vllm/v1/core/kv_cache_manager.py并且只在准入等待/被抢占请求时生效——正在解码的请求不受影响只有新客人进门才需要看到预留房。这个设计很讲究水印太激进显存常年空转水印为零高峰期抢占频发、延迟抖动。它是吞吐和稳态延迟之间最便宜的一个旋钮。前缀缓存与 LRU 驱逐谁先让位多个请求共享同一段系统提示词时**前缀缓存Prefix Caching相同前缀的 KV 块只算一次、被多个请求共享**能让第二个请求的预填充近乎免费。引用计数归零的块不会立刻消失而是带着前缀哈希标记进入空闲队列等待被后来的相同前缀认领。空间不够时谁先让位看 vllm/v1/core/block_pool.py 的空闲块队列没有缓存哈希的块纯私有块排在队首最先被复用有缓存哈希的块排在队尾形成LRU最近最少使用最久没被访问的先淘汰顺序命中时再刷新位置也就是说驱逐故事线是先用没人要的私有块再按最久没被读过的顺序拆缓存块。缓存命中率直接决定这个顺序值多少钱——前缀重复度高的工作负载RAG、多轮对话能从这套机制里拿到最大红利。挤爆之后怎么办把 KV 换到 CPU 内存Swap显存实在不够时一个选择是把某些请求的 KV 块从 GPU换出Swap Out到 CPU 内存请求暂时停跑显存腾给急事资源空闲后再换回来继续。代价是 PCIe 搬运——换出 1GB KV 大约相当于白等一次小模型推理所以它只适合CPU 内存够大、请求还要续跑很久的场景。抢占的两种模式怎么选**抢占Preemption显存不足时强制中断某个请求、释放其资源**是调度器的最后手段。经典 vLLM 提供两种模式SWAP 模式被抢占者的 KV 换到 CPU回来时零重算延迟恢复快要求 CPU 内存充足且频繁抢占会让 CPU-GPU 带宽成为新瓶颈RECOMPUTE 模式直接丢弃 KV被抢占者回到 WAITING 重新预填充不占额外内存最坏情况多算一遍已完成的 tokenV1 引擎的_preempt_requestvllm/v1/core/sched/scheduler.py只保留重算这一条路径而且会挑最晚进入的 RUNNING 请求下手尽量让先来者少受牵连。选型依据可以这样记长上下文、单请求价值高、CPU 内存充裕 → SWAP 类机制通用在线服务、请求短而杂 → RECOMPUTE简单且无二次瓶颈调参速查两个典型场景的配置建议场景一高并发短请求问答、分类、Agent 工具调用——目标是高吞吐 稳延迟# 高并发短请求放宽吞吐压低尾延迟 SchedulerConfig( max_num_batched_tokens8192, # 每步 token 预算拉大 max_num_seqs256, # 并发序列数放宽 max_num_partial_prefills1, # 长请求串行消化 ) CacheConfig( block_size16, watermark0.02, # 少量预留防准入抖动 )场景二长文本生成代码、报告、长文档问答——目标是别让长请求互相踩踏# 长文本生成限流预填充给解码留足空间 SchedulerConfig( max_num_batched_tokens4096, # 压缩单步预算 max_num_seqs64, # 压低并发 max_num_partial_prefills2, # 允许多个长 prompt 并行分片 long_prefill_token_threshold2048, # 定义长请求 ) CacheConfig( watermark0.05, # 预留更厚减少长请求中途被抢占 )参数管什么往大了调往小了调max_num_batched_tokens单步 token 预算吞吐升、预填充更快但单步延迟变长延迟更稳吞吐下降max_num_seqs单步最多序列数并发更高KV 竞争加剧显存压力小排队变长block_size每块 token 数管理开销小浪费与缓存粒度变粗更省显存管理开销上升watermark准入预留比例抢占更少可用显存变少吞吐更高尾延迟抖动加大max_num_partial_prefills并发长预填充数多长文档并行消化单长请求独占算力建议盯住的监控指标GPU KV 块水位空闲块占比持续贴地说明要调小预算或加卡前缀缓存命中率低于预期检查请求前缀是否稳定、块大小是否过粗抢占次数偶发正常持续上涨说明watermark或并发参数过激排队时长waiting 队列深度突增往往先于延迟告警出现预填充耗时分布判断分块预填充是否在有效兜底长请求延伸阅读调度主循环 vllm/v1/core/sched/scheduler.py、块池与驱逐 vllm/v1/core/block_pool.py、缓存配置 vllm/config/cache.py。一次请求的旅程里调度器做的所有事归结起来就一句在 token 预算和 KV 块预算两条硬约束下让 GPU 每一毫秒都有活干又别让任何一条请求被饿死。从固定批次的火车到随到随登的滚装船vLLM 的调度哲学已经被验证过无数次下一步值得期待的是调度器开始结合负载预测做主动式资源规划把挤爆后再抢救变成提前排好班。【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表