【深夜调试大语言模型的难题根源】
你是否曾在深夜调试大语言模型服务时,对着飙升的延迟和捉襟见肘的 GPU 显存一筹莫展?为何同样的模型,在线服务商能支撑高并发,自建的推理服务却频频超时?试图增大 batch size 提升吞吐量,却换来首字延迟的恶性膨胀。这些问题的根源,往往藏在黑盒般的推理引擎内部。
【深入 Nano - vLLM 推理引擎】
这篇文章深入 Nano - vLLM,一个由 DeepSeek 贡献者开源的、仅 1200 行代码却完整实现 vLLM 核心机制的推理引擎。文章从生产者 - 消费者调度器如何平衡吞吐量与延迟,到 BlockManager 如何通过哈希实现前缀缓存,再到张量并行下 Leader - Worker 的共享内存通信,用清晰的工程视角拆解了从提示词到输出词元的完整路径。
【整体架构设计、调度策略及完整路径】
在生产环境中部署大语言模型时,推理引擎是关键基础设施组件。每个 LLM API 都运行在推理引擎之上。深入理解其底层运作机制,对系统设计决策有重要影响。本系列文章通过 Nano - vLLM 探讨内部机制,它是精简版但达生产级标准的推理引擎,实现了使 vLLM 具备生产就绪能力的关键特性,基准测试显示其吞吐量可与完整版 vLLM 相媲美甚至超越。第一部分聚焦工程架构,第二部分将深入探讨注意力机制等。
【主流程:从 Prompt 到输出】
【从 Prompts 到 Sequences(序列)】
当 generate 方法被调用,每个 prompt 字符串先经过 tokenizer 转换成 sequence,不同模型家族使用不同 tokenizer,sequence 成为流经系统其余部分的核心工作单元。
【生产者 - 消费者模式】
系统采用以 Scheduler 为中心的生产者 - 消费者模式,add_request 方法充当生产者,独立的 step 循环充当消费者,这种解耦设计可累积多个 sequence 一起处理,提升性能。
【批处理与吞吐量 - 延迟的权衡】
GPU 计算有固定开销,批处理可分摊开销提升吞吐量,但 batch 越大,单个请求延迟可能增加;batch 越小,延迟越低但吞吐量下降,batch size 参数调控这种权衡。
【Prefill 与 Decode:生成过程的两个阶段】
LLM 推理分为 Prefill 和 Decode 两个阶段。Prefill 处理输入 prompt 构建模型内部状态,用户看不到输出;Decode 生成输出 token,是文本流式输出阶段。单个 sequence 有且仅有一次 prefill 阶段,随后是多个 decode 步骤,Scheduler 需区分这两个阶段。
【Scheduler 内部机制】
【Waiting 与 Running 队列】
Scheduler 维护 Waiting Queue 和 Running Queue。新增的 sequence 先进入 Waiting Queue,Scheduler 与 Block Manager 协作分配资源后,转入 Running Queue,然后从 Running Queue 挑选 sequence 打包成 batch 并附上操作标识。
【处理资源耗尽的情况】
当 GPU 显存被占满,Running queue 中没空间存储下一个 token 缓存的 sequence 会被 preempt 移回 Waiting queue 队首。sequence 完成生成后,Scheduler 会将其从 Running queue 移除并释放资源。
【Block Manager:KV Cache 的控制平面】
【从 Sequences 到 Blocks】
Block Manager 将 sequence 切分成固定大小的 block,不同 sequence 的 token 不共享同一个 block,但一个较长的 sequence 可横跨多个 block。
【通过哈希实现 Prefix Caching】
Block Manager 维护「哈希值 → block id」的映射表,新 sequence 到达时,计算 block 哈希,若缓存中有相同哈希的 block,增加其引用计数复用,在大量请求共享相同前缀的场景下高效。
【控制平面 vs. 数据平面】
Block Manager 运行在 CPU 内存中,负责追踪元数据,真正的 KV cache 数据存储在 GPU 上。Block Manager 是控制平面,GPU 显存是数据平面,这种分离设计让资源分配决策可快速完成。block 被释放时,Block Manager 标记为空闲,GPU 内存不清零,复用覆盖原有内容。
【The Model Runner: 执行(Execution)和并行(Parallelism)】
【张量并行通信】
当模型太大无法放入单张 GPU 时,Nano - vLLM 支持 tensor parallelism,通信架构采用 leader - worker 模式,Rank 0 接收指令并协调,Ranks 1 to N - 1 轮询共享内存缓冲区获取指令,shared - memory 方法对单机多 GPU 设置高效。
【计算前的准备】
Model Runner 根据操作类型准备输入数据,Prefill 准备将多个 sequences 组合成 batch 计算累计序列长度,Decode 准备将单个 tokens 等组合成 batch,还包括将 CPU 端词元数据转换为 GPU 张量。
【CUDA Graphs: 减少 Kernel 启动开销】
对于 decode 步骤,CUDA Graphs 通过记录一系列 GPU 操作重放解决 kernel 启动开销问题,Nano - vLLM 为常见 batch sizes 预先捕获 CUDA graphs。
【Sampling: 从 Logits 到 Tokens】
模型输出 logits,最后通过 sampling 从概率分布中选择 token,temperature 参数控制选择过程,低 temperature 值使输出更具确定性,高 temperature 值使输出更具多样性,这是 LLM 输出“随机性”的来源。
【What's Next】
第二部分将打开模型黑盒,深入探讨模型如何转换 tokens、注意力机制原理、KV cache 物理布局、Dense 架构与 MoE 架构对比以及 tensor parallelism 在计算层面的实现。理解这些内部机制,才能拼出完整图景。
【本期互动内容】
❓Nano - vLLM 用极简代码实现了生产级特性。如果让你设计一个「教学级」推理引擎,你会优先保留哪三个核心模块?为什么?