跳到主要内容

AI 推理的突发容量规划:当黑色星期五遇上你的 KV Cache

· 阅读需 12 分钟
Tian Pan
Software Engineer

黑色星期五的流量峰值来了。传统 API 服务的应对方式是启动更多容器。60 秒之内,你的容量就扩充到三倍。自动扩缩容器做了它一贯的事,你安然入睡。

但如果用同一个自动扩缩容器跑 LLM,结果就大相径庭了。新的 GPU 实例要在四分钟的模型权重加载之后才能上线。等那时候,你的请求队列已经塞满,现有 GPU 在半途生成的请求的内存压力下颠簸挣扎,用户盯着转圈圈的加载动画发呆。增加更多算力没有任何帮助——瓶颈根本不在你以为的地方。

AI 推理负载打破了让响应式自动扩缩容在传统服务中奏效的大多数假设。理解其中的原因,是构建能够扛住流量峰值的系统的前提。

为什么 LLM 不只是慢 API

根本区别在于:LLM 推理在生成过程中是有状态的,状态存在于 GPU 内存中。每个活跃请求都持有一个实时的键值(KV)Cache——一种按请求存储的内存结构,记录了到目前为止每个已生成 Token 的中间注意力计算结果。对于处理 4096 个 Token 上下文的 70B 参数模型而言,每个请求的 KV Cache 会消耗数 GB 的 GPU 内存。

这带来了一个传统容量规划完全忽视的后果:在计算资源仅使用了 40% 的情况下,内存就可能已经耗尽

对于无状态 API,增加实例后请求会分散到各实例上。但对于 LLM 推理,新实例对正在处理中的请求毫无帮助。每个活跃的生成任务都占据着无法迁移、共享或压缩(不中断请求的前提下)的内存。当一批长上下文请求同时涌来时,它们会在填满 GPU 计算之前先填满 GPU 内存。新请求之所以排队,不是因为 GPU 在忙,而是因为没有地方放它们的 KV Cache。

那套为 REST API 设计的自动扩缩容数学逻辑,依赖于请求独立性和无状态计算这两个前提。两者在这里都不成立。

KV Cache 才是真正的瓶颈

要正确规划突发容量,你需要用内存来思考,而不是请求数。

每个并发请求持有的内存与其序列长度和模型层数成正比。对于 13B 参数模型,单个 8K Token 的上下文可能需要 1.5–3 GB 的 KV Cache 内存。一块 80 GB 显存的 GPU,在加载模型权重后,可能只有 30–40 GB 留给 KV Cache,无论有多少 CUDA 核心空闲,最多只能同时处理 10–20 个长上下文请求。

流量峰值到来时,这意味着:

  • 请求并发量受内存限制,而非 FLOPS。
  • 给现有实例增加更多 GPU 计算没有意义。
  • 队列被等待内存释放的请求填满,而不是等待 CPU 空闲。
  • 已排队请求等待现有生成任务完成并释放 KV Cache 分配,延迟因此攀升。

输入/输出的 Token 数量在实践中差异极大。用户聊天消息可能只有 50 个 Token,文档摘要任务可能有 12000 个 Token。一个长上下文请求消耗的内存预算,相当于 80 个短请求。这使得突发容量规划是概率性而非确定性的——你在对一个分布建模,而不是在计算固定成本。

LLM 服务中"容量"的真正含义

规划峰值时,你需要对三个独立上限建模:

内存容量:整个服务集群可用的 KV Cache 总内存。这决定了在你的典型上下文长度分布下,最大并发请求深度。

计算吞吐量:集群每秒能生成的 Token 数。这决定了进行中的请求完成并释放 KV Cache 的速度,进而影响队列清空速率。

冷启动延迟:新实例从启动到可接受请求所需的时间。对于 LLM,这包括容器镜像拉取(数分钟)、模型权重加载(数分钟)以及运行时初始化。相比之下,无状态服务的新容器几秒钟就能就绪。

这三者之间的相互作用,正是峰值如此危险的原因。峰值增加了队列深度(受内存容量限制),减缓了清空速率(因为排队请求也在竞争计算资源),同时触发了自动扩缩容——但新容量要四到八分钟后才能到位。在新容量上线之前,系统可能已经越陷越深。

对比传统服务:无状态 API 自动扩缩容时,新实例数秒内就绪,队列迅速清空,系统快速恢复。而 LLM 推理的恢复延迟则是一个数量级之长。

可预测峰值的容量规划计算

对于可预测的流量事件——定时批量任务、产品发布、营销活动——你可以在事件之前进行确定性容量规划。

从预期的 Token 预算入手。估算峰值请求量,乘以你的 p95 上下文长度,计算出峰值窗口内需要处理的总 Token 数。除以你的 GPU 集群实测的每秒 Token 吞吐量。再加上足够的余量以应对排队动态,通常是 1.5–2 倍,以应对不均匀的到达模式和长尾上下文长度。

一个实际案例:你预计在 15 分钟的峰值窗口内有 500 个并发用户,每人发送一个 1000 Token 的提示并收到 500 Token 的回复。总计 75 万个 Token。你的服务集群在所有 GPU 上合计每秒产出 20000 个 Token。简单计算说明你需要 37 秒的持续生成——但这假设了请求完美批处理。实际上,排队和内存压力会拉长这个窗口。规划时应取 2–3 倍:在峰值窗口内将集群规模调整为每秒 60000–90000 个 Token,峰值过后再缩回。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates