# vLLM不要迷信PagedAttention神话,聊聊线上藏着的内部碎片陷阱

做推理基建久了,很多掘友应该听过这套说法:上vLLM,打开PagedAttention,显存碎片直接原地消失,GPU利用率直接拉满起飞。最开始我也是被这套宣传洗脑,压测环境跑出来数据漂漂亮亮,感觉这下可以把显存吃干榨尽,结果上生产跑个一两天,就开始遇到各种邪门现象。

理想环境和真实业务中间隔了一道鸿沟

先说原理,PagedAttention借鉴操作系统虚拟内存思路,把整块KV‑Cache切为固定大小的gpu block,不再给每个请求分配连续显存块,依靠block table做间接寻址,以此解决传统推理框架外部显存碎片化问题。

在基准测试集ShareGPT里面效果确实亮眼,外部碎片几乎清零,很多博客文章讲到这里就戛然而止,很少往下聊**内部碎片(internal fragmentation)**这个坑。

简单白话解释一下:block_size一般默认16 token。假如一个对话生成只输出10个token,依然要占完整一个block,剩下6个token位置直接空着,这块显存不能借给别的请求使用。这就是内部碎片,每个请求尾巴都会吃掉一部分闲置显存空间。

测试集里面大多是长会话样本,单请求token数很大,单块内闲置占比很低,碎片问题几乎看不见。一旦业务场景大量短query,比如RAG抽取、工具调用、短问答,成千上万并发请求堆上来,零零碎碎的尾部空位就会不断累积。外部碎片消灭了,但内部碎片悄悄蚕食你的VRAM。

线上会出现哪些迷惑性故障现象

最折磨人的就是那种渐进式恶化,刚重启实例一切正常,吞吐、TTFT都很漂亮,跑大半天之后慢慢变坏,并不是一上来直接OOM炸服务。

  1. 显卡看nvidia‑smi显存占用还没顶满,但是block池已经快要耗尽,调度器被迫触发preemption抢占,把正在运行的请求踢掉做重计算recompute。业务侧看到就是P99延迟随机飙升,普通请求时不时卡顿一下,日志翻一遍又看不到明确OOM报错,排查很容易走偏,以为是带宽或者CUDA kernel问题。
  2. 盲目调大gpu_memory_utilization参数,直接拉到0.95。很多新手觉得这个值越高越好。这个参数是预留给KV block池的显存占比,没有预留足够空间给prefill峰值、NCCL通信buffer以及中间activation张量。遇到一波长prompt突刺流量,瞬间直接爆OOM实例crash,整套推理服务直接重启。一般生产环境我习惯先从0.85起步,压测充分之后再慢慢往上试探,不要直接抄网上示例配置。
  3. 调大block_size试图减少block管理开销,结果适得其反。block越大,每一块里面的内部碎片就越可观。短请求占比高的业务,盲目开大block_size等于变相持续浪费显存资源。

这里插一句黑话,很多人压测只看稳态吞吐量,忽略碎片带来的隐性损耗。压测脚本都是理想化流量,现实业务是长短请求大杂烩,这就是本地压测和生产环境之间最大的一道代沟。

可以落地的几手调优手段,没有银弹

  • 业务侧尽量统计真实请求序列长度分布,搞清楚你的业务到底长会话多还是短query占大头。如果短请求占比很高,就要对内部碎片留余量评估,不要拿论文指标直接当做上线依据。
  • 监控不要只盯着GPU显存使用率,务必把vLLM暴露出来的metrics拉起来:vllm_num_gpu_blocks_used、vllm_preemption_count。preemption计数持续上涨是非常重要告警信号,比单纯看显存百分比更有参考价值。一旦这个指标疯狂涨,说明block池已经吃紧,要么降并发上限,要么扩容显存资源。
  • 开启chunked‑prefill,避免个别超长prefill请求垄断GPU资源,把其他请求全部堵在队列里面。但也要留意,这个特性会引入调度逻辑开销,上线前要做对比压测。
  • prefix‑caching可以开启,利用公共system prompt做KV块复用,降低新请求prefill开销,但也要注意引用计数ref‑cnt异常泄漏的潜在风险,版本迭代时不时踩过小坑。

这里要澄清,不是说PagedAttention不行,恰恰相反它是目前工业界非常靠谱的方案。只是网上很多教程把它塑造成解决一切显存问题的万能解药。它解决的主要是外部碎片,内部碎片问题依然客观存在,需要工程师自己去做权衡取舍。

做推理基建久了越来越有体会,很多组件都没有完美版本,论文、开源demo给你的往往是最优case,我们做工程就是不断和各种边角case博弈。

有时候线上出问题,排查半天,最后只是各种细碎损耗叠加出来的结果,并不是某个重大bug。重启实例可以临时缓解碎片带来的症状,但重启属于治标不治本,不能当做常态化解决方案。

平时我排障的时候,一般先看metrics,再看流量分布,再怀疑组件bug,顺序别搞反。

欢迎评论聊聊你们线上vLLM踩过哪些稀奇古怪坑。

相关推荐
xn71331 小时前
EmbeddingGemma 2 270M 实测:278 Chunk、32 个查询与 RRF 反例
人工智能·后端·架构
SL_staff1 小时前
目标健康度自检清单:开发者视角下的目标-计划-任务链路断点诊断
java·开源·github
for_ever_love__1 小时前
MySQL 高频面试题 30 问:索引、事务、锁、日志、主从与分库分表(MySQL 8.0 版)
java·数据库·spring boot·mysql·spring cloud·面试·总结
神仙别闹1 小时前
基于C++实现的贪吃蛇游戏平台
java·c++·游戏
漠野9231 小时前
画布的保存按钮背后,站着一个编译器
架构
两万五千个小时1 小时前
DeepSeek Harness 从 0 开始:20 goal模式
人工智能·程序员·架构
漠野9231 小时前
让每个节点自己决定:要不要跑,还是循环跑
架构
dcacheor1 小时前
现代桌面播放器的交互困境与架构演进:从单窗流媒体走向多模态视讯工作台
架构
布吉岛的石头1 小时前
Java 程序员第 49 阶段11:Java 接 BERT:用 ONNX Runtime 做句向量推理
java·人工智能·python·深度学习·bert·transformer