文章标题:现实世界中的 KVCache 缓存:在大型云服务商中表征与优化 KVCache 缓存
作者/机构:Jiahao Wang†1, Jinbo Han†1, Xingda Wei 1, Sijie Shen2, Dingyan Zhang1, Chenguang Fang2, Rong Chen1, Wenyuan Yu2, and Haibo Chen1
1上海交通大学并行与分布式系统研究所 2阿里巴巴集团

A1 主要贡献

本文针对大型语言模型(LLM)服务中的一个关键性能优化技术——KV Cache(KV$)缓存,进行了首次系统性的生产环境工作负载特征分析。研究的核心问题在于,尽管KV$缓存能显著提升服务吞吐量和延迟,但业界对于其在真实工作负载下的效益以及如何设计最优的系统(如缓存驱逐策略)缺乏深入理解,现有研究多依赖于合成工作负载,无法反映真实场景的复杂性。

研究目标
1. 通过分析来自全球顶尖云服务商(阿里云)的真实生产环境 traces(包括 to-C 聊天机器人和 to-B API调用两种典型场景),深入刻画LLM服务的KV$工作负载模式。 2. 基于特征分析的发现,设计并实现一种工作负载感知的缓存驱逐策略,以在真实世界负载下,尤其是在缓存容量有限的情况下,提升服务性能。 **核心创新点与发现**: 本文通过对大规模生产环境数据的详细分析,得出了几个与以往研究不同的关键观察: 1. **KV$复用普遍但分布倾斜,单轮请求复用同等重要:真实负载中KV$复用很常见,但复用率低于合成数据集的报告值。复用表现出高度倾斜的分布,10%的KV$块贡献了77%的复用。与直觉相反,多轮对话请求并非总是复用的主要贡献者;在to-B负载中,单轮API请求贡献了高达97%的KV$复用。 2. **KV$复用模式在类别内可预测:尽管从全局看,所有请求的复用时间和复用概率呈现多样性,但如果将请求按类别(如API调用、聊天;单轮、多轮)划分,特定类别内的复用模式(如复用时间)趋于稳定和可预测。这为设计感知工作负载的缓存策略提供了依据。
3. KV$生命周期短暂,所需缓存容量适中**:KV$的生命周期非常短(例如,to-B负载中P99生命周期为97秒),这意味着为达到理想缓存命中率所需的总缓存大小是适中的。例如,对于采用GQA模型的to-B工作负载,每个GPU只需配备相当于其HBM两倍大小的KV$缓存容量,即可使用标准LRU策略接近无限容量下的理想命中率。 基于以上发现,本文提出了一种**工作负载感知的KV$缓存驱逐策略。该策略利用分析出的各类工作负载的复用概率分布来决定缓存块的优先级,从而在真实追踪数据上,特别是在缓存容量受限时,显著提高了缓存命中率和平均响应时间。

下表对比了当前可用的LLM服务追踪数据,凸显了本文所用数据的深度和规模。
Table 1: 对当前可用的LLM服务追踪数据的比较。Time是每个请求的调用时间。Type是请求类型,例如是否为API调用。UID是调用请求的用户ID。Turn是请求的多轮信息。Content是每个请求的(匿名)输入和输出token。

A3 背景知识与关键观察

LLM服务、KVCache、KVCache缓存及多轮服务背景

LLM服务流程。大型语言模型(LLM)以自回归的方式处理请求。如图1所示,对于一个或一批请求(每个请求包含多个token,即prompt),模型首先执行一个prefill阶段(❶),通过一次前向传播生成第一个token。随后,模型进入decoding阶段(❷),通过多次前向传播迭代地生成剩余的token,直到输出序列结束(EOS)token。在每次迭代中,输入都包含原始prompt和所有先前已生成的token。


Figure 1: LLM处理请求的示意图。

**KVCache (KV$)**。LLM的一次前向传播包含三个步骤,如图2所示:(1)通过矩阵乘法计算Q、K、V矩阵;(2)使用Q和K推导出注意力分数;(3)将注意力分数与V矩阵结合产生注意力结果。这些步骤计算量巨大。由于具有相同token的输入会共享相同的K和V矩阵(见❶),所有LLM服务系统都会在GPU上缓存prefill阶段生成的K和V矩阵以节省计算时间。这些缓存的K和V矩阵在处理同一请求的decode阶段被复用,以避免重复计算,因此被称为KV$。

KV$缓存与KV$块。除了在处理单个请求的prefill和decode阶段之间复用KV$外,如果不同请求共享相同的前缀token,KV$也可以在这些请求之间复用。如图2(❷)所示,“A paper on”的K和V值对于#Req0和#Req1是相同的。因此,即使#Req0完成解码,我们仍然可以缓存其KV$以供#Req1使用,这极大地改善了#Req1的响应时间(即首token时间,TTFT):它在prefill阶段只需计算“AI is”的K和V。KV$缓存通过节省计算量进一步提高了服务吞
吐量。鉴于此,现有服务系统都会缓存已完成请求的KV$。我们将此方法称为KV$缓存【索引29,vLLM: Efficient Memory Management for Large Language Model Serving with PagedAttention,2023,SOSP】【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】【索引19,Prompt Cache: Modular Attention Reuse for Low-Latency Inference,2024,MLSys】【索引68,Efficiently programming large language models using sglang,2023,CoRR】【索引25,Ragcache: Efficient knowledge caching for retrieval-augmented generation,2024,CoRR】【索引36,Cachegen: KV cache compression and streaming for fast large language model serving,2024,ACM SIGCOMM】【索引64,Stateful Large Language Model Serving with Pensieve,2023,CoRR】,尽管也存在其他名称如前缀缓存或prompt缓存。KV$可以被缓存在GPU内存、主机内存(或远程机器内存),甚至SSD上。由于在token级别检查前缀匹配可能成本高昂,现有KV$系统的缓存粒度是块(block),每个块包含可配置数量token的KV。例如,vLLM【索引29,vLLM: Efficient Memory Management for Large Language Model Serving with PagedAttention,2023,SOSP】默认将16个token分组为一个块。


Figure 2: 展示了:❶ 一个预填充请求(Req#0)的KV$如何被Req#0的解码过程复用,以及 ❷ KV$如何被未来一个请求(Req#1)的预填充过程复用。

多轮服务。通过多轮对话与LLM交互是提升服务质量的常见模式【索引57,Autogen: Enabling next-gen llm applications via multi-agent conversations,2024,First Conference on Language Modeling】【索引55,Mint: Evaluating llms in multi-turn interaction with tools and language feedback,2023,arXiv】。具体来说,用户在收到LLM的生成内容后,可能会带着新的prompt发出下一轮请求。由于LLM需要之前的对话上下文进行处理,服务系统会将之前轮次的请求输入和输出拼接到新请求的输入之前,然后将这个新的输入送入LLM进行服务。为了方便管理多轮请求的历史,一个多轮对话中的请求通常被分组在一个会话(session)中。多轮请求自然会复用前几轮的KV$,因为当前的LLM系统会有意将历史输入和输出作为前缀附加到每个新请求上。 ### 现实世界中的KV$工作负载特征

3.1 追踪数据收集

数据来源与匿名化处理。我们收集并分析了来自阿里云通义(ALIYUN TONGYI)一个服务集群的两周(2025年2月和2024年12月)LLM服务请求追踪数据。为简洁起见,本文展示了每个trace中具有代表性的一天的数据,其结果在整个工作周内保持一致。由于阿里云严格的隐私政策,我们无法收集每个请求的原始输入和输出。对于一个特定的trace,其所有收集到的请求都由同一模型提供服务。我们首先描述由服务集群运维团队提供的详细匿名化追踪记录,然后重点介绍两种代表了当今典型服务工作负载的trace之间的差异。图3展示了一条收集到的请求记录的结构:
1. 时间戳(Timestamp): 服务集群接收到请求的时间。
2. 对话ID(Chat ID): 请求的唯一标识符。
3. 父对话ID(Parent Chat ID): 对于多轮会话中的请求,服务系统会为每个请求分配一个父ID,将其链接到会话中的前一个请求。通过遍历父ID,我们可以识别出属于同一会话的所有请求。如果父ID为空,则该请求是会话的第一轮,我们称之为单轮请求(single-turn request)。否则,我们称带有非空父ID的请求为多轮请求(multi-turn request)。
4. 用户ID(User ID): 提交请求的用户的唯一ID。为保护隐私,这些ID被映射到一个随机选择的域。
5. 请求类型(Request type): 服务网关将LLM请求分为五类:Text(通过ChatBot等接口输入的纯文本)、File(文件分析,如使用LLM总结文档内容)、Multimodal(通过OCR增强处理的图像理解)、Search(集成了网络搜索以增强知识的前端)、API(通过与OpenAI兼容的接口进行程序化访问【索引41,Openai developer platform】)。
6. 输入/输出Token数量: 提供给LLM的输入token数量和其生成的输出token数量。
7. 输入/输出token的哈希值: 由于严格的隐私政策,运行时系统通过加盐哈希和域重映射来生成追踪数据。具体来说,收集器采用SipHash【索引8,Siphash: A fast short-input PRF,2012,INDOCRYPT】为每四个连续的token生成唯一的哈希值,每个trace使用随机盐,然后将哈希ID重映射为连续的自然数。这种细粒度的哈希方式相比单token哈希,能够在增强隐私保护的同时,进行更细粒度的缓存分析。


Figure 3: 一个收集到的追踪记录示例。

Trace A vs. Trace B。我们收集了两种追踪数据(A和B),代表两种典型的LLM服务工作负载。Trace A代表一个常见的to-C(面向消费者)场景,用户通过云端构建的服务与模型交互,如ChatBot(Text类型)或文件/多模态/搜索服务。to-C工作负载的一个关键特征是通常有人类参与其中(human-in-the-loop)。Trace B代表一个to-B(面向企业)工作负载,商业用户通过计算机程序调用云端托管的与OpenAI兼容的API与LLM交互【索引41,Openai developer platform】。API调用对商业用户至关重要,因为他们可以系统地利用LLM自动化任务,如文档翻译或用户请求分类。Trace B没有请求类型信息,因为与当前其他供应商提供的LLM接口调用类似【索引41,Openai developer platform】【索引20,Gemini api,2025】【索引4,Claude api,2025】,这些信息在客户端被拼接。

3.2 现实世界中的KV$复用分析 **KV$的可复用性**。图4展示了两种追踪数据在理想情况下的缓存命中率,即假设缓存容量无限。可以看出,LLM工作负载可以从缓存中受益——在Trace A和B上分别有62%和54%的命中率。命中率的计算方式如下:对于一个trace中LLM需要计算的总共N个KV$块,如果命中率为62%,这意味着这N个块中的62%可以复用先前请求计算并缓存的KV$。虽然理想命中率很高,但它低于在合成工作负载上报告的命中率(例如,超过80%【索引64,Stateful Large Language Model Serving with Pensieve,2023,CoRR】【索引68,Efficiently programming large language models using sglang,2023,CoRR】【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】)。


Figure 4: 在真实世界LLM服务工作负载下一天内KV$缓存的理想缓存命中率分析。报告的访问和命中块数已进行归一化处理。 **单轮和多轮请求对KV$复用的同等重要性**。虽然普遍认为多轮请求是缓存命中的主要贡献者【索引64,Stateful Large Language Model Serving with Pensieve,2023,CoRR】【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】,但在to-B工作负载(Trace B)上情况并非如此。图5显示了每种请求类型的贡献及其多轮比例。对于Trace A,它主要由聊天机器人发送的请求(78%)主导,除了多模态请求外,所有请求类型都有相似的多轮比例(47-51%)。对于Trace B,它只有API请求,且多轮比例可忽略不计(小于0.1%)。然而,单轮请求为Trace B贡献了97%的总缓存命中。

Figure 5: 我们收集的追踪数据中请求的工作负载类型和多轮比例。

单轮API请求在to-B工作负载中主导命中的原因。这主要有两个原因。首先,LLM API请求通过共同的系统提示(system prompts)共享KV$。具体来说,每个请求包括:(1)提供任务指令的系统提示(例如,文档翻译指南)和(2)包含特定请求数据的用户提示(例如,目标文档)。当程序进行API调用时【索引34,Parrot: Efficient serving of llm-based applications with semantic variable,2024,OSDI】,它们通常在程序中硬编码相同的系统提示,从而使得即使是单轮请求,也能在不同请求间共享KV$。其次,API请求通常表现出快速的提交率(例如,>10 QPS),这使得能够频繁复用来自系统提示的相同共享KV$。 **跨用户KV$命中罕见。图6展示了在无限大小KV$缓存假设下,用户之间的缓存命中热力图。颜色越深表示归一化后的命中次数越高。我们可以看到,对于每个用户,大多数命中都来自他们自己提交的请求(对角线)。虽然用户自然会复用自己请求的KV$——无论是通过多轮对话,还是通过程序调用具有相同系统提示的API来完成相同任务,但较低的用户间命中率表明,用户倾向于自定义自己的系统提示,而不是使用第三方库提供的模板提示【索引6,Prompt library】。因此,我们建议在设计KV$系统时,应更多地关注用户内(intra-user)的KV$复用,而非用户间(inter-user)的复用【索引19,Prompt Cache: Modular Attention Reuse for Low-Latency Inference,2024,MLSys】【索引68,Efficiently programming large language models using sglang,2023,CoRR】【索引25,Ragcache: Efficient knowledge caching for retrieval-augmented generation,2024,CoRR】【索引36,Cachegen: KV cache compression and streaming for fast large language model serving,2024,ACM SIGCOMM】。


Figure 6: 分析一个用户是否可能命中由另一个用户缓存的KV$。颜色越深,归一化的命中次数越高。注意,我们放大了对角线以防其过细,因为追踪数据提供商服务了大量用户。 **KV$复用存在倾斜
。图7显示了不同用户贡献的KV$缓存命中以及累积命中情况。KV$命中模式高度倾斜:Trace A中19%的用户请求和Trace B中4%的用户请求贡献了超过90%的KV$块命中。这种倾斜源于两个因素。首先,请求在用户间的分布不均,尤其是在Trace B中。图8显示了不同用户发送的归一化请求数量:15%的用户(头部用户)贡献了Trace B中90%的请求。由于KV$命中主要发生在同一用户的请求之间(见图6),请求数量的倾斜预计会导致KV$命中的类似倾斜。其次,即使请求由不同用户相对均匀地发送,单个用户在KV$命中方面也存在显著差异。如图8所示,Trace A的请求分布呈中度倾斜:19%的用户产生50%的请求,72%的用户产生90%的请求。然而,KV$命中仍然是倾斜的。我们怀疑这是因为他们倾向于进行多轮请求。
Figure 7: 在无限缓存大小的理想设置下,不同用户贡献的归一化(norm.)命中分析。
Figure 8: 不同用户归一化(norm.)请求计数的分析。 #### 3.3 多轮请求特征分析 **多轮请求在to-C工作负载中主导复用**。我们首先研究多轮请求的特征,因为它们仍然在to-C工作负载中主导KV$复用。我们省略了Trace B的结果,因为其中多轮请求非常罕见。

多轮请求具有高可变性。我们观察到两种可变性。首先,不同会话的轮数差异很大。图9显示了Trace A上轮数的分布:54%的请求是单轮请求,而第50和第90百分位的轮数分别为1和5。该分布具有长尾特性——最长的会话有232轮,比中位数大两个数量级(232倍)。


Figure 9: Trace A上多轮请求的轮数分布。

用户级别的多轮请求分布差异。其次,多轮请求分布在用户层面表现出显著差异。图10显示,大多数用户的平均轮数相似,除少数头部用户外——排名前10%的用户平均轮数是平均值的8.9倍。此外,轮数的标准差也差异巨大,从1到44不等。这表明用户交互模式多样:一些用户表现出高可变性,而另一些则保持稳定。


Figure 10: 每个用户发送请求的平均(上图)和标准差(下图)轮数分析。用户根据其平均轮数(上图)和标准差(下图)排序。

下一轮请求的概率可预测且因类别而异。给定一个工作负载类别和时间间隔,发出下一轮请求的概率是可预测的,并且该概率因请求类别而异。一个请求类别包括原始请求类型(如Text和Search)以及请求的轮数,即第1轮的文本请求(单轮文本请求)与第2轮的文本请求是不同的。图11的热力图展示了在长时间间隔(24小时)和短时间间隔(3小时)内,发出下一轮请求的概率如何随时间变化。颜色强度表示在一个时间窗口(10分钟)内分析出的频率。我们可以看到,尽管不同请求类别的频率不同(由垂直线显示),但对于一个特定类别,发出下一轮请求的频率在一小时的时间间隔内保持一致(由水平线显示)。我们将其归因于在特定时间间隔和请求类别下,KV$复用的概率分布是相当固定的。有趣的是,发出下一轮请求的频率因请求类别而异。例如,单轮请求发出下一轮请求的概率(平均=0.5)显著低于多轮请求(平均=0.8)。

Figure 11: 不同请求类型发出下一轮请求的频率随时间变化的示意图。x轴是时间线。工作负载类别根据其流行度排序。 #### 3.4 时间与空间局部性分析 **时间局部性由复用时间分布表征**。时间局部性可以通过分析复用时间的分布来表征,即一个KV$块被另一个请求复用之间的时间间隔。

**KV$复用时间短**。图12显示了两种追踪数据上KV$复用时间的分布。我们可以看到,两种工作负载的复用时间通常都很短:在Trace A中,80%的复用时间在10分钟以内,而在Trace B中则在10秒以内。这种差异源于两种追踪数据中请求产生的交互模式不同:前者是人机交互,后者是计算机程序交互。


Figure 12: Trace A和B中所有请求的KV$复用时间分布。 **不同工作负载类型的时间局部性不同**。首先,单轮请求在to-C工作负载中的局部性要低得多,而在to-B工作负载中则相反。图13的中间子图报告了在两种追踪数据上,一个单轮请求是否能被另一个单轮请求复用。如图所示,在Trace A中,不到30%的单轮请求是可复用的,但在Trace B中,超过50%的请求可以被复用。
Figure 13: Trace A和B中单轮请求的KV$复用时间分布。B只有一种请求类别(API)。

不同请求类型的时间局部性也不同。其次,不同请求类型显示出不同的时间局部性。图14展示了按请求类型分类的多轮请求的复用时间分布。我们可以看到,聊天请求(Text)的复用时间比图像理解(Multimodal)长,但比文件理解(File)短。这源于工作负载的特性:用户通常花更多时间处理基于文件内容的复杂LLM输出,而不是处理对话聊天的随意输出。相反,视觉信息的处理速度比文本处理快【索引47,Your brain at work: Strategies for overcoming distraction, regaining focus, and working smarter all day long,2010,Journal of Behavioral Optometry】,导致图像任务的复用时间更短。最后,搜索(Search)工作负载的复用时间第二长,因为用户通常需要大量时间来分析搜索到的结果。


Figure 14: Trace A和B中多轮请求的KV$复用时间分布。B只有一种请求类别(API)。 **KV$复用时间概率遵循指数分布**。给定一个时间段和请求类别,KV$复用时间的概率分布遵循指数分布。图15展示了不同请求类别下KV$块的复用时间概率分布。对于每个类别,我们测量其KV$在缓存后特定时间间隔内被复用的可能性。我们通过计算请求执行后每一秒复用事件的频率来绘制这些分布。从结果中,我们得出三个关键观察。首先,指数分布能很好地拟合给定请求类别的复用概率。其次,该概率是工作负载感知的,即不同请求类别的分布,包括相同请求类型但不同轮次的分布,是不同的(例如,text-1 vs. text-2)。这意味着需要一种区分不同请求类别的工作负载感知设计。最后,具有相似流量模式的请求的分布是相似的。以text-1为例:如第一行所示,从上午9:00-10:00绘制的分布与上午10:00-11:00绘制的分布相似,但与夜间——凌晨3:00-4:00(第二行)绘制的分布显著不同。不同日期的分布也相似(第一行 vs. 第三行)。第一和第三个观察结合起来意味着我们可以使用最近的历史数据来获取一个请求类别的分布。
Figure 15: KV$块复用时间概率分布的经验分析。列表示不同请求类别的数据。第一行:高流量(白天)下的分布。第二行:低流量(夜间)下的分布。第三行:不同日期但流量模式相似的分布比较。

空间局部性分析。图16显示了两种追踪数据的整体空间局部性。我们通过测量在不同缓存步长(stride,即每个请求缓存的token百分比)和不同起始token偏移量下理想缓存命中率来表征空间局部性。这给出了一个二维热力图,例如,偏移量(10%,10%)意味着对于每个请求,我们只从10%的token位置开始缓存10%的token。


Figure 16: 两种追踪数据的整体空间局部性。

空间局部性特征。首先,从请求开头开始缓存时,KV$显示出更好的空间局部性,这是预期的,因为只有具有相同前缀的请求才能共享KV$(§2)。我们强调这个看似微不足道的点,因为一些KV$优化【索引26,Compute or load KV cache? why not both?,2024,CoRR】会缓存请求的尾部token,以通过计算和加载并发来隐藏KV$加载时间。然而,这种方法可能会降低空间局部性,如图17特别表明,复用缓存中的中间部分对于多轮对话的收益微乎其微。


Figure 17: Trace A上多轮请求的空间局部性。

空间局部性是工作负载感知的。其次,空间局部性与时间局部性一样,也是工作负载感知的。在图18中,我们观察到像文本(text)和多模态(multimodal)这样的工作负载表现出明显的空间局部性,而文件(file)和搜索(search)几乎没有空间局部性。由于缺乏用户输入内容,我们猜测原因如下:应用程序为文本和多模态工作负载添加了固定的系统提示,而文件和搜索的系统提示则依赖于用户输入。


Figure 18: 单轮请求的空间局部性。

步长大小的影响因负载而异。最后,我们发现增加步长大小在Trace A中意味着更高的缓存命中率(图17),但在Trace B中并非如此(图18最后一列)。在Trace A中,多轮请求对缓存命中有所贡献,因此为一个请求缓存更多token将导致更多缓存命中。在Trace B中,只有系统提示对缓存命中有所贡献。因此,缓存请求的50%步长已经达到了50%的峰值命中率。这暗示Trace B中的大多数系统提示长度低于总请求长度的50%,尽管我们没有详细的请求数据来支持这一推测。

3.5 KV$缓存容量需求分析 **容量是缓存系统关键**。确定合适的缓存容量对缓存系统至关重要。与传统存储系统不同,缓存的KV$是短暂的,因此确定合适的容量需求可以节省平台成本。本节采用自下而上的方法分析KV$容量:首先,我们表征请求KV$生命周期的特征。然后,我们分析每个请求的存储使用情况。结合这两点,我们可以估算出所需的总KV$容量。 **KV$生命周期短暂且可预测**。图19分析了KV$块的生命周期。如果一个KV$块不再被复用,它就“死亡”了。我们可以看到,大多数KV$块的“存活”时间很短。在Trace A中,90%的KV$块在612秒后不再被复用,而Trace B的这个数字是0.3秒。这与我们在前几节的分析一致,例如,许多多轮请求的复用时间很短(图12),且大多数请求的轮数很少(图9)。当一个多轮请求结束时,其KV$将不再被复用。尽管有一些异常值,Trace B中的块生命周期更短。与Trace A不同,其缓存的大部分KV$块是为系统提示复用的,因此它们可以在很长一段时间后被复用。例如,在Trace B中,最长生命周期是1200分钟,而在Trace A中是800分钟。图20进一步显示了不同请求类别下KV$块的平均生命周期如何随时间变化。在图中,颜色强度代表归一化的生命周期,颜色越深表示生命周期越长的KV$块。我们可以看到,尽管在24小时尺度上平均生命周期随时间变化,但当我们放大到更小的时间尺度(上午9:00到11:00),模式是相当稳定的。这意味着我们可以使用历史数据来预测KV$块的生命周期,从而减小KV$缓存大小以节省成本,因为在快速存储介质(如CPU的DRAM)中存储KV$是昂贵的。
Figure 19: 两种追踪数据上KV$块的生命周期分布。


Figure 20: 不同请求类别下KV$块平均生命周期随时间变化的示意图。注意,x轴代表时间线。请求类别根据其使用情况排序。 **单个请求的KV$缓存使用量适中**。考虑缓存时的一个关键因素是要缓存的KV$大小,它与每个请求的输入长度和相应的模型输出长度成正比。图21显示了不同追踪数据上请求大小的分布。注意,我们报告的是相对于服务实例上可用于服务该请求的HBM的相对大小。这是因为相对值能更直观地显示缓存每个请求KV$所需的容量。可用于KV$的HBM是通过从服务实例中GPU的总HBM中减去模型参数和激活大小来计算的。由于每个请求的KV$大小取决于模型的具体注意力机制,我们报告了三种代表性模型在使用两种广泛使用的注意力方法时的结果:分组查询注意力(GQA【索引3,GQA: training generalized multi-query transformer models from multi-head checkpoints,2023,EMNLP】)和多头注意力(MHA【索引54,Attention is all you need,2017,NeurIPS】)。GQA使用较少的内存来存储KV$。我们可以看到,KV$的总体大小与HBM相比是适中的。以Trace A为例,在像Qwen2-7B这样的GQA模型上,主导请求类型Text中请求的第50、90和99百分位的HBM使用率分别为单轮请求的0.09%、0.15%和0.37%,以及多轮请求的0.36%、1.31%和2.21%。单轮和多轮请求的平均使用率分别为0.09%和0.56%。这种低使用率是由于每个token消耗的兆字节数很少,并且生产追踪数据中的请求往往较小:在Qwen2-7B中,16个token消耗0.875 MB的KV$,而单轮和多轮的平均总token长度(输入+输出)分别为973和5,953。对于其他模型,尽管Llama3-70B也采用GQA,但由于每个实例的GPU数量减少,其HBM使用率略高:参数大小增加了10倍,而我们测量的GPU数量仅增加了4倍。最后,MHA模型由于每个token的KV$增加,使用率最高。值得注意的是,最近的开源模型倾向于使用GQA(或每个token KV$更少的注意力机制,如MLA【索引35,Deepseek-v3 technical report,2024,arXiv】)。
Figure 21: 单轮和多轮请求在不同追踪数据上的KV$大小分布。大小是相对于可用于服务的GPU内存(HBM)进行归一化的。每个图内元组中的数字代表输入和输出的长度。

**整体KV$缓存所需内存适中**。我们通过测量多大的缓存可以确保理想的缓存命中率来分析所需的KV$缓存容量,这里假设采用理想的驱逐策略,即从不驱逐将被复用的KV$。测量方法如下:在给定时间,处理一个请求时,如果该请求的KV$将被复用,我们将其KV$大小加入总KV$大小;同时减去所有永远不会被复用的已缓存KV$的大小。一个棘手的问题是,所需的大小取决于为工作负载部署的服务实例数量:如果实例供应过剩,那么估计的需求会很小。为了获得最大需求,我们使用一个设置,即采用最少数量的服务实例,每个实例以最大QPS服务,因此没有供应过剩。图22显示了归一化到服务实例总HBM的结果。我们可以看到,GQA模型需要相对较小的缓存容量就能达到理想的缓存命中率:在Trace A中,Llama3-70B只需要4倍于可用HBM的KV$。这在现代服务集群中通常是可实现的,无需像远程内存或SSD这样的更多存储层次结构【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】。例如,在一个典型的配置中,有8个A100 GPU和1TB的CPU内存,每个GPU平均可以访问128GB的CPU内存,这几乎是为存储KV$保留的HBM空间的4倍。此外,对于Trace B,KV$容量甚至小于保留的HBM,因此在GPU上缓存可能就足够了。尽管GQA需要较小的缓存,但我们应注意MHA模型确实需要大量的KV$缓存,这是由于它们每个token的KV对很大(见图21)。因此,在有限的缓存容量下,优化缓存驱逐策略仍然很重要。

Figure 22: 在不同模型和追踪数据上实现理想缓存命中率所需的KV$缓存大小分析。数据收集自上午10:00至11:00。

A2 方法细节

4.1 设计空间概述

**现有KV$缓存机制与策略**。现有KV$缓存系统【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】【索引29,vLLM: Efficient Memory Management for Large Language Model Serving with PagedAttention,2023,SOSP】【索引68,Efficiently programming large language models using sglang,2023,CoRR】【索引64,Stateful Large Language Model Serving with Pensieve,2023,CoRR】遵循相似的缓存机制和策略。在机制方面,现有系统主要以分层方式在GPU和CPU上缓存KV$。KV$以块为粒度进行管理(见§2):当一个KV$块生成时,它首先被缓存在GPU HBM上。如果GPU因内存不足无法缓存新生成的块,缓存系统会采用驱逐策略(如下所述)将一些块从GPU驱逐到CPU。被驱逐的块以逐层异步的方式交换到CPU,因此交换成本可以忽略不计。如果CPU也内存不足,这些块将被移除。在执行新请求之前,如果请求命中了缓存的块,服务系统会直接复用缓存的块以避免重复计算。注意,如果命中发生在CPU上,该块也会以逐层的方式交换到GPU。在策略方面,KV$缓存系统主要需要两种策略:如何确定缓存命中以及如何驱逐缓存的块。对于第一种策略,设计选择在其检查哪些块可能贡献命中的粒度上有所不同:一些系统检查所有请求间的匹配【索引68,Efficiently programming large language models using sglang,2023,CoRR】【索引25,Ragcache: Efficient knowledge caching for retrieval-augmented generation,2024,CoRR】,而另一些仅检查来自单个用户的请求内的匹配【索引64,Stateful Large Language Model Serving with Pensieve,2023,CoRR】【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】。对于第二种策略,当前系统主要采用标准驱逐策略,如LRU或FIFO。尽管它们采用了一些扩展,如检查被驱逐的块是否在调度队列中【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】,但总体原理没有改变。

现有策略的缺点。像LRU这样与工作负载无关的策略可能会忽略我们在§3中分析的工作负载特征,我们认为它们是次优的。以Trace A为例:给定相同的自上次访问以来的时间(例如,大于10秒),10轮文本请求比1轮文本请求更有可能进行下一轮交互(见图11)。然而,如果有大量1轮请求涌入系统,10轮请求可能会被LRU驱逐,因为其复用时间更长。

**我们的解决方案:基于工作负载感知复用概率分布的KV$驱逐策略**。为此,我们提出了一种工作负载感知的缓存驱逐策略,该策略基于§3.4中描述的特征,考虑了每个请求类别的复用概率分布。在较高层面上,在驱逐时,我们为每个块计算一个优先级——即一个KV$在未来被复用的可能性,该可能性基于其请求类别(工作负载)的复用概率分布剖析。该优先级进一步综合考虑了空间局部性以及KV$块的短暂生命周期。优先级最低的块被首先驱逐。我们的缓存机制遵循现有系统【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】【索引29,vLLM: Efficient Memory Management for Large Language Model Serving with PagedAttention,2023,SOSP】【索引68,Efficiently programming large language models using sglang,2023,CoRR】【索引64,Stateful Large Language Model Serving with Pensieve,2023,CoRR】——包括异步交换和流水线加载,因为这些技术已经趋于标准化设计。 Table 2: 基于§3发现的我们工作负载感知缓存驱逐策略中主要技术的总结

### 4.2 工作负载感知的KV$缓存驱逐策略

现有的工作负载感知策略。工作负载感知的缓存驱逐策略在文献中已有广泛研究【索引14,Improving WWW proxies performance with greedy-dual-size-frequency caching policy,1998,Hewlett-Packard Laboratories】【索引40,The LRUK page replacement algorithm for database disk buffering,1993,SIGMOD】【索引28,Caching strategies to improve disk system performance,1994,Computer】【索引24,LIRS: an efficient low interreference recency set replacement policy to improve buffer cache performance,2002,SIGMETRICS】【索引37,ARC: A self-tuning, low overhead replacement cache,2003,FAST】【索引11,LHD: improving cache hit rate by maximizing hit density,2018,NSDI】【索引48,Learning cache replacement with CACHEUS,2021,FAST】。一个代表性的策略是Greedy-Dual-Frequency-Size(GDFS)策略【索引14,Improving WWW proxies performance with greedy-dual-size-frequency caching policy,1998,Hewlett-Packard Laboratories】,它使用以下与工作负载相关的特征来评估每个缓存对象(例如KV$)的优先级:

其中,Clock捕获对象的最后访问时间(类似于LRU),Frequency是对象的总访问次数(类似于LFU),Size是缓存对象的大小,Cost是将缓存内容带回缓存的成本。优先级最低的对象被首先驱逐。 **GDFS策略的局限性**。虽然上述GDFS公式可以改造用于计算KV$块的优先级,但我们发现它没有充分考虑LLM服务中的KV$使用情况以及不同类别请求的已知概率分布。例如,由于KV$块的生命周期短,一个频繁访问的块未来可能不会被复用,导致一个频繁访问然后“死亡”的块浪费了KV$空间。此外,一个带回缓存成本更高的块并不一定意味着它在未来更有可能被复用。相反,我们应该优先将更有可能被复用的块带回缓存。虽然在GDFS的设置中这些工作负载信息不可用,但根据我们在前一节的特征分析,在服务LLM时这些信息是现成可用的。 **我们的策略**。我们遵循GDFS的方法来计算每个KV$块的优先级,并使用该优先级来确定驱逐顺序,但我们的优先级是根据我们所表征的KV$复用特征进行改造的: `Priority = (ReuseProbw(t, life), −Offset)` (工作负载感知) 具体来说,优先级由一个包含两个指标的元组表示,我们按字典序比较元组。这两个指标的原理是: - **ReuseProbw (➀)**:计算一个KV$块在给定时间t的复用概率,其中t是自上次访问以来的时间。对于每个工作负载(请求类别),复用概率通过一个两步过程计算。首先,我们在后台对最近访问的数据进行一段时间的采样。其次,基于图15中的观察,我们对采样数据拟合一个指数分布,并通过查找拟合曲线来获得复用概率。图23展示了如何计算复用概率的示例。我们首先使用上午9:00到10:00的后台采样数据来拟合给定工作负载复用概率的累积分布函数(CDF)(蓝线)。注意,拟合曲线与真实数据(红线)非常接近。之后,我们可以查找该曲线来获得一个KV$块在未来的复用概率。注意,该函数进一步考虑了块的预期生命周期(life),这对于考虑KV$的短暂生命周期至关重要,我们将在下面描述。
- Offset (➁):考虑了§3.4中描述的空间局部性:优先级与KV$块在整个请求中的前缀长度成反比。 我们不显式考虑频率(➂),因为我们发现由于KV$块的生命周期短(见图19),即使是频繁复用的块,频率也无法为缓存策略提供有用的信息。更重要的是,我们还需要用生命周期来调节计算出的复用概率。否则,对于具有长尾复用时间分布的请求,拟合的复用概率将在很长一段时间内返回一个较大的概率值。这与KV$生命周期短的观察相矛盾,并导致有限缓存空间的低效利用。
Figure 23: 给定工作负载(请求类别)下如何计算KV$块复用概率的示意图。

详细的驱逐算法。图24展示了我们工作负载感知缓存驱逐算法的简化伪代码。在驱逐时,我们首先遍历所有缓存的块(第4-6行),并使用工作负载(b.w)为每个块计算复用概率。然后将该优先级与块的偏移量进行比较,以更新待驱逐的块(第7-9行)。
输入:B:缓存的KV$块;Life:KV$块的预期生命周期;H(w):工作负载(w)拟合概率分布的超参数,该分布在后台定期更新。
输出:B:被驱逐的KV$块。

Figure 24: 我们工作负载感知缓存驱逐算法的简化伪代码。 **性能优化**。上述朴素算法的一个缺点是,它需要计算所有KV$块的复用概率来识别最不可复用的候选者。为了避免过多的计算开销,我们观察到每个工作负载内的所有KV$块根据指数分布自然地按其最后访问时间戳排序,因此我们可以在比较同一工作负载内的块时避免计算复用概率。具体来说,对于每个工作负载,我们维护一个按最后访问时间排序的KV$块优先级队列。在驱逐期间,我们不扫描所有块,而是首先将每个工作负载中最近最少使用的块作为驱逐候选。之后,我们运行图24中描述的算法来获得最终被驱逐的块。这将复杂度从O(N)降低到O(W),其中W是工作负载的数量(通常在几十的范围内)。因此,工作负载感知策略的性能开销对服务来说是微不足道的,例如,我们观察到每次驱逐的策略延迟为79 µs,聚合开销仅为典型服务引擎(vLLM【索引29,vLLM: Efficient Memory Management for Large Language Model Serving with PagedAttention,2023,SOSP】)调度开销的1.2%。

A4 实验环境与结果

实验环境

硬件配置
- GPU:在一台配备8块NVIDIA A800-80GB GPU的服务器上进行评估。
- 互联:GPU之间通过400 GBps双向NVLink连接,支持张量并行。GPU通过PCIe Gen4连接到主机,提供高达32 GBps的双向带宽。

软件配置
- 实现基础:由于SOTA的CPU-GPU KV$缓存系统如CachedAttention和Pensieve不开源,我们在vLLM(一个默认采用GPU KV$缓存的SOTA LLM服务系统)上实现了一个CPU-GPU KV$缓存。 - **集成功能**:集成了SOTA系统的策略和机制,并实现了Mooncake中描述的以KV$为中心的全局调度器,以支持多实例服务。
- 评估策略:本文提出的工作负载感知(WA)策略仅应用于单个服务实例。

模型架构
- Qwen2-7B【索引9,Qwen technical report,2023,arXiv】:使用1个GPU。
- Llama2-13B【索引53,Llama: Open and efficient foundation language models,2023,CoRR】:使用1个GPU。
- Llama3-70B【索引15,The llama 3 herd of models,2024,CoRR】:使用4个GPU。
选择这些模型是为了覆盖不同的模型大小和注意力机制。

数据集
- 使用§3.1中描述的Trace ATrace B作为评估工作负载。
- 由于GPU资源有限,采用一种保留时间模式的缩放方法【索引50,Tracesplitter: a new paradigm for downscaling traces,2021,EuroSys】对追踪数据进行缩放以适应测试平台。
- 匿名追踪评估方法:通过为每个匿名块生成唯一的token列表来构建输入,以精确复现原始追踪的缓存命中模式,并根据追踪的输出长度约束模型,从而保留多轮请求的缓存模式。

实验结果

我们对比了本文提出的工作负载感知策略(WA)与标准策略(LRU, FIFO, LFU, S3-FIFO)在不同CPU缓存容量配置下的缓存命中率和服务性能。缓存容量以相对于GPU HBM大小的倍数表示。

缓存命中率提升
- WA策略优势:如图25-27所示,与所有基线相比,WA策略实现了8.1%至23.9%的命中率提升;与表现最好的基线相比,命中率提升了1.5%至3.9%。这是因为WA策略利用了工作负载的复用模式知识。
- 缓存容量影响:随着缓存容量的增加,WA的优势减小,因为更大的缓存可以容忍效率较低的策略。
- 工作负载差异:WA在Trace A上的效果比Trace B更显著。原因有二:(1)Trace B的工作负载信息较少(>99%是单轮请求),导致WA策略退化为类似LRU的策略。(2)Trace B所需的KV$容量较小,GPU HBM已接近最优。 - **LFU表现不佳**:由于KV$生命周期短,最频繁访问的块可能很早就失效,从而污染缓存,导致LFU命中率低下。


Figure 25: 在Qwen2-7B上,缓存命中率和QTTFT随CPU缓存配置的变化分析。

Figure 26: 在Llama2-13B上,缓存命中率和QTTFT随CPU缓存配置的变化分析。

Figure 27: 在Llama3-70B上,缓存命中率和QTTFT随CPU缓存配置的变化分析。

服务性能提升
- QTTFT降低:缓存命中率的提高直接转化为服务性能的显著改善。如图25-27所示,WA策略使得排队首token时间(QTTFT)降低了28.3%至41.9%。

消融研究
- 策略组件效果:图28在Qwen2-7B和Trace A上进行的消融研究显示:
- 仅使用基于分布的方法(技术➀),命中率提升1%。
- 进一步考虑KV$的短暂生命周期(技术➂),命中率再提升2.4%。 - 其他模型趋势类似。

Figure 28: 在Qwen2-7B上,当#CPU Cache / HBM为1时的消融研究。 **公平性问题讨论**: - 与现有系统一样,恶意客户端可能通过发送大量长相同前缀的请求来独占前缀缓存,引发公平性问题。确保公平性是一个与缓存策略正交的话题,可以通过与LLM服务策略(如FairRide)的协同设计来解决。 ## A7 补充细节 (相关工作) **通过KV$缓存在请求间复用KV$**。复用KV$以加速LLM服务已被广泛研究【索引29,vLLM: Efficient Memory Management for Large Language Model Serving with PagedAttention,2023,SOSP】【索引62,Chunkattention: Efficient self-attention with prefix-aware kv cache and twophase partition,2024,ACL】【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】【索引19,Prompt Cache: Modular Attention Reuse for Low-Latency Inference,2024,MLSys】【索引68,Efficiently programming large language models using sglang,2023,CoRR】【索引61,Cacheblend: Fast large language model serving for RAG with cached knowledge fusion,2024,CoRR】并在商业LLM服务中得到应用。当前,生产系统仅通过前缀匹配来处理缓存命中,因为它保留了模型推理的原始算法且无精度损失。一些研究【索引19,Prompt Cache: Modular Attention Reuse for Low-Latency Inference,2024,MLSys】【索引61,Cacheblend: Fast large language model serving for RAG with cached knowledge fusion,2024,CoRR】【索引22,Epic: Efficient position-independent context caching for serving large language models,2024】已经研究了非前缀KV$缓存的方法。一旦这些方法成熟并部署到生产环境中,我们可以重新审视我们的特征分析。 **其他KV$相关的优化**。新兴工作【索引58,Efficient streaming language models with attention sinks,2024,ICLR】【索引67,H2O: heavy-hitter oracle for efficient generative inference of large language models,2023,NeurIPS】【索引32,Infinigen: Efficient generative inference of large language models with dynamic KV cache management,2024,OSDI】【索引13,Pyramidkv: Dynamic KV cache compression based on pyramidal information funneling,2024,CoRR】提出了运行时KV$压缩和删除方法以减小KV$大小。例如,StreamingLLM仅保留最近token的有限注意力窗口和一些初始token。H2O仅涉及对注意力得分贡献最大的token进行推理。KVQuant【索引21,Kvquant: Towards 10 million context length LLM inference with KV cache quantization,2024,NeurIPS】实现了3-bit KV缓存量化,以最小的困惑度下降为代价,实现了百万长度上下文的快速推理。这些方法减少了每个请求的KV$需求,但会降低准确性。我们的研究与这些工作兼容:如果一个未压缩/完整的KV$是可复用的,那么压缩或删除后的版本也同样是可复用的。

优化缓存策略。优化缓存策略在文献中已有长期研究,包括通用缓存策略【索引40,The LRUK page replacement algorithm for database disk buffering,1993,SIGMOD】【索引28,Caching strategies to improve disk system performance,1994,Computer】【索引27,2q: A low overhead high performance buffer management replacement algorithm,1994,VLDB】【索引52,EELRU: simple and effective adaptive page replacement,1999,SIGMETRICS】【索引31,LRFU: A spectrum of policies that subsumes the least recently used and least frequently used policies,2001,IEEE Trans. Computers】【索引24,LIRS: an efficient low interreference recency set replacement policy to improve buffer cache performance,2002,SIGMETRICS】【索引37,ARC: A self-tuning, low overhead replacement cache,2003,FAST】【索引70,Second-level buffer cache management,2004,IEEE Trans. Parallel Distributed Syst.】【索引10,CAR: clock with adaptive replacement,2004,FAST】【索引23,Clock-pro: An effective improvement of the CLOCK replacement,2005,USENIX ATC】【索引16,Lightweight robust size aware cache management,2022,ACM Trans. Storage】【索引11,LHD: improving cache hit rate by maximizing hit density,2018,NSDI】【索引48,Learning cache replacement with CACHEUS,2021,FAST】【索引66,SIEVE is simpler than LRU: an efficient turn-key eviction algorithm for web caches,2024,NSDI】【索引14,Improving WWW proxies performance with greedy-dual-size-frequency caching policy,1998,Hewlett-Packard Laboratories】或特定领域【索引59,A large scale analysis of hundreds of in-memory cache clusters at twitter,2020,OSDI】【索引12,The CacheLib caching engine: Design and experiences at scale,2020,OSDI】【索引49,Icebreaker: warming serverless functions better with heterogeneity,2022,ASPLOS】【索引17,Faascache: keeping serverless computing alive with greedy-dual caching,2021,ASPLOS】。我们延续了这一研究方向,并利用我们表征的KV$复用属性来优化KV$缓存策略。

优化LLM服务。我们延续了优化LLM服务系统性能的研究方向【索引69,Distserve: Disaggregating prefill and decoding for goodput-optimized large language model serving,2024,OSDI】【索引56,Loongserve: Efficiently serving long-context large language models with elastic sequence parallelism,2024,CoRR】【索引30,Efficient memory management for large language model serving with pagedattention,2023,SOSP】【索引33,AlpaServe: Statistical multiplexing with model parallelism for deep learning serving,2023,OSDI】【索引63,Orca: A distributed serving system for transformer-based generative models,2022,OSDI】【索引45,Splitwise: Efficient generative LLM inference using phase splitting,2024,ISCA】【索引18,Cost-Efficient Large Language Model Serving for Multi-Turn Conversations with CachedAttention,2024,USENIX ATC】【索引65,Fast and live model auto scaling with O(1) host caching,2024,CoRR】,特别关注于为KV$缓存表征服务工作负载。我们的工作与KV$缓存之外的优化是正交的。

A5 结论

本文首次对用于KV$缓存系统的生产环境服务工作负载进行了系统性和深入的特征分析。我们的研究揭示了几个重要的发现,这些是先前研究中使用的合成工作负载未能捕捉到的。基于这些发现,我们进一步提出了一种工作负载感知的缓存驱逐策略,该策略改进了现有的如LRU和LFU等与工作负载无关的策略。我们相信,我们的工作作为一个起点,可以通过一种工作负载驱动的方法,为研究和工业界改进当前和未来的LLM服务系统带来益处。

A6 附录

A.1 不同日期的追踪结果

复用概率分布的日间稳定性。图29展示了在连续5个工作日内,每个请求类别在未来时间窗口的复用概率累积分布函数(CDF)的演变。我们可以观察到,在工作日之间,上午9:00到10:00的复用概率是相似的。因此,我们可以离线分析前一天的复用日志,来预测第二天每个类别的复用概率。然而,值得注意的是,“image”类型的复用概率比其他类别更难预测,我们推断这是因为图像类型的可复用性粒度比文本类型更粗,并且不同用户之间存在更大的可变性。


Figure 29: 5个工作日内复用概率累积分布函数的演变。第一行:上午9:00到10:00的分布。第二行:上午10:00到11:00的分布。