随着大语言模型(LLM)在生产环境的大规模落地,从“模型训练与微调”转向到人人都可以实现的“高吞吐、低延迟的在线推理服务”。
在传统 Web 微服务架构中,面对高并发流量,横向增加计算节点或堆砌硬件通常能够获得近乎线性的吞吐与延迟收益。然而,在 LLM 推理场景下,开发者经常会遭遇一系列反直觉的性能悖论:
- 算力悖论:升级到峰值 TFLOPS 高出数倍的昂贵加速卡,单个用户的流式生成速度(Tokens/s)却几乎原地踏步;
- 缓存悖论:前缀缓存(Prefix Cache)命中率已经高达 90%,但用户依然频繁抱怨“响应迟钝”;
- 争用雪崩:一个突发的超长文档分析请求刚进入系统,原本稳定的几十个短文本交互会话的首字延迟便发生断崖式下跌。
深入了解就需要理解自回归(Autoregressive)生成的本质,深入 GPU 底层计算与显存层次结构,理清长短请求在资源调度上的博弈。
1. 模型究竟在算什么?三种核心实体的本质
在自回归生成过程中,模型依赖“下一个词预测(Next-token Prediction)”循环:每一步采样生成 1 个新 token,必须将它拼回上下文,作为下一次模型前向传播的前置输入。
| 核心实体 | 本质定义 | 显存行为规律 | 系统与工程影响 |
|---|---|---|---|
| 模型静态权重 (Model Weights) |
静态只读矩阵(包含 QKV 投影、MLP 层等参数) | 整个推理期常驻显存,不随并发动态增加 | 决定启动模型所需的最小显卡物理显存门槛 |
| 键值缓存 (KV Cache) |
存储自注意力历史所有 Token 对应的 Key/Value 向量 | 随上下文长度与并发请求数严格线性膨胀 | 动态显存杀手,易引发显存碎片、抢占(Preemption)与 OOM |
| 生成输出序列 (Output Tokens) |
词表中采样出的离散 Token ID 序列 | 仅占极小整数索引数组空间 | 本质是自回归迭代的“步数计数器”,直接决定 Decode 总耗时 |
1.1 模型权重(Model Weights):静态的算力载体
- 物理本质:模型的网络参数矩阵(包含 Attention 的 QKV 投影矩阵、O 投影矩阵、MLP 层权重等)。
- 显存特征:静态只读。以 FP16/BF16 精度的 70B 模型为例,参数常驻显存约占用 140 GB(70 × 2)。无论当前服务的并发请求是 1 还是 100,模型权重在单机(或张量并行拓扑)中通常只需加载一份。
1.2 KV Cache(键值缓存):动态显存增长的原因
- 物理本质:在多头自注意力(Self-Attention)计算中,每个 token 都会投影出 Query (Q)、Key (K)、Value (V) 向量。当前第 T 步生成的 token 与历史前 T-1 个 token 交互计算注意力分布时,历史 token 对应的 K 和 V 向量值永远不会改变。
- 显存特征:为了避免每前进一步都把整个历史输入重复运行一遍网络,引擎会在显存中将历史所有 token 的 K 和 V 向量缓存下来。KV Cache 的总体积与
Batch Size × Context Length × Layers × Hidden Dim呈严格线性正比。在 1M 上下文普及的当下,一个并发请求的 KV Cache 就能消耗数十 GB 显存,是引发推理服务 OOM(Out Of Memory)崩溃的首要风险源。
1.3 生成的文本(Output Tokens):决定自回归迭代的轮数
- 物理本质:模型在词表(Vocabulary)离散分布中采样出的 Token ID 数组。
- 显存特征:Token ID 本身只占微乎其微的整型显存空间,但它具有强烈的系统调度属性——模型生成多少个 token,就需要串行执行多少轮 Decode 迭代。
2. 理解 GPU 的两类瓶颈:算力更强的卡为何生成不一定变快?
要透彻解释这个现象,必须借助体系结构中经典的 Roofline 模型(算力-带宽屋顶模型) 与 计算访存比(Arithmetic Intensity,FLOPs/Byte)。
大模型推理被明确切分为两个特征截然相反的阶段:
| 阶段对比项 | Prefill 阶段(预填充 / 计算首字) | Decode 阶段(增量解码 / 逐字吐出) |
|---|---|---|
| 计算对象 | 用户输入的完整 Prompt(N 个 tokens) | 刚生成的上 1 个 token(1 个 token) |
| 核心算子 | 矩阵乘矩阵(GEMM) | 矩阵乘向量(GEMV) |
| 计算访存比 | 极高(高 FLOPs/Byte,参数重用度高) | 极低(低 FLOPs/Byte,参数几乎无重用) |
| 硬件受限类型 | Compute-bound(算力受限) | Memory-bound(显存带宽受限) |
| 物理瓶颈点 | Tensor Core 算力峰值(TFLOPS) | HBM 显存物理读写带宽(GB/s) |
从上面不难看出:Decode 步步都在“等米下锅”
在 Decode 阶段,为生成仅仅 1 个 token,GPU 必须将模型的全部静态参数矩阵从显存(HBM)搬运进芯片内的计算核心(SRAM/Register)一次,完成一次极薄的矩阵向量乘(GEMV)。
以 70B 模型(BF16 占用约 140 GB)在 Batch Size = 1 时为例:
- 每生成一个 token,硬件至少要在 HBM 与计算核心之间搬运 140 GB 的数据;
- 如果显卡的显存带宽为 2 TB/s(2000 GB/s),那么单次搬运耗时下限为:
140 GB / 2000 GB/s = 0.07 秒 = 70 ms; - 换算为生成速率,单流生成的物理天花板仅约为:
1 / 0.07 ≈ 14.28 tokens/s。
如果你从一张显卡切换到另一张计算算力(TFLOPS)提升 3 倍、但显存物理带宽几乎没变的显卡,Decode 阶段的生成速率将毫无起色。因为计算单元绝大部分时间都处于空闲饥饿状态,都在等待显存把参数“运送”到位。
只有当 Batch Size 足够大(通过 Continuous Batching 合并多个会话)时,单次加载的模型权重才能被多个请求共享复用,从而提升计算访存比,硬件才会从 Memory-bound 迁移至 Compute-bound,新型号的高算力优势才得以发挥。
3. 计算与存储的复用:前缀缓存(Prefix Caching)的价值与边界
既然算力与显存搬运麻烦,优化的第一准则必然是消除冗余计算。
3.1 跨请求的前缀复用机制(Radix Attention / APC)
在企业级多租户场景中,大量请求天然共享相同的前缀模式:
- 带有冗长 System Prompt 的统一 Agent 框架;
- 带有统一 Few-shot 样例的结构化抽取任务;
- RAG 架构中共享的行业长知识库或企业制度文档;
- 多轮连续对话的历史会话上下文。
现代推理框架(如 vLLM 的 Automatic Prefix Caching、SGLang 的 RadixAttention)在显存中维护一颗动态前缀树(Radix Tree)。系统以固定大小的 Token 块(Block)计算哈希值,当后续请求到达时,系统若在前缀树中找到完全一致的前缀块,便直接引用显存中现存的 KV Cache,彻底跳过该前缀对应的多层 Transformer 前向计算。
3.2 深度思考:缓存命中率很高,用户为何仍觉得慢?
许多监控面板显示系统的 Prefix Cache 命中率达到了 90% 以上,但始终总有用户依然在中反馈“生成响应非常缓慢”。这背后有两个不可忽视的系统级因素:
- 缓存只砍掉了 Prefill,无法加速 Decode 的串行自回归:前缀缓存直接省下的是“理解长输入”的算力消耗,它能显著缩短首字延迟(TTFT)。但一旦首字吐出,进入后续生成阶段,如果要输出 800 个词,系统依旧要踏踏实实地执行 800 轮单步 Decode 循环。正如前文所述,Decode 受制于显存带宽,无法被缓存抹去。
- 多租户排队与算力资源拥堵:即使某个短请求的前缀 100% 命中了缓存,但在请求进入调度引擎的瞬间,GPU 可能正在全负荷计算数个未命中缓存的万字长请求。调度器在完成当前大型计算批次前无法分派资源,导致即使是命中缓存的轻量请求,也要在队列中承担长尾等待。
4. 高并发下长短请求争用:从资源互斥到精细化调度
在真实的云端生产服务中,长文本任务(如 代码库审查)与短文本任务(如日常聊天问答)通常交织涌入同一实例。这种混合负载会引发极度激烈的底层硬件争用。
4.1 争用现象与危害
- 排头阻塞(Head-of-Line Blocking):长文本 Prefill 是一个极大的 GEMM 密集型任务。如果调度器把整个 16k Prompt 一次性灌入 GPU,它将在数百毫秒乃至数秒内霸占 GPU 所有的流处理器(SM),导致同一卡上并发的所有交互式任务无法进行 Decode 步进,短请求用户会看到屏幕输出骤然定格卡死。
- 显存池挤占与抢占(Preemption):长请求在生成过程中,KV Cache 会持续吞噬剩余显存。当显存池彻底耗尽时,系统为了避免 OOM 崩溃,必须触发抢占机制(Preemption):强行暂停低优先级的请求,将其 KV Cache 换出(Swap)到主机内存(CPU RAM),甚至直接从显存中丢弃。被抢占的请求在显存重新充裕后恢复执行,但往往伴随着灾难性的延迟抖动或重新计算开销。
4.2 Chunked Prefill 与 PagedAttention
| 调度模式 | 执行流水时序 | 硬件算力表现 | 并发短请求体验 |
|---|---|---|---|
| 传统粗粒度调度 (独占整卡) |
[ 8K Prompt Prefill 计算 (独占数秒) ]
↓
|
长 Prompt 计算密集,短期内独占占用 GPU 全部 SM 单元 | 所有其他并发交互请求完全挂起卡顿,打字机输出骤然定格 |
| Chunked Prefill (细粒度切片流水) |
Step 1: [ Chunk 1 (512) + 并发 Decodes ]
↓
↓
|
长文本切片 GEMM 与短请求 GEMV 混合,完全利用 Tensor Core | 短请求在每个切片步长间持续推进,长文本稳健计算,消除定格 |
- Chunked Prefill(分块预填充):调度器不再允许任何长 Prompt 一次性独占执行,而是将其按预设步长(如 512 或 1024 tokens)切片。在每一个调度步长(Step)内,系统将“一个长 Prompt 切片”与“正在等待生成的新一轮并发 Decode”混合打包成一个 Batch 执行。
- 算力利用:切片提供的 GEMM 规模恰好足以把 Tensor Core 算力充分打满;
- 延迟保护:并发的 Decode 请求可以在每个切片步长之间顺畅穿插推进,彻底消灭了长文本带来的排头定格现象。
- PagedAttention(分页式注意力显存管理):借鉴操作系统的虚拟内存分页思想,将 KV Cache 拆解为固定大小的离散内存页(Blocks)。物理显存不再需要为每个请求预留连续空间,彻底消除了显存外部碎片,使系统能安全地将显存水位压榨至 95% 以上,大幅降低了显存争用引发的抢占(Preemption)概率。
5. 性能指标究竟在衡量什么?
要科学评测大模型推理系统的表现,传统的 QPS 和平均延时指标已经完全失效,业界普遍采用三大黄金维度:
| 指标全称 | 缩写 | 物理定义 | 业务感知映射 |
|---|---|---|---|
| Time to First Token | TTFT | 从发出请求到客户端收到第 1 个字符的时间 | 系统启动灵敏度。决定用户点击发送后是否感觉“系统卡住”。受排队时延、Prompt 长度、前缀缓存命中率直接影响。 |
| Inter-Token Latency | ITL | 流式传输过程中,连续两个 token 到达的间隔时间 | 打字机输出的平滑度与卡顿感。ITL 平均值低但 P99 极高意味着肉眼可见的“吐字一卡一顿”。 |
| Time Per Output Token | TPOT | 剔除首字后,整个 Decode 阶段耗时除以生成 Token 总数 | 实际输出吞吐速率。1 / TPOT 即为每秒吐字数(tokens/s),决定完整答案的交付总时长。 |
5.2 从离线负载 Trace 到真实 GPU 服务区别
真实生产流量 Trace 通常至少包含:arrival_time(到达时间)、input_len(输入长度)、output_len(输出长度)、prefix_block_hash(前缀哈希)。
- 离线 Trace 能分析出的:理论前缀命中率、无调度损耗下的理论算力上限、全显存理想分布下的吞吐天花板。
- 真实 GPU 实例上进行压力测试重点是什么:
- 算子混合执行的真实硬件退化:Chunked Prefill 将 GEMM 与 GEMV 强行融合执行时,GPU 计算单元管线切换引发的实际流水线损耗;
- 分布式张量并行通信阻塞:跨卡跨节点(NVLink / InfiniBand)在 All-Reduce 与 Attention 同步时的物理通信时延;
- KV Cache 换入换出的 IO 瓶颈:显存吃紧触发 Preemption 时,通过 PCIe 往返搬运 KV Cache 到 Host 内存产生的真实性能断崖;
- 极端负载下的长尾延迟恶化:排队队头阻塞与前缀树驱逐抖动叠加引发的真实 P99 TTFT 与 P99 ITL。
6. 小作业的答案
Q1:一个长请求进来以后,短请求为什么可能变慢?
- 算力层面:长 Prompt 的 Prefill 计算量巨大。若未采用切片技术,会直接独占 GPU 计算单元,让短请求在队列中遭遇排头阻塞;
- 显存层面:长请求需要申请海量 KV Cache,会迅速掠夺剩余显存池。系统触发抢占(Preemption)将短请求的会话移出显存甚至强行重算,直接破坏了短请求的流式平滑度。
Q2:开启缓存以后,哪些成本减少了?哪些等待依然存在?
- 确切削减的成本:命中前缀的巨大 Prefill 浮点计算量(FLOPs)被直接抹平;首次响应的排队与计算时间大幅压缩,TTFT 显著降低;集群总吞吐上限提升。
- 依然存在的等待:
- 逐字生成的物理带宽等待:生成阶段每一步依然要遍历模型参数,受显存物理带宽约束,Decode 生成速率无法仅凭缓存得到质的飞跃;
- 全新内容的计算等待:未命中前缀的自定义上下文依然需要扎扎实实地跑完整 Prefill;
- 集群高并发下的调度排队等待:当整卡显存或批处理队列被压满时,轻量请求依然需要排队等候入场。
附录:核心术语与概念速查表
本文涉及的大语言模型推理、硬件体系结构与系统调度核心术语中英文对照及工程定义如下:
| 英文名词 / 缩写 | 中文对照 | 范畴分类 | 定义 |
|---|---|---|---|
| Autoregressive | 自回归 | 算法机制 | 文本生成的串行范式:每一步模型预测出一个新 token,必须拼入上下文作为下一次前向计算的输入。 |
| KV Cache | 键值缓存 | 算法与显存 | 在自注意力计算中,将历史所有 token 的 Key 和 Value 向量缓存在显存中,避免每步生成都要重复投影历史数据。 |
| Prefill | 预填充 / 首字计算阶段 | 推理阶段 | 一次性处理用户输入的完整 Prompt,计算并生成其对应的全部 KV Cache 及首个生成 token 的阶段。 |
| Decode | 增量解码 / 逐字吐字阶段 | 推理阶段 | 每次仅输入最新生成的 1 个 token,复用历史 KV Cache 迭代预测下一个 token 的自回归串行阶段。 |
| GEMM / GEMV | 通用矩阵乘 / 矩阵向量乘 | 底层算子 | GEMM 计算密度高,多用于 Prefill 阶段;GEMV 访存开销占比极大,多见于低并发 Decode 阶段。 |
| Arithmetic Intensity | 计算访存比 / 运算强度 | 体系结构 | 单位内存数据访问量所对应的浮点运算次数(FLOPs/Byte),用于判断计算处于“算力受限”还是“带宽受限”。 |
| Roofline Model | 屋顶模型 | 体系结构 | 体系结构中用于分析特定负载受硬件峰值算力(Compute Bound)还是显存带宽(Memory Bound)制约的可视化分析框架。 |
| Memory-bound | 显存带宽受限 / 访存受限 | 性能瓶颈 | 计算核心处于饥饿闲置状态,系统吞吐与延迟主要卡在数据从显存(HBM)向片上计算核心(SRAM)传输的物理速率上。 |
| Compute-bound | 算力受限 | 性能瓶颈 | 显存数据供应充足,系统性能瓶颈主要受限于 GPU Tensor Core 等执行单元的峰值浮点运算能力(TFLOPS)。 |
| Continuous Batching | 连续批处理 / 动态批处理 | 调度算法 | 在每一步迭代完成后,动态剔除已结束的请求并合并新到达的请求,消除静态批处理中长短木桶效应导致的 GPU 算力浪费。 |
| APC / Radix Attention | 自动前缀缓存 / 基数树注意力 | 缓存机制 | 将公共 Prompt(系统指令、Few-shot、知识库文档等)分块哈希并以前缀树维护,命中时直接复用已有的 KV Cache。 |
| PagedAttention | 分页注意力机制 | 显存管理 | 借鉴操作系统的虚拟内存分页思想,将 KV Cache 切为固定大小的离散页块(Blocks),彻底消灭显存外部碎片。 |
| Chunked Prefill | 分块预填充 | 调度算法 | 将长 Prompt 切分为若干固定长度的切片(Chunk),与等待推进的 Decode 混合打包执行,兼顾算力打满与低响应延迟。 |
| Head-of-Line Blocking | 排头阻塞 | 调度问题 | 队列前方的长文本 Prefill 密集任务霸占硬件计算资源,导致排在后面的轻量短请求被长时间挂起等待。 |
| Preemption | 抢占 / 调度抢占 | 资源调度 | 显存耗尽时,系统强制暂停低优先级请求,将其 KV Cache 换出到主机内存(Swap)或丢弃重算以避免系统崩溃。 |
| TTFT | 首字延迟 | 性能指标 | Time to First Token。用户点击发送至客户端收到第 1 个 Token 的耗时,反映系统的启动灵敏度。 |
| ITL | 字符间延迟 / 吐字间隔 | 性能指标 | Inter-Token Latency。流式输出中相邻两个 Token 到达的时间间隔,衡量打字机效果的平滑度与卡顿感。 |
| TPOT | 单字生成耗时 | 性能指标 | Time Per Output Token。除首字外的 Decode 阶段总耗时除以生成 Token 数,倒数即为实际吐字速率(Tokens/s)。 |
| Trace | 运行轨迹 / 负载追踪 | 性能评测 | 生产环境中捕获的请求序列记录(包含到达时间戳、输入长度、输出长度、前缀哈希等),用于离线重放与容量评估。 |
文章评论