AI Infra 学习路线 · 阶段三 · 推理线 · 核心原理
面试高频题。纯理论,不依赖卡性能,理解即可
底子复用:阶段二显存账(KV cache 占显存)+ 阶段一 OS 分页概念
一、PagedAttention(管显存)
1. 要解决的问题:朴素管 KV cache 浪费巨大
背景:decode 时 KV cache 不断增长(每生成 1 token 追加一份 K/V),而事先不知道一个请求会生成多长。
朴素做法(vLLM 之前):为每个请求预留一块按最大长度算的连续显存(如模型最大 2048,就预留能装 2048 token 的连续空间)。
两种浪费(面试术语):
- 内部碎片 internal fragmentation:预留 2048 但实际只生成 50 → 剩 1998 的空间白占。
- 外部碎片 external fragmentation:每个请求要连续大空间 → 显存被切成大小不一的块,新请求即使总空闲够,也找不到足够大的连续空间。
结果:KV cache 显存利用率仅20%-40%,六七成被碎片浪费。而显存是推理命根子(KV cache 越大越能支持长序列/高并发)→ 浪费显存 = 限制并发和上下文长度。
2. 方案:照搬操作系统分页(名字由来)
OS 分页核心:不要求连续。内存切成固定大小页,按需给页,物理上可分散,用页表记录逻辑→物理映射。
PagedAttention 照搬:
- KV cache 切成固定大小的块 block(如每块存 16 个 token 的 K/V)。
- 请求的 KV cache按需一块块分配(生成 16 token 占一块,再生成再要),物理上可分散。
- 请求结束,占的块立刻释放还给池子。
- 用块表 block table记录"请求第 N 段 token 在哪个物理块" = OS 页表的翻版。
对应关系:
| 操作系统 | PagedAttention |
|---|---|
| 物理内存页 page | KV cache 块 block(存 N 个 token 的 K/V) |
| 页表 page table | 块表 block table |
| 进程逻辑地址空间 | 一个请求的 KV 序列 |
3. 为什么解决了浪费
- 消灭内部碎片:按需分配,答 50 token 只占 4 块(50÷16),浪费最多是最后一块没填满的几个 token(从"浪费 1998"→"浪费几个")。
- 消灭外部碎片:块固定大小,任何空闲块都能给任何请求用,不存在"找不到连续大空间"。
- 利用率从 20-40% →接近 100%→ 同显存装下更多请求 KV cache → 并发/序列长度大幅提升 → 吞吐大增。
4. 额外红利:块可共享(prefix caching 的基础)
既然靠块表映射,多个请求若有相同前缀(如同一段 system prompt),这段前缀 KV 一样 →共用同几个物理块,不各存一份。
= vLLM 日志里enable_prefix_caching=True的底层。省显存 + 省重复计算前缀的时间。
(对应 OS 里多进程共享同一物理页,如共享库。)
面试标准答法
PagedAttention 把 KV cache 切成固定块、按需非连续分配、用块表做映射,借鉴 OS 分页消除内部/外部碎片,使显存利用率接近 100%,从而支撑更高并发和更长序列。额外好处:块可共享,相同前缀的请求共用块(prefix caching)。
二、Continuous Batching(管调度)
1. 要解决的问题:静态批处理的"等"浪费
静态批处理(之前测 batch 的方式):凑一批,一起开始、一起跑完。实验里 OK,但真实场景:
- 请求陆续到达(用户不同时刻发)。
- 生成长度差异巨大(有人答 20 token,有人答 800)。
两种浪费:
- 等齐才开始:凑批要等够数,先到的请求干等凑齐才开工 → 延迟高。
- 等最慢才结束(最致命):整批必须等最慢的(答 800 的)跑完才释放。早完成的(答 20 的)陪跑空占位置到整批结束,GPU 算力/显存被"已完成却走不了"的请求白占。
比喻:拼车非要坐满才发车、所有人到终点才让下车。
2. 方案:动态进出的池子
continuous batching(也叫 in-flight batching):去掉"批"的固定概念,改成动态池子,调度器在每一步生成(每个 token 迭代)重新审视:
- 谁完成了,立刻踢出、释放其位置和 KV cache 块。
- 有空位,立刻把排队的新请求塞进来。
"批"时刻变化:每步都可能有请求进/出,GPU始终满载,无"等齐"也无"陪跑"浪费。
比喻:网约车随上随下,到站即下空位,等车的即上补位,始终坐满。
3. 效果
消除两种浪费 → GPU 每一刻被喂满 → 吞吐大增。这是 vLLM 高吞吐的另一半来源(配合 PagedAttention)。
面试标准答法
Continuous batching 在每个生成步动态调度请求,完成即释放、新请求即加入,消除静态批处理的"等齐开始"和"等最慢结束"两种浪费,让 GPU 持续满载。它依赖 PagedAttention 的灵活显存管理才能实现。
三、两大法宝如何配合 ★(关键,很多人答不全)
continuous batching 的"随时进出"依赖 PagedAttention 的"灵活显存管理"。
原因:请求要能随时加入/释放,其 KV cache 显存就必须能灵活、按需、非连续地分配回收。若还是静态那种"预留连续大块",请求走了留下特定大小的连续空洞,新请求未必塞得进(外部碎片)。PagedAttention 把 KV cache 切成统一小块、按需分配回收 → 请求一结束块立刻进池 → 新请求随时凑块加入。
一句话:调度的灵活性,建立在显存管理的灵活性之上。
- PagedAttention 管"显存怎么高效分配回收"。
- continuous batching 管"请求怎么高效调度进出"。
- 后者建立在前者之上 → 所以两大法宝总是一起出现。
四、推理线理论脉络(层层咬合)
KV cache(模块一:推理为何吃显存)
→ PagedAttention(怎么高效管这块显存)
→ continuous batching(在高效显存管理之上怎么高效调度请求)
→ 共同目标:把 GPU 喂满、把显存用尽,换最大吞吐
→ 接回总主线:瓶颈在数据/资源的管理,不在算力
待动手(需好性能才有意义,涉及那个压测决策)
- 压测调参(吞吐/延迟/TTFT,gpu_memory_utilization/max_num_seqs)
- vllm serve 起 OpenAI 兼容 API server(真正的"部署")
- 量化部署(AWQ/GPTQ/FP8)对比
- 决策点:vLLM 在本卡性能残废(JIT+关FlashInfer),压测数据用"死磕后的vLLM"还是"又快又稳的transformers"出