vLLM调度机制深度解析:CPU到GPU的完整映射流程

vLLM调度转换的核心挑战
vLLM作为高性能LLM推理引擎,其调度器生成的schedule output仅是CPU端控制信息,无法被GPU直接使用。本文系统解析vLLM如何将调度计划转换为GPU输入张量,以及如何精确定位KV Cache的物理写入位置。
vLLM是由UC Berkeley Sky Computing Lab团队开发的开源LLM推理服务框架,其核心创新是PagedAttention机制,借鉴操作系统虚拟内存管理思想,将KV Cache划分为固定大小的block进行管理,极大提升了GPU显存利用率。在传统推理框架中,每个请求的KV Cache必须占用连续显存空间,导致大量内存碎片;而vLLM通过分页管理实现了非连续的KV Cache存储,使显存利用率从传统方案的约50%提升至接近98%。正因如此,调度器产出的控制信息与GPU实际需要的物理地址之间存在复杂的多层映射关系。
这个转换过程包含多层坐标映射:从请求ID到全局索引、从全局状态到批次索引、从离散请求到连续token序列,最终映射到物理显存地址。掌握这些映射关系是理解vLLM内部机制的关键。

Worker请求状态管理机制
请求上下文的持久化策略
模型推理是多步骤流程,单个请求需要执行多个step。LLM推理分为prefill(预填充)和decode(解码)两个阶段:prefill阶段一次性处理所有输入token并生成第一个输出token,decode阶段每步仅生成一个新token。由于自回归(autoregressive)特性,每个decode step都需要访问之前所有token的KV Cache,因此worker必须持久化请求状态和计算进度,避免重复构建上下文。核心数据结构包括:
- request_state:追踪每个请求的计算进度(如completed_tokens),记录该请求已经处理了多少token,从而确定下一步需要从哪个位置继续计算
- block_table:维护逻辑block到物理block ID的映射关系。其设计类似于操作系统的页表——逻辑block代表请求视角下的连续KV Cache空间,物理block ID则对应GPU显存中实际分配的block位置。这种间接映射使得物理显存可以非连续分配,从而消除内存碎片问题
schedule output仅对当前step有效,执行完毕后调度器会生成新的output。worker需将output更新到持久状态,保证状态连续性。
双重索引体系的设计逻辑
调度器使用字符串request_id标识请求,但worker为提升访问性能采用数组下标(request_state_index)。字符串哈希查找的时间复杂度为O(1)但常数因子较大,而数组下标访问仅需一次内存偏移计算,在高频调用场景下性能差异显著。新请求到达时分配index,请求完成后index回收复用,这种池化管理策略避免了频繁的内存分配和释放开销。
具体示例:
- 请求B分配到第7行(index=7):已完成31个token,物理block ID为37和12
- 请求A分配到第6行(index=6):已完成16个token,物理block ID为81和44
状态管理方法:
add_request():为新请求初始化state和block_tableupdate_request():为已注册请求追加新分配的block ID

批次构建与序列压平技术
从全局状态提取执行批次
schedule output指明本轮执行计划:请求B执行1个token,请求A执行8个token。worker执行流程:
- 从全局状态中提取相关请求
- 按本轮执行token数量排序
- 组装成新的batch
这引入新的映射关系:请求B从全局第7行映射到batch第2行,请求A从全局第6行映射到batch第1行。通过index_mapping维护这一对应关系。这种设计使得batch可以紧凑排列,无需为全局状态表中的空行浪费计算资源。
Token序列的连续化处理
GPU无法直接执行离散的token组合。GPU的SIMT(单指令多线程)架构决定了它在处理连续、规整的数据时效率最高——如果将不同请求的token分别发送给GPU处理,会导致大量kernel启动开销和GPU空闲周期。因此必须将"请求B 1个token + 请求A 8个token"压平为9个连续token序列,最大化GPU吞吐量。这种序列压平(flattening)技术配合FlashAttention等融合kernel,能够在一次GPU调用中完成所有请求的计算。
压平后通过以下数组保留边界信息:
- query_start_loc:记录每个请求起始位置,如[0, 1, 9]表示token 0属于请求B,token 1-8属于请求A。该数组采用前缀和编码方式,本质上是压缩稀疏行(CSR)格式的变体,attention kernel通过它在一个连续计算中区分不同请求的边界,防止跨请求的注意力泄露(即请求A的token不应attend到请求B的KV Cache)
- position:记录token在原始请求中的位置。请求B本轮位置为31,请求A本轮位置为16-23。该信息对于RoPE(旋转位置编码)等位置编码机制至关重要,确保每个token获得与其在原始序列中位置一致的位置编码
- input_ids:存储真实token ID,从output的token_ids对应位置复制
这三个数组实现从连续序列到原始请求的反向映射能力。

KV Cache物理地址精确定位
多层坐标转换链路
获得连续token序列后,最终目标是确定GPU显存的读写位置。KV Cache的分页存储中,每个物理block包含固定数量的slot(如block_size=16表示每个block存储16个token的KV向量)。slot是KV Cache的最小寻址单位,每个slot存储一个token在所有attention head上的Key和Value向量。需要完成:
- input_block_tables:定位attention可见的KV pages,告知kernel到哪些物理block中读取历史KV Cache
- slot_mapping:标记本轮新token的写入slot,指定新计算的KV向量应存储到哪个物理位置
完整转换链路:
batch_index → request_state_index(通过index_mapping)
flat_token_index → position(一一对应)
position → logic_block + offset(除法和取余)
request_state_index + logic_block → physical_block_id(查block_table)
physical_block_id + offset → slot_id(最终物理地址)
这条链路的本质是将二维的(block, offset)坐标线性化为一维地址,类似于C语言中二维数组的行优先存储方式。
地址计算实例
以请求B的第一个token为例:
- flat_token_index = 0,position = 31
- logic_block = 31 // 16 = 1(block_size=16,即每个block容纳16个token的KV Cache)
- offset = 31 % 16 = 15(在该block内的第16个slot,从0开始计数)
- 查block_table[7][1] = 12(请求B的第二个逻辑block对应物理block 12)
- slot_id = 12 * 16 + 15 = 207(全局物理slot编号)
注意slot_id的单位不是字节,而是一个KV Cache单元,由attention banking机制定义。每个KV Cache单元的实际字节大小取决于模型的head_dim和数据精度——例如在FP16精度、head_dim=128的配置下,单个slot存储一对KV向量需要 2 × 128 × 2 = 512字节(乘以attention head数量)。不同KV Cache group会生成各自的block_table和slot_mapping。KV Cache group的概念源自GQA(Grouped Query Attention)等技术——在GQA中,多个query head共享同一组KV head,因此不同的head组可能对应独立的KV Cache存储区域,需要分别管理其物理block分配。

Attention模块的完整输入准备
经过上述转换,worker准备好attention计算的完整输入。现代高效attention实现(如FlashAttention、FlashInfer)要求输入严格符合特定的内存布局规范,以充分利用GPU的共享内存和寄存器层级实现最优计算性能。
input_batch包含:
- request_id列表
- index_mapping(batch索引到全局索引映射)
- input_ids(真实token序列)
- position数组(token位置信息,供RoPE等位置编码使用)
- query_start_loc(请求边界标记,确保attention不会跨请求泄露)
- seq_lens(每个请求的序列长度,包括历史token和当前新增token,attention kernel据此确定每个query token需要attend的KV范围)
每个KV Cache group提供:
- input_block_tables(可见的物理block列表,kernel通过间接寻址访问分散在显存各处的KV Cache block,实现零拷贝的高效随机访问)
- slot_mapping(写入位置映射表,指定新生成的KV向量写入目标slot)
这些数据结构构成GPU可直接消费的输入格式,attention kernel据此完成高效并行计算。
四大索引空间映射总结
vLLM调度执行涉及四个关键索引空间:
- request_state_index:请求在worker全局状态中的行号,用于持久化存储请求的计算进度和block_table,生命周期从请求到达到请求完成
- batch_index:请求在当前批次中的行号,是每个step临时生成的紧凑索引,通过index_mapping与request_state_index关联
- flat_token_index:token在压平序列中的位置,将多个请求的token拼接为一维连续数组后的全局编号
- position:token在原始请求序列中的位置,反映该token在完整对话/生成上下文中的真实序号
这四个索引空间构成了一条从高层语义到底层物理的完整映射链路:request_state_index和batch_index处理请求级别的管理,flat_token_index实现GPU计算所需的连续化,position则连接到KV Cache的物理寻址。理解这些索引空间及其转换关系,是深入vLLM架构的基础。建议结合示例图反复推演,掌握从CPU调度指令到GPU物理地址的完整映射路径。
核心要点
相关推荐

AI训练设施面临超人类黑客威胁:史无前例的网络攻击风险
AI安全专家警告:下一代大模型训练基础设施可能遭遇AI黑客的超人类级别攻击,威胁规模超过人类历史总和。了解AI训练安全面临的前所未有挑战及应对策略。

Anthropic员工辞职引发AI行业人才流动深度讨论
Anthropic员工公开辞职在Hacker News引发热议,获287点赞344评论。深度解析AI行业人才流动背后的技术方向分歧、企业文化变迁与价值观差异,探讨AI安全公司面临的商业化挑战与未来发展路径。

Querit搜索API:为AI Agent打造的实时搜索与定时监控方案
Querit是面向LLM和AI Agent的Web搜索API,提供毫秒级响应、Monitor API定时监控、多源去重及Dify/LangChain集成,FreshQA准确率达83.17%,适用于竞品监测与新闻追踪。