论文状态:已完成

Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving

发表:2024/06/24
原文链接PDF 下载
价格:0.10
价格:0.10
已有 4 人读过
本分析由 AI 生成,可能不完全准确,请以原文为准。

TL;DR 精炼摘要

Mooncake 是一种以 KVCache 为中心的解耦式架构,大幅提升了 LLM 服务的有效吞吐量,同时满足延迟相关的服务水平目标(SLO)。通过分离预填充和解码阶段,并利用 GPU 集群的闲置资源,Mooncake 在长上下文场景中实现了高达 525% 的吞吐量提升,能处理 75% 更多请求。

摘要

Mooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI. It features a KVCache-centric disaggregated architecture that separates the prefill and decoding clusters. It also leverages the underutilized CPU, DRAM, and SSD resources of the GPU cluster to implement a disaggregated cache of KVCache. The core of Mooncake is its KVCache-centric scheduler, which balances maximizing overall effective throughput while meeting latency-related Service Level Objectives (SLOs). Unlike traditional studies that assume all requests will be processed, Mooncake faces challenges due to highly overloaded scenarios. To mitigate these, we developed a prediction-based early rejection policy. Experiments show that Mooncake excels in long-context scenarios. Compared to the baseline method, Mooncake can achieve up to a 525% increase in throughput in certain simulated scenarios while adhering to SLOs. Under real workloads, Mooncake's innovative architecture enables Kimi to handle 75% more requests.

论文精读

中文精读

1. 论文基本信息

1.1. 标题

Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving (月饼:一种以 KVCache 为中心的解耦式 LLM 服务架构)

1.2. 作者

Ruoyu Qin, Zheming Li, Weiran He, Mingxing Zhang, Yongwei Wu, Weimin Zheng, Xinran Xu (Moonshot AI 与 Tsinghua University)

1.3. 发表期刊/会议

该论文发布在 arXiv,是一个预印本平台。arXiv 在学术界具有很高的影响力,通常用于快速分享最新的研究成果,但未经同行评审。

1.4. 发表年份

2024 年 6 月 24 日 (UTC)

1.5. 摘要

MooncakeKimi 的大型语言模型(LLM)服务平台,Kimi 是月之暗面公司提供的一个领先的 LLM 服务。Mooncake 采用以 KVCache 为中心的解耦架构(KVCache-centric disaggregated architecture),将预填充阶段(prefill)和解码阶段(decoding)的集群分开。它还利用 GPU 集群中未充分利用的 CPUDRAMSSD 资源来实现 KVCache 的解耦缓存(disaggregated cache)。Mooncake 的核心是其以 KVCache 为中心的调度器(KVCache-centric scheduler),该调度器旨在平衡最大化整体有效吞吐量(effective throughput)与满足与延迟相关的服务水平目标(Service Level Objectives, SLOs)。与假设所有请求都将被处理的传统研究不同,Mooncake 面对高度过载(highly overloaded)的场景。为了缓解这些问题,我们开发了一种基于预测的早期拒绝策略(prediction-based early rejection policy)。实验表明,Mooncake 在长上下文(long-context)场景中表现出色。与基线方法相比,在某些模拟场景下,Mooncake 可以在遵守 SLO 的前提下,实现高达 525% 的吞吐量提升。在真实工作负载下,Mooncake 的创新架构使 Kimi 能够处理多达 75% 的请求。

1.6. 原文链接

原文链接: https://arxiv.org/abs/2407.00079 PDF 链接: https://arxiv.org/pdf/2407.00079v4.pdf

2. 整体概括

2.1. 研究背景与动机

随着大型语言模型(LLMs)在各个领域的广泛应用,LLM 服务的工作负载变得日益多样化,请求的输入/输出长度、到达频率和分布各不相同,并且对服务水平目标(SLOs)提出了不同的要求,例如首令牌时间(Time to First Token, TTFT)和令牌间隔时间(Time Between Tokens, TBT)。作为模型即服务(Model as a Service, MaaS)提供商,Kimi 面临的核心挑战是如何在满足这些延迟 SLO 的同时,最大化整体有效吞吐量(effective throughput)。

现有研究在 LLM 服务效率方面已取得进展,例如通过连续批处理(continuous batching)和 PagedAttention 等技术来优化 GPU 内存管理和利用率。同时,一些研究者也提出了将 LLM 推理的预填充(prefill)阶段和解码(decoding)阶段分离的解耦架构(disaggregated architecture),因为这两个阶段具有截然不同的计算特性。然而,当前研究仍存在一些空白:

  1. 资源利用率问题: 尽管 GPU 服务器通常是高度集成的节点,但其中 CPUDRAMSSD 等资源在 LLM 服务中往往未被充分利用。

  2. KVCache 调度复杂性: KVCache 的调度对于提高吞吐量至关重要(例如通过复用 KVCache 和最大化批处理量),但这些优化可能与延迟 SLO 相冲突。

  3. 过载场景的挑战: 大多数现有研究假设资源充足,并侧重于提高资源利用率。然而,在 GPU 供应受限且用户请求量快速增长的现实世界 MaaS 场景中,过载(overload)是常态,这使得调度问题变得更加复杂,并可能导致资源浪费(例如,预填充完成后才发现无法满足解码 SLO 而拒绝请求)。

    针对这些挑战,本文提出了 Mooncake,旨在通过以 KVCache 为中心的解耦架构和智能调度策略来解决这些问题,尤其关注长上下文处理和过载场景下的性能优化。

2.2. 核心贡献/主要发现

Mooncake 及其论文的主要贡献和发现可以总结如下:

  • KVCache-centric 解耦架构: 提出了一个创新性的、以 KVCache 为中心的解耦架构。它不仅将预填充集群(prefill cluster)和解码集群(decoding cluster)物理分离,还利用 GPU 服务器中未充分利用的 CPUDRAMSSD 资源构建了一个解耦的 KVCache 缓存池,极大地扩展了 KVCache 的容量和传输带宽。
  • KVCache-centric 调度器 (Conductor): 设计了一个名为 Conductor 的核心调度器,它以 KVCache 为中心进行全局调度。该调度器能够平衡最大化整体有效吞吐量与满足 TTFTTBT 等延迟 SLO。它考虑了 KVCache 的复用、预填充实例的负载平衡以及 KVCache 热点迁移等因素。
  • 长上下文处理优化:
    • 引入了分块流水线并行(Chunked Pipeline Parallelism, CPP)来高效处理长上下文预填充,减少跨节点通信开销并适应动态上下文长度。
    • 实现了逐层预填充(Layer-wise Prefill),通过将 KVCache 的传输与计算重叠,显著降低了长上下文预填充的延迟和 VRAM 占用。
  • 过载场景下的早期拒绝策略: 针对 MaaS 平台常见的过载问题,开发了基于预测的早期拒绝策略(prediction-based early rejection policy)。该策略通过在请求的预填充阶段开始前,预测其在解码阶段是否会满足 SLO,从而决定是否接受请求,有效减少了因请求被拒绝而导致的计算资源浪费,并缓解了早期拒绝可能导致的负载波动问题。
  • 显著的性能提升:
    • 在长上下文模拟场景下,Mooncake 相较于基线方法(vLLM)在满足 SLO 的前提下,吞吐量最高可提升 525%
    • 在真实工作负载下,Mooncake 的架构使得 Kimi 能够处理多达 75% 的请求,同时保持 TBT SLO 的高度满足率(接近 100%),而 vLLM 只有 57% 的请求满足 TBT SLO

3. 预备知识与相关工作

3.1. 基础概念

为了理解 Mooncake 提出的架构和调度策略,需要先了解 LLM 服务中的一些基本概念和挑战:

  • 大型语言模型 (Large Language Models, LLMs):指参数量巨大,通常基于 Transformer 架构的深度学习模型,能够理解和生成人类语言。
  • Transformer 架构 (Transformer Architecture)LLM 的核心架构,由编码器(encoder)和解码器(decoder)组成,但 LLM 通常只使用 decoder-only 结构。它依赖自注意力机制(self-attention mechanism)来处理序列数据。
  • 预填充阶段 (Prefill Stage)LLM 推理的第一个阶段。当用户输入一个提示(prompt)时,模型会并行处理所有输入词元(tokens),计算并生成第一个输出词元,同时将中间计算结果(键和值)存储为 KVCache。这个阶段通常计算密集型,尤其对于长输入序列。
  • 解码阶段 (Decoding Stage)LLM 推理的第二个阶段。模型利用预填充阶段生成的 KVCache,自回归地(autoregressively)逐个生成新的输出词元。每次生成一个新词元,都会将新的键和值添加到 KVCache 中。这个阶段通常是内存密集型,并且需要高效的批处理。
  • KVCache (键值缓存)Transformer 模型中注意力机制计算的中间结果,即键(Key)和值(Value)向量的缓存。在自回归生成过程中,为了避免重复计算历史词元的注意力,KVCache 被存储并复用。它占据 GPU 显存(VRAM),对 LLM 服务的内存管理至关重要。
  • 词元 (Token):文本经过分词器(tokenizer)处理后的基本单位,可以是单词、子词或字符。LLM 以词元为单位进行输入和输出。
  • 连续批处理 (Continuous Batching):一种 LLM 服务优化技术,旨在提高 GPU 利用率。它允许在 GPU 空闲时,将新的请求动态地添加到正在进行的批处理中,或移除已完成的请求,从而保持 GPU 的持续高负载。
  • PagedAttentionvLLM 提出的 KVCache 管理技术,灵感来源于操作系统中的虚拟内存分页,将 KVCache 存储在非连续的内存空间中,并支持灵活的共享和重用,有效解决了 KVCache 碎片化和内存浪费问题。
  • 服务水平目标 (Service Level Objectives, SLOs):衡量服务质量的关键指标,通常包括延迟、吞吐量、可用性等。在 LLM 服务中,主要关注 TTFTTBT
  • 首令牌时间 (Time to First Token, TTFT):用户发送请求到模型生成第一个输出词元之间的时间间隔。这对于用户体验,尤其是交互式应用,至关重要。
  • 令牌间隔时间 (Time Between Tokens, TBT):模型生成连续两个输出词元之间的时间间隔。这衡量了模型生成速度的流畅性。
  • 模型浮点运算利用率 (Model FLOPs Utilization, MFU):衡量 GPU 计算资源利用效率的指标,即 GPU 实际执行的浮点运算次数与理论峰值之间的比率。提高 MFU 通常需要更大的批处理量。
  • 解耦架构 (Disaggregated Architecture):将系统中不同功能模块(如计算、存储、网络)或不同处理阶段(如预填充、解码)分离,并部署在独立的资源池上,以实现更灵活的资源分配和优化。
  • 前缀缓存 (Prefix Caching):一种 KVCache 复用技术。如果多个请求共享相同的前缀输入序列(例如,相同的系统提示或文档开头),那么这部分共享前缀的 KVCache 可以被计算一次并缓存起来,供后续请求直接使用,从而节省预填充阶段的计算开销。
  • 远程直接内存访问 (Remote Direct Memory Access, RDMA):一种允许网络适配器直接访问远程服务器内存,而无需 CPU 介入的技术。它能显著降低网络通信的延迟和 CPU 开销,对于高速数据传输(如 KVCache 跨节点传输)非常重要。

3.2. 前人工作

论文在介绍 Mooncake 的设计时,提及并借鉴了大量 LLM 服务领域的现有工作。理解这些工作对于把握 Mooncake 的创新点至关重要。

  • LLM 服务效率优化:
    • FasterTransformer [28], TensorRT-LLM [29], DeepSpeed Inference [30]:这些是生产级 LLM 推理系统,通过底层优化(如算子融合、量化、高效并行策略)显著提升吞吐量。它们通常聚焦于单个模型的性能,而不涉及复杂的分布式调度。
  • KVCache 管理与批处理:
    • Orca [12]:通过迭代级调度(iteration-level scheduling)实现不同请求阶段的并发处理。
    • vLLM [13]:利用 PagedAttention 技术进行动态 KVCache 管理,极大地优化了内存使用和吞吐量。MooncakeKVCache 管理方面受 vLLM 启发,但 vLLM 主要支持本地 KVCache 缓存,且其耦合的预填充/解码设计在长上下文场景下可能受限。
    • Prompt Cache [33]:预计算并存储常用 promptKVCache,减少推理延迟。
    • SGLang [34]:利用 RadixAttentionLRU 缓存机制,高效地自动共享 KVCache
    • AttentionStore [35]:与 Mooncake 同期的工作,提出了一个分层 KVCache 系统,利用成本效益高的内存和存储介质来容纳所有请求的 KVCacheMooncake 在架构上与 AttentionStore 有相似之处,但更侧重于长上下文推理中的大规模 KVCache 管理和传输,以及缓存感知的全局调度。
  • 解耦架构:
    • Splitwise [7]:最早提出将预填充和解码阶段分离的解耦架构,通过阶段拆分提高效率。
    • DistServe [8]:进一步优化资源分配和并行策略,以最大化 GPU 的有效吞吐量(goodput)。
    • TetriInfer [9]:结合分块预填充(chunked prefill)和两阶段解耦,并提出预测性的两阶段调度算法来优化资源利用。
    • 这些工作与 Mooncake 的设计理念相似,都认为预填充和解码阶段需要分离以优化资源,但 Mooncake 更进一步,将 KVCache 置于调度的中心,并专注于过载场景。
  • 长上下文处理:
    • Loongserve [14]:通过弹性序列并行(elastic sequence parallelism)高效服务长上下文 LLM。虽然与 Mooncake 的分块流水线并行(CPP)目标相似,但 MooncakeCPP 旨在减少跨节点通信和简化动态调整。
  • 注意力机制核心公式 (Attention Mechanism Core Formula): 由于 LLM 基于 Transformer 架构,其核心是注意力机制。即使论文未复述,理解它对于理解 KVCache 的作用至关重要。 自注意力机制(Self-Attention Mechanism)的计算公式如下: Attention(Q,K,V)=softmax(QKTdk)V \mathrm{Attention}(Q, K, V) = \mathrm{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V 其中:
    • QQ (Query):查询矩阵,由输入序列通过线性变换得到。

    • KK (Key):键矩阵,由输入序列通过线性变换得到。

    • VV (Value):值矩阵,由输入序列通过线性变换得到。

    • QKTQ K^T:查询和键的点积,表示查询与每个键的相似度。

    • dk\sqrt{d_k}:缩放因子,用于防止点积结果过大,其中 dkd_k 是键向量的维度。

    • softmax\mathrm{softmax}:softmax 函数,将注意力分数归一化为概率分布。

    • Attention(Q,K,V)\mathrm{Attention}(Q, K, V):输出的注意力加权值,是值矩阵 VV 的加权和。

      在自回归解码阶段,KVCache 存储的就是历史词元的 KKVV 矩阵,从而避免了在生成每个新词元时重复计算整个历史序列的 KKVV

3.3. 技术演进

LLM 服务技术经历了从早期简单的 Transformer 推理框架到如今高度优化的分布式系统的演进:

  1. 早期优化阶段: 聚焦于单个 GPU 或节点内的优化,如 FasterTransformerTensorRT-LLM 通过算子融合、批处理、量化等手段提升单卡或单机性能。
  2. 批处理与内存管理: 随着 LLM 规模增大,KVCache 成为瓶颈。OrcavLLM 等引入了连续批处理和 PagedAttention 等技术,高效管理 KVCache,显著提升了 GPU 利用率和吞吐量。
  3. 解耦架构的兴起: 认识到预填充和解码阶段的计算特性差异巨大,SplitwiseDistServeTetriInfer 等工作提出了将这两个阶段分离的解耦架构,以实现更灵活的资源配置和调度。
  4. KVCache-centric 与过载处理: Mooncake 在解耦架构的基础上,进一步将 KVCache 推向中心地位,不仅利用闲置资源构建大规模 KVCache 缓存池,还设计了 KVCache-centric 调度器,并首次系统地解决了 MaaS 环境中普遍存在的过载问题,提出了基于预测的早期拒绝策略。

3.4. 差异化分析

Mooncake 与现有工作的主要区别和创新点在于:

  • KVCache 的核心地位: Mooncake 是第一个明确提出并围绕 KVCache 构建整个解耦架构和调度策略的系统。它不仅仅是利用 KVCache,而是将其视为系统优化的核心,通过解耦缓存池、热点迁移等手段最大化其价值。
  • 利用未充分利用的资源: Mooncake 明确指出并利用了 GPU 集群中 CPUDRAMSSD 等未充分利用的资源来构建一个大规模的解耦 KVCache 缓存池,这是其他解耦系统较少强调的。
  • 长上下文处理的独特方案: 提出了分块流水线并行(CPP)和逐层预填充(Layer-wise Prefill),这些技术旨在高效处理超长上下文,同时减少网络开销和 VRAM 占用,这与传统的序列并行(SP)或张量并行(TP)在分布式环境中的使用有所不同。
  • 聚焦过载场景: 大多数现有研究假设资源充足,Mooncake 则针对 MaaS 平台常见的过载场景,开发了预测式早期拒绝策略,以最小化资源浪费和优化系统稳定性。这是对 LLM 服务调度领域的一个重要补充。
  • 端到端性能与 SLO 导向: Mooncake 不仅仅追求吞吐量最大化,而是严格在满足 TTFTTBT SLO 的前提下进行优化,并通过“有效吞吐量”(goodput)的概念来衡量性能。

4. 方法论

Mooncake 的方法论围绕其 KVCache-centric 的解耦架构展开,旨在通过智能调度和资源管理,在长上下文和过载场景下最大化有效吞吐量并满足 SLO

4.1. 方法原理

Mooncake 的核心思想是,KVCacheLLM 推理中连接预填充和解码阶段的关键桥梁,也是资源消耗的重要组成部分。通过将 KVCache 作为中心,系统可以实现以下目标:

  1. 解耦预填充与解码: 充分利用两个阶段不同的计算特性,分别优化资源。预填充阶段计算密集,适合并行处理和大规模 KVCache 复用;解码阶段内存带宽密集,适合连续批处理以提高 MFU
  2. KVCache 的高效管理与复用:KVCache 存储在 CPU 内存和 SSD 中,利用 GPU 集群中未充分利用的资源,提供更大的缓存容量。同时,通过前缀缓存和热点迁移,最大化 KVCache 的复用率,减少重复计算。
  3. 智能调度策略: 设计一个全局调度器(Conductor),它基于 KVCache 的分布和实例负载,做出最优的调度决策,平衡吞吐量和 SLO
  4. 过载场景韧性: 针对真实世界的过载情况,引入预测式早期拒绝机制,避免资源浪费,并稳定系统负载。

4.2. 核心方法详解

4.2.1. Mooncake 架构概览

Mooncake 的整体架构如 Figure 1 所示,它是一个 KVCache-centric 的解耦架构,主要由以下核心组件构成:

Figure 1: Mooncake Architecture. 该图像是Mooncake架构的示意图,展示了KVCache中心调度器的组成部分,包括预填充实例、KVCache池和解码池。图中显示了不同调度器的功能,如缓存感知的预填充调度器、KVCache平衡调度器和负载均衡解码调度器,强调了各个组件之间的资源分配和相互作用。

Figure 1: Mooncake Architecture.

  • Prefill Cluster (预填充集群): 负责处理请求的预填充阶段。通常由多个 GPU 节点组成,这些节点针对并行计算和长上下文处理进行优化。
  • Decoding Cluster (解码集群): 负责处理请求的解码阶段。也由多个 GPU 节点组成,这些节点针对连续批处理和高效内存访问进行优化。
  • KVCache Pool (KVCache 池): 这是一个解耦的缓存存储,它利用 GPU 集群中未充分利用的 CPU DRAMSSD 资源来存储 KVCache。这提供了巨大的容量和传输带宽,使得 KVCache 可以在不同节点之间高效共享和迁移。
  • Conductor (调度器): Mooncake 的全局调度核心。它负责:
    • 接收新请求。
    • 根据当前 KVCache 分布、预填充和解码实例的负载以及 SLO 要求,选择合适的预填充和解码实例。
    • 预测 KVCache 块的未来使用情况,并执行 KVCache 的交换(swapping)和复制(replication)操作,以避免获取瓶颈并降低存储成本。
    • 在过载场景下,执行早期拒绝策略。

4.2.2. KVCache 池设计

KVCache 池是 Mooncake 能够实现高效 KVCache 复用和解耦架构的关键。

Figure 3: The KVCache pool in CPU memory. Each block is attached with a hash value determined by both its own hash and its prefix for deduplication. 该图像是示意图,展示了 KVCache 池在 CPU 内存中的组织结构。图中展示了多个 Token 块和对应的哈希值,区分了前缀缓存块、增量缓存块和未分配缓存块。每个缓存块都附有通过自身哈希及其前缀确定的哈希值,以便进行去重处理。该设计支持 KVCache 的存储、读取和加载,旨在优化 Mooncake 的缓存管理效率。

Figure 3: The KVCache pool in CPU memory. Each block is attached with a hash value determined by both its own hash and its prefix for deduplication.

如 Figure 3 所示,KVCacheCPU 内存中以分页的块(paged blocks)形式存储。每个块都附带一个哈希值,这个哈希值由其自身内容的哈希和其前缀的哈希共同决定,用于实现去重(deduplication)。这种设计使得相同的前缀 KVCache 可以被识别并共享。

  • 存储介质: 利用 CPU DRAMSSD 作为 KVCache 的存储介质,相较于昂贵的 GPU VRAM,提供了更大的容量和更低的成本。
  • 缓存算法: 根据请求模式,可以采用 LRU (Least Recently Used,最近最少使用)、LFU (Least Frequently Used,最不经常使用) 或基于请求特征的算法进行缓存淘汰。
  • Messenger (消息传递器): Messenger 是一个独立的组件,部署在每个节点上,负责管理和传输这些 KVCache 块。它利用 GPUDirect RDMA 等技术,实现 KVCache 块在 CPU 之间和 CPUGPU 之间的高速、跨机器传输。
  • 开放 Context Caching API 这种架构还允许 Mooncake 向外部用户提供 Context Caching API,以实现更高级别的 KVCache 复用。

4.2.3. 请求工作流

一个请求在 Mooncake 架构中的典型工作流如 Figure 4 所示,由 Conductor 协调完成:

Figure 4: Workflow of inference instances. (\\*) For prefill instances, the load and store operations of the KVCache layer are performed layer-by-layer and in parallel with the prefill computation to mitigate transmission overhead (see \(\\ S 5 . 2 )\) . (†) For decoding instances, asynchronous loading is performed concurrently with GPU decoding to prevent GPU idle time. 该图像是图表,展示了推理实例的工作流程。对于预填充实例,KVCache 层的加载和存储操作是逐层进行并与预填充计算并行,以减轻传输开销。对于解码实例,异步加载与 GPU 解码并发进行,以防止 GPU 空闲时间。

Figure 4: Workflow of inference instances. (*) For prefill instances, the load and store operations of the KVCache layer are performed layer-by-layer and in parallel with the prefill computation to mitigate transmission overhead (see  S5.2)\ S 5 . 2 ) . (†) For decoding instances, asynchronous loading is performed concurrently with GPU decoding to prevent GPU idle time.

  1. KVCache 复用 (KVCache Reuse):

    • 当一个新请求到达并完成词元化(tokenizing)后,Conductor 会为该请求选择一对预填充实例和解码实例。
    • 选定的预填充实例接收请求,其中包含原始输入、可复用的前缀缓存(prefix cache)的块 ID,以及为该请求分配的完整缓存的块 ID
    • 预填充实例根据前缀缓存块 ID,从远程 CPU 内存加载前缀缓存到 GPU 内存,以引导请求处理。如果不存在可复用的前缀缓存,则跳过此步骤。
    • 此步骤的选择需要平衡三个目标:尽可能多地复用 KVCache、平衡不同预填充节点的负载以及保证 TTFT SLO
  2. 增量预填充 (Incremental Prefill):

    • 预填充实例(或实例组)使用已加载的前缀缓存完成预填充阶段,并将新生成的增量 KVCache 存回 CPU 内存。
    • 如果未缓存的输入词元数量超过预设阈值 prefill_chunk,预填充阶段将被拆分为多个块,并以流水线(pipeline)方式执行。
  3. KVCache 传输 (KVCache Transfer):

    • 上文提到的 Messenger 服务部署在每个节点上,管理和传输 KVCache。每个 Messenger 作为独立进程运行,接收信号以实现高速、跨机器的 KVCache 传输。
    • 此步骤是异步执行的,并与增量预填充步骤重叠。预填充实例会逐层(layer-by-layer)将其生成的 KVCache 流式传输到目标解码节点(destination decoding node)的 CPU 内存,以减少等待时间。
  4. 解码 (Decoding):

    • 一旦所有 KVCache 都被接收到解码节点的 CPU DRAM 中,该请求就会以连续批处理(continuous batching)的方式加入下一个批次。
    • Conductor 会根据解码节点的当前负载预先选择它,以确保不会违反 TBT SLO
    • 然而,本地调度器会再次检查 SLO,因为预期的负载在预填充阶段后可能发生变化。如果此时发现无法满足 SLO,请求可能会被拒绝,从而导致预填充阶段的计算成本被浪费。

4.2.4. 预填充池实现

4.2.4.1. 多节点预填充 (Multi-node Prefill)

为了处理日益增长的长上下文 LLM 请求(如 128K 甚至 1M 词元),Mooncake 引入了 分块流水线并行 (Chunked Pipeline Parallelism, CPP) 来加速预填充。

  • 长上下文的挑战: 对于长上下文,输入词元数量可能是输出词元的 10 到 100 倍,使得 TTFT 优化至关重要。虽然可以使用多个 GPU 节点并行处理,但传统的张量并行(Tensor Parallelism, TP)在跨节点时需要昂贵的 RDMA all-reduce 操作,降低 MFU。序列并行(Sequence Parallelism, SP)虽然减少了网络消耗,但在 MFU 上仍不如单节点 TP,且需要复杂的动态伸缩。
  • CPP 的方案: Mooncake 利用 decoder-only Transformer 的自回归特性,将预填充集群中的每 XX 个节点分组为一个流水线预填充节点组。对于每个请求,其输入词元被分成多个块,每个块的长度不超过 prefill_chunk。同一请求的不同块可以由不同的节点同时处理,从而实现并行化并减少 TTFT
  • CPP 的优势:
    1. 高效通信: 类似于训练中的流水线并行,CPP 只在每个流水线阶段的边界处进行跨节点通信,这部分通信可以与计算重叠,从而带来更好的 MFU,并减少与 KVCache 传输的网络资源竞争。
    2. 适应性强: CPP 自然适用于短上下文和长上下文,对短上下文预填充没有显著开销,避免了频繁动态调整节点分区。

4.2.4.2. 逐层预填充 (Layer-wise Prefill)

除了计算能力,VRAM 的有限性也是一个宝贵资源。Mooncake 旨在最小化 KVCacheVRAM 中的占用。

  • 原理: 由于预填充是逐层处理且受计算限制的,因此可以将 KVCache 的传输和存储与计算重叠。
  • 实现:Mooncake 中,KVCache 的加载和存储是异步执行的。
    • 在每个层(layer)的注意力计算开始前,模型等待该层 KVCache 的异步加载完成,并触发下一层 KVCache 的异步加载。
    • 注意力计算完成后,启动该层 KVCache 的异步存储。
    • 所有层计算完成后,等待所有异步存储操作完成。
  • 优势:
    • 降低 VRAM 占用: 这种传输重叠使得预填充实例的执行时间大致等于 KVCache 加载时间或标准预填充时间,具体取决于前缀缓存占输入长度的比例。这允许我们在预填充调度中,只要 VRAM 能容纳单个请求,就可以忽略其大小。

    • 减少延迟: 如 Figure 7 所示,逐层预填充能有效减少长上下文请求的延迟。

      Figure 7: Latency of storing KVCache of different request lengths (Layer-wise latency refers to the difference in latency between Layer-wise Prefill and Prefill without storing KVCache). 该图像是一个图表,展示了不同请求长度下存储KVCache的延迟。蓝色条表示序列化延迟,黄色条表示分层延迟。随着序列长度增加,延迟显著上升,尤其在128000时达到最高值。

Figure 7: Latency of storing KVCache of different request lengths (Layer-wise latency refers to the difference in latency between Layer-wise Prefill and Prefill without storing KVCache). Figure 7 展示了存储不同请求长度的 KVCache 的延迟。其中,“Layer-wise latency”指的是逐层预填充(Layer-wise Prefill)与不存储 KVCache 的预填充之间的延迟差异。从图中可以看出,随着请求长度的增加,逐层预填充带来的延迟增量是可控的,证明了其在长上下文场景下的有效性。

4.2.5. KVCache-centric 调度

本节主要讨论 Conductor 如何在正常情况下调度请求和 KVCache 块。

4.2.5.1. 预填充全局调度 (Prefill Global Scheduling)

传统的 LLM 服务调度通常采用负载均衡策略。而 Mooncake 的调度算法(如 Algorithm 1 所示)在此基础上,额外考虑了前缀缓存命中长度和可复用 KVCache 块的分布。

Input: prefill instance pool P, decoding instance pool D, request R, cache block size B.
Output: the prefill and decoding instances (p, d) to process R.
1: block_keys ← PrefixHash(R.prompt_tokens, B)
2: TTFT ← inf
3: p ← ∅
4: best_prefix_len, best_matched_instance ← FindBestPrefixMatch(P, block_keys)
5: for instance ∈ P do
6:     prefix_len ← instance.prefix_len
7:     T_queue ← EstimatePrefillQueueTime(instance)
8:     if best_prefix_len / prefix_len < kvcache_balancing_threshold then  # Cache-aware prefill scheduling
9:         T_prefill ← EstimatePrefillExecutionTime(len(R.prompt_tokens), prefix_len)
10:        if TTFT > T_queue + T_prefill then
11:            TTFT ← T_queue + T_prefill
12:            p ← instance
13:        end if
14:    else:  # Cache-aware and -balancing prefill scheduling
15:        transfer_len ← best_prefix_len - prefix_len
16:        T_transfer ← EstimateKVCacheTransferTime(instance, best_matched_instance, transfer_len)
17:        T_prefill ← EstimatePrefillExecutionTime(len(R.prompt_tokens), best_prefix_len)
18:        if TTFT > T_transfer + T_queue + T_prefill then
19:            TTFT ← T_transfer + T_queue + T_prefill
20:            p ← instance
21:        end if
22:    end if
23: end for
24: d ← SelectDecodingInstance(D)  # Load-balancing decoding scheduling
25: if TTFT > TTFT_SLO or TBT > TBT_SLO then
26:     reject R; return
27: end if
28: if best_prefix_len > kvcache_balancing_threshold then
29:     TransferKVCache(best_matched_instance, p)  # KVCache hot-spot migration
30: end if
31: return (p, d)

算法 1: 缓存感知预填充调度

  • 输入: 预填充实例池 PP,解码实例池 DD,请求 RR,缓存块大小 BB
  • 输出: 处理请求 RR 的预填充实例 pp 和解码实例 dd

算法步骤详解:

  1. 生成块键: block_keys \leftarrow PrefixHash(RR.prompt_tokens, BB)。对于每个新请求,其输入词元被划分为多个块,并为每个块计算一个哈希键。这个哈希键包含了当前块及其所有前置块的哈希信息,用于识别前缀缓存关系。
  2. 初始化: TTFT \leftarrow \infty (无穷大),pp \leftarrow \emptyset (空)。
  3. 查找最佳前缀匹配: (best_prefix_len, best_matched_instance) \leftarrow FindBestPrefixMatch(PP, block_keys)。Conductor 检查所有预填充实例,找到能提供最长前缀匹配 (best_prefix_len) 的实例 (best_matched_instance)。
  4. 遍历预填充实例选择:
    • 对于池 PP 中的每个 instance
      • prefix_len \leftarrow instance.prefix_len。获取当前实例能提供的前缀匹配长度。
      • T_queue \leftarrow EstimatePrefillQueueTime(instance)。估算请求在该实例的预填充队列中等待的时间。
      • 缓存感知预填充调度 (Cache-aware prefill scheduling):
        • 如果 best_prefix_len / prefix_len < kvcache_balancing_threshold:这意味着当前实例的本地前缀匹配长度相对较短(或最佳匹配相对较长),或者说,本地计算的收益可能更高,或者无需进行昂贵的 KVCache 传输。
        • T_prefill \leftarrow EstimatePrefillExecutionTime(len(RR.prompt_tokens), prefix_len)。估算在该实例上执行预填充所需的时间,基于请求总长度和当前实例可用的前缀缓存长度。
        • 如果 T_queue + T_prefill 小于当前的 TTFT 最优值,则更新 TTFT 和最佳预填充实例 pp
      • 缓存感知与平衡预填充调度 (Cache-aware and -balancing prefill scheduling):
        • 否则:这意味着最佳前缀匹配很长,且当前实例没有最佳匹配,可能需要传输 KVCache
        • transfer_len \leftarrow best_prefix_len - prefix_len。计算需要传输的 KVCache 长度。
        • T_transfer \leftarrow EstimateKVCacheTransferTime(instance, best_matched_instance, transfer_len)。估算从 best_matched_instance 传输 KVCache 到当前 instance 所需的时间。
        • T_prefill \leftarrow EstimatePrefillExecutionTime(len(RR.prompt_tokens), best_prefix_len)。估算在该实例上执行预填充所需的时间,假设它获得了最长的前缀缓存。
        • 如果 T_transfer + T_queue + T_prefill 小于当前的 TTFT 最优值,则更新 TTFT 和最佳预填充实例 pp
  5. 解码实例选择: dd \leftarrow SelectDecodingInstance(DD)。Conductor 基于负载均衡策略选择一个解码实例。
  6. SLO 检查与拒绝: 如果 TTFT > TTFT_SLOTBT > TBT_SLO,则拒绝请求 RR 并返回 HTTP 429 Too Many Requests 状态码。
  7. KVCache 热点迁移 (KVCache hot-spot migration): 如果 best_prefix_len > kvcache_balancing_threshold,则 TransferKVCache(best_matched_instance, pp)。这表示如果存在很长的最佳前缀匹配,并且该匹配的长度超过了某个平衡阈值,则将该 KVCache 从其当前持有者 best_matched_instance 传输到选定的预填充实例 pp。这有助于实现 KVCache 的热点迁移和复制。
  8. 返回: 返回选定的预填充实例 pp 和解码实例 dd

工程实现细节:

  • 预填充时间预测: 采用基于离线测试数据的预测模型,根据请求长度和前缀缓存命中长度估算预填充持续时间。
  • 排队时间计算: 通过聚合所有排队请求的预填充时间来计算当前请求的排队时间。
  • 传输时间预测: 难度较大,因为它不仅取决于数据大小,还受网络状态和拥塞影响。这也促使了 KVCache 热点块的复制。

4.2.5.2. 缓存负载均衡 (Cache Load Balancing)

为了解决 KVCache 块流行度不均导致的热点问题和传输拥塞,Mooncake 提出了启发式自动热点迁移方案

  • 问题: 每个预填充机器维护自己的本地前缀缓存,但不同缓存的使用频率差异巨大(例如系统提示高频使用,特定文档缓存低频使用)。
  • 策略:
    1. Conductor 因实例负载高而未能将请求路由到具有最长前缀缓存的预填充实例时,如果估算的额外预填充时间短于传输时间,Conductor 会将缓存位置和请求转发给备用实例。这个备用实例会主动从持有者那里获取 KVCache 并存储到本地。
    2. 如果最佳远程前缀匹配长度不大于当前本地可复用前缀乘以一个阈值(kvcache_balancing_threshold),则倾向于直接计算输入词元而非传输 KVCache
  • 效果: 这两种策略不仅减少了请求的预填充时间,还促进了热点缓存的自动复制,使其更广泛地分布在多台机器上,从而实现缓存负载均衡。

4.2.6. 过载导向调度 (Overload-oriented Scheduling)

大多数现有 LLM 服务工作假设所有请求都将被处理,并侧重于吞吐量或 TTFT/TBT 优化。然而,在 MaaS 平台中,过载是常态。Mooncake 引入了过载导向调度来处理这类场景。

4.2.6.1. 过载场景下的调度 (Scheduling in Overload Scenarios)

  • 系统负载定义:Mooncake 的解耦架构中,预填充和解码阶段独立处理,因此负载通过 SLO 满足度来衡量。
    • lttftl_{ttft}:请求的 TTFT SLO 约束。
    • ltbtl_{tbt}:请求的 TBT SLO 约束。
    • 预填充和解码实例的负载通过将其预测的最大 TTFTTBTlttftl_{ttft}ltbtl_{tbt} 进行比较来确定。
  • 关键决策: 调度需要做出两个关键决策:
    1. 是否接受预填充阶段的请求,基于预填充实例的负载。
    2. 是否继续进行解码阶段,基于解码实例的负载。

4.2.6.2. 早期拒绝 (Early Rejection)

  • 问题: 如果一个请求在完成预填充阶段后,因为解码实例负载过高而被拒绝,那么预填充阶段消耗的计算资源就浪费了。

  • 策略: 早期拒绝策略将解码实例的负载评估提前到预填充阶段开始之前。当请求到达时,Conductor 基于预填充和解码池中较高的负载来评估是否接受请求。

  • 优势: 显著减少了因请求被拒绝而导致的无效计算,提高了负载均衡。

  • 挑战: 早期拒绝可能导致负载波动,如 Figure 9 所示。这是由于预测解码负载和实际执行之间存在时间差。

    Figure 9: The load of prefill and decoding instances over 20 minutes, before using the predictionbased early rejection. 该图像是图表,展示了在20分钟内预填充实例(Prefill)和解码实例(Decoding)的负载变化情况,表示在未使用基于预测的提前拒绝策略之前的性能波动。

Figure 9: The load of prefill and decoding instances over 20 minutes, before using the predictionbased early rejection. Figure 9 展示了在使用基于预测的早期拒绝策略之前,预填充实例和解码实例在 20 分钟内的负载情况。图中的曲线显示,预填充(Prefill)和解码(Decoding)实例的负载呈现出明显的反向波动,表明两者之间存在时间滞后和资源利用不平衡。

4.2.6.3. 基于预测的早期拒绝 (Early Rejection Based on Prediction)

为了解决早期拒绝导致的负载波动问题,Mooncake 提出了基于预测的早期拒绝框架。

Figure 10: Instance load when applying Early Rejection and Early Rejection Based on Prediction. 该图像是图表,展示了应用早期拒绝和基于预测的早期拒绝时的实例负载情况。图中的四个阶段分别展示了预填请求和解码请求在不同时间段的负载变化,并通过星号和箭头指示了接收和拒绝的决策。

Figure 10: Instance load when applying Early Rejection and Early Rejection Based on Prediction. Figure 10 对比了应用早期拒绝(Early Rejection)和基于预测的早期拒绝(Early Rejection Based on Prediction)时实例的负载情况。图 (a) 展示了早期拒绝策略下预填充和解码实例负载的剧烈波动,而图 (b) 展示了基于预测的早期拒绝策略如何缓解这种波动,使负载更加平稳。

  • 原理: 该框架预测请求预填充阶段完成后的解码负载,并据此决定是否接受请求。
  • 预测方法:
    • 请求级别预测 (Request level): 预测每个请求的输出长度是挑战,因为高成本或低准确性。如果能准确预测输出长度,就能更精确地估计 TTFTTBT
    • 系统级别预测 (System level): Mooncake 目前采用的是系统级别预测。它不试图预测单个请求的完成时间,而是估算指定时间后实例的总体批处理量或 TBT 状态。
      • 具体实现: 假设每个请求的解码阶段都花费统一的时间 tdt_d。在给定时间 tt
        1. 由预填充实例在 tt 时刻完成的请求被添加到统一的解码实例中。
        2. tt 之前执行时间超过 tdt_d 的请求将从解码实例中移除。
        3. 计算所有解码实例的平均 TBT 比率与 ltbtl_{tbt},以预测负载。
  • 优势: 缓解了早期拒绝带来的负载波动,提高了资源利用率。

5. 实验设置

5.1. 数据集

为了全面评估 Mooncake 的性能,实验采用了多种数据集,包括公共数据集、模拟数据和真实工作负载的重放数据。所有实验均使用一个遵循 LLaMA2-70B 架构的虚拟模型进行,以保护专有信息并方便复现。

以下是原文 Table 2 的数据集详情:

DatasetAvg Input LengthAvg Output LengthCache RatioArrival Pattern
ArXiv Summarization [26]8088229~0%Poisson Process
L-Eval [27]1901972>80%Poisson Process
Simulated Data16k, 32k, 64k, 128k51250%Poisson Process
Real Data7955194~50%Timestamp-based

以下是原文 Table 2 的结果:

  • ArXiv Summarization [26]:
    • 平均输入长度:8088 词元 (tokens)
    • 平均输出长度:229 词元
    • 缓存命中率:~0% (该数据集的请求通常不共享前缀,因此 KVCache 复用率低)
    • 请求到达模式:泊松过程 (Poisson Process)
  • L-Eval [27]:
    • 平均输入长度:19019 词元
    • 平均输出长度:72 词元
    • 缓存命中率:>80% (该数据集可能包含大量共享前缀的请求,KVCache 复用率高)
    • 请求到达模式:泊松过程
  • Simulated Data (模拟数据):
    • 输入长度:16k, 32k, 64k, 128k 词元 (专门用于测试长上下文性能)
    • 平均输出长度:512 词元
    • 缓存命中率:50%
    • 请求到达模式:泊松过程
  • Real Data (真实数据):
    • 平均输入长度:7955 词元
    • 平均输出长度:194 词元
    • 缓存命中率:~50%
    • 请求到达模式:基于时间戳 (Timestamp-based),即重放实际的请求轨迹。该数据集包含 23,000 条请求,是在 1 小时内的在线请求数据样本。

数据细节 (Listing 1): 为了保护用户隐私,真实数据轨迹经过匿名化处理,仅包含时间戳、输入长度、输出长度和哈希 ID

{ "timestamp": 27482, "input_length": 6955, "output_length": 52, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2353, 2354]
{ "timestamp": 30535, "input_length": 6472, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2366]
}
  • Timestamp:请求的相对到达时间,单位毫秒。
  • Input & Output Length:输入和输出词元数量,不含实际文本。
  • Hash ID:描述前缀缓存关系。通过对词元块(块大小 512)及其前置块进行哈希生成,然后映射到全局唯一 ID。相同的 Hash ID 表示可以共享 KVCache。例如,上述样本中前 12 个 Hash ID 相同,表示可以共享 12×512=614412 \times 512 = 6144 个词元的前缀缓存。

统计特征 (Figure 5 & Figure 6):

Figure 5: Input and output length distributions in the request trace. 该图像是图表,展示了请求跟踪中的输入和输出长度分布。左侧的蓝色直方图表示输入长度的频率分布,右侧的绿色直方图表示输出长度的频率分布。

Figure 5: Input and output length distributions in the request trace. Figure 5 展示了真实请求轨迹中输入和输出长度的分布。平均输入长度为 7,590 词元,平均输出长度为 182 词元,平均输入-输出比约为 720。这反映了 Kimi 在长上下文处理方面的能力。

Figure 6: CDF (Cumulative Distribution Function) of the block hit count in the request trace. 该图像是图表,展示了请求追踪中的块命中计数的累积分布函数(CDF)。横轴为块命中计数,纵轴为CDF值,图中显示了随着块命中计数增大,CDF逐渐接近1的趋势,反映了请求处理的效率。

Figure 6: CDF (Cumulative Distribution Function) of the block hit count in the request trace. Figure 6 展示了块命中计数的累积分布函数(CDF)。它揭示了 KVCache 块流行度的显著不平衡,超过 50% 的缓存块未被使用,而某些块被访问数万次。这强调了复制热点块以避免传输拥塞的重要性。

缓存策略分析 (Table 1):

以下是原文 Table 1 的结果:

Block capacityInf1000005000030000100001000
LRUCache0.510.510.500.480.400.30
LFUCache0.510.510.490.430.350.30
LengthAwareCache0.510.500.480.420.350.30

Table 1 比较了在不同缓存容量下 LRULFULengthAwareCache 三种缓存策略的命中率。随着缓存容量从 1,000 块增加到 50,000 块,缓存命中率从 30% 提高到 50%,但进一步增加容量改进不明显。LRUCache 在该数据集上表现最佳,这可能与请求利用率的时间局部性有关。

5.2. 评估指标

实验中关注在定义 SLO 下,不同系统的吞吐量表现。

  • 吞吐量 (Throughput): 通过每秒请求数 (Requests per Second, RPS) 来衡量。RPS 越高,表示吞吐量越高。
  • 首令牌时间 (Time to First Token, TTFT): 用户请求到达与模型生成第一个输出词元之间的时间。
  • 令牌间隔时间 (Time Between Tokens, TBT): 模型生成连续两个输出词元之间的时间。
  • 90th Percentile (P90): 评估 TTFTTBT 的主要指标,表示 90% 的请求满足该延迟要求。用于判断是否满足 SLO
  • 服务水平目标 (Service Level Objectives, SLOs):
    • TTFTP9010×基准值\mathrm{TTFT}_{\mathrm{P90}} \le 10 \times \text{基准值}:90% 的推理请求的 TTFT 不超过单请求无干扰运行下的 10 倍。
    • TBTP905×基准值\mathrm{TBT}_{\mathrm{P90}} \le 5 \times \text{基准值}:90% 的推理请求的 TBT 不超过单请求无干扰运行下的 5 倍。
    • 标准化: 为便于比较,所有 TTFTTBT 值都根据其上限进行了归一化,上限设为 1.0。
  • 有效吞吐量 (Goodput): 衡量的是在满足 SLO 的前提下,系统成功处理的请求数量。只有完全完成执行并满足 SLO 的请求才被计入有效吞吐量。否则,所有已消耗的资源都被视为浪费。

5.3. 对比基线

  • vLLM [13]: 作为业界最先进的开源 LLM 服务系统之一,被选作主要基线。
    • 优点: vLLM 整合了连续批处理(continuous batching)和 PagedAttention 等技术,显著提高了推理吞吐量。
    • 局限性: vLLM 的设计将推理请求的预填充和解码阶段耦合在一起。在长上下文场景中,这种耦合可能导致解码阶段的中断,影响 TBT SLO。为应对长上下文,vLLM 有时需要将请求单独处理,而非批处理。

5.4. 测试环境 (Testbed)

  • 硬件: 实验系统部署在一个高性能计算节点集群上。
    • 每个节点配置:8 块 NVIDIA-A800-SXM4-80GB GPU,每块 GPU 配备 80GB HBM 显存。
    • GPU 互联:通过 NVLINK 连接。
    • 网络:配备支持高达 800 Gbps 互联带宽的 RDMA 网卡。
  • 部署: 每个节点根据启动参数配置为预填充实例或解码实例。
  • 模型: 使用一个遵循 LLaMA2-70B 架构的虚拟模型(dummy model),以确保实验结果的可复现性并保护专有信息。

6. 实验结果与分析

6.1. 核心结果分析

6.1.1. 端到端性能

6.1.1.1. 公共数据集

本节评估了 MooncakevLLMArXiv SummarizationL-Eval 公共数据集上的端到端性能。

  • 基线配置: vLLM 使用 4 个实例,表示为 vLLM-[4M]
  • Mooncake 配置: 两种配置。
    1. Mooncake-[3P+1D]:3 个预填充实例(Prefill)和 1 个解码实例(Decoding)。

    2. Mooncake-[2P+2D]:2 个预填充实例和 2 个解码实例。

      以下是原文 Figure 11 的结果:

      Figure 11: End-to-end experiments of Mooncake and vLLM on the ArXiv Summarization and L-Eval datasets 该图像是图表,展示了Mooncake与vLLM在ArXiv Summarization和L-Eval数据集上的端到端实验结果。图中比较了不同请求速率下的P90 TTFT和P90 TBT,展示了Mooncake在高请求速率下的优越性能。

Figure 11: End-to-end experiments of Mooncake and vLLM on the ArXiv Summarization and L-Eval datasets

结果分析:

  • 吞吐量提升:
    • ArXiv Summarization 数据集上,Mooncake-[3P+1D]vLLM-[4M] 实现了 20% 的吞吐量提升,同时满足 SLO
    • L-Eval 数据集上,Mooncake-[3P+1D]vLLM-[4M] 实现了 40% 的吞吐量提升。L-Eval 数据集由于高缓存命中率(>80%),Mooncake 的前缀缓存机制进一步降低了预填充时间,从而显著提升了吞吐量。
  • 配置失衡影响:
    • Mooncake-[2P+2D] 虽然 TBT 延迟较低,但在 TTFT 指标上表现不如 Mooncake-[3P+1D]vLLM-[4M]。这表明预填充和解码实例之间的负载不平衡会影响整体性能。作者指出,在实际部署中,预填充和解码实例的比例需求在一定时期内相对稳定,可以预先设置。

6.1.1.2. 模拟数据

本节使用模拟数据进行端到端实验,重点关注长上下文场景。集群配置与公共数据集实验相同。

以下是原文 Figure 12 的结果:

Figure 12: End-to-end experiments of Mooncake and vLLM on simulated data. 该图像是图表,展示了Mooncake与vLLM在不同请求速率下的TTF和TBT性能。图中分别显示了16k、32k、64k和128k提示的实验结果,比较了不同架构在负载下的表现。Mooncake在高请求速率下的表现优于vLLM,验证了其优越的架构设计。

Figure 12: End-to-end experiments of Mooncake and vLLM on simulated data.

结果分析:

  • 长上下文优势: 模拟数据中的长上下文请求(如 16k, 32k, 64k, 128k 词元)显著干扰了 vLLM 的解码阶段。为了应对此问题,vLLM 不得不单独处理这些请求,而非进行批处理。
  • Mooncake 性能: Mooncake 即使采用批处理,其两阶段解耦设计也有效地最小化了预填充阶段对解码阶段的影响,确保 TBT SLO 不被打破。
  • 吞吐量显著提升: Mooncake 展示了显著更高的吞吐量,相比 vLLM,吞吐量提升范围从 50%525%,同时满足相同的 TTFTTBT SLO 约束。这验证了 Mooncake 在长上下文场景下的优越性。

6.1.1.3. 真实工作负载

本节使用真实请求轨迹(23,000 个请求)重放实验,以评估 Mooncake 在实际生产环境下的性能。

  • Mooncake 配置: 10 个预填充实例和 10 个解码实例,表示为 Mooncake-[10P+10D]

  • vLLM 配置: 20 个 vLLM 实例,表示为 vLLM-[20M]

  • SLO 阈值: TTFT 上限为 30 秒,TBT 上限为每词元 0.1 秒。

    以下是原文 Figure 13 的结果:

    Figure 13: Request TTFT and TBT distributions of Mooncake and vLLM under real workloads 该图像是图表,展示了Mooncake和vLLM在真实工作负载下请求的首次令牌到达时间(TTFT)和令牌之间时间(TBT)的累积分布函数(CDF)。图中的曲线显示了两个服务在性能方面的比较,Mooncake在TTFT上表现良好,符合其设计目标。

Figure 13: Request TTFT and TBT distributions of Mooncake and vLLM under real workloads

结果分析:

  • TTFT 分布: Mooncake-[10P+10D]vLLM-[20M]TTFT 分布几乎相同,接近 100% 的请求满足 TTFT SLO。这表明两个系统在首令牌生成速度上表现相当。
  • TBT 分布:
    • Mooncake-[10P+10D] 的请求几乎 100% 满足 TBT SLO
    • vLLM-[20M] 只有大约 57% 的请求满足 TBT SLO,并且一些请求表现出极高的 TBT。这再次印证了 vLLM 在长上下文或高负载下,预填充对解码阶段的干扰问题。
  • 处理请求量: 在此实验中,Mooncake 在满足 SLO 的前提下,能够处理约 75% 更多的请求。这突出显示了 Mooncake 架构在真实世界、高并发场景下的优势。

6.1.2. 过载场景下的性能

本节评估了 Mooncake 在过载场景下的性能,重点是系统能够处理的最大请求数量。为了模拟过载,将真实轨迹的重放速度提高到 2x

以下是原文 Table 3 的结果:

BaselineEarly RejectionEarly Rejection based on Prediction
Number of rejected requests418337713589

以下是原文 Table 3 的结果:

结果分析:

  • 基线策略 (Baseline): 拒绝了 4,183 个请求。该策略在预填充和解码两个阶段开始前基于负载拒绝请求,但如果预填充阶段已完成而解码阶段被拒绝,仍会造成资源浪费。
  • 早期拒绝 (Early Rejection): 拒绝了 3,771 个请求。与基线相比,拒绝的请求数量减少,表明通过提前评估解码负载,避免了不必要的预填充计算,从而提高了系统资源的有效利用。
  • 基于预测的早期拒绝 (Early Rejection based on Prediction): 拒绝了 3,589 个请求。这是性能最佳的策略,进一步减少了被拒绝的请求数量。这证明了通过预测解码实例的未来负载,Mooncake 能够缓解早期拒绝引起的负载波动,并进一步提高请求处理能力。

6.1.3. KVCache-centric 调度实验

为了验证 KVCache-centric 调度策略的有效性,作者在 Mooncake 集群上进行了调度实验,对比了不同策略。

  • 集群配置: 8 个预填充实例和 8 个解码实例。

  • 工作负载: 重放 23,000 个真实请求。

  • 评估指标: 平均 TTFTTTFT SLO 达成率。

    以下是原文 Figure 8 的结果:

    Figure 8: The prefill scheduling experiment in the Mooncake cluster. 该图像是一个箱线图,展示了在不同调度策略下的总延迟(TTFT)。横坐标表示不同的调度策略,包括KVCache-centric、cache-aware、load-balancing和random,纵坐标为延迟时间(秒)。图中标明了服务水平目标(SLO),并且KVCache-centric策略显示了最低的延迟,达到14.36秒。

Figure 8: The prefill scheduling experiment in the Mooncake cluster. Figure 8 展示了在 Mooncake 集群上进行的预填充调度实验结果。图中的柱状图比较了四种调度策略的平均 TTFT:随机调度(Random)、负载均衡调度(Load-balancing)、缓存感知调度(Cache-aware)和 KVCache-centric 调度。

结果分析:

  • TTFT 表现:
    • 随机调度 (Random): 平均 TTFT 最高(~17.15 秒),且 SLO 达成率最低(~70%)。
    • 负载均衡调度 (Load-balancing): 平均 TTFT 略低于随机调度(~16.71 秒),SLO 达成率有所提高(~75%)。
    • 缓存感知调度 (Cache-aware): 显著降低了平均 TTFT(~15.42 秒),SLO 达成率进一步提升(~80%),表明考虑缓存复用对性能有积极影响。
    • KVCache-centric 调度: 表现最佳,平均 TTFT 最低(~14.36 秒),SLO 达成率最高(~85%)。这证明了 KVCache-centric 调度(同时考虑缓存感知和缓存负载均衡)能够显著降低请求的 TTFT,并提高 SLO 满足率。

6.2. 消融实验/参数分析

论文中没有明确标注为“消融实验”的章节,但其对不同调度策略和早期拒绝策略的对比可以视为对 Mooncake 各个组件有效性的验证:

  • KVCache-centric 调度 (Figure 8): 通过对比随机、负载均衡、缓存感知以及 KVCache-centric 调度,验证了 KVCache 感知和负载均衡机制(即 KVCache-centric 调度)对于降低 TTFT 和提升 SLO 满足率的有效性。这实际上是一种组件效果的消融分析。
  • 早期拒绝策略 (Table 3, Figure 9, Figure 10): 对比了基线、早期拒绝和基于预测的早期拒绝三种策略,清晰地展示了早期拒绝策略能够减少资源浪费,而基于预测的早期拒绝策略则能进一步缓解负载波动并提高系统处理能力。这验证了在过载场景下,这些策略对于提高有效吞吐量的贡献。

7. 总结与思考

7.1. 结论总结

Mooncake 是一项针对 LLM 服务的创新性工作,旨在解决长上下文处理和高负载(过载)场景下的性能挑战。其核心是一个以 KVCache 为中心的解耦架构,主要贡献和结论包括:

  • 解耦架构: 通过将预填充和解码阶段分离到独立的集群,并利用 GPU 集群中未充分利用的 CPUDRAMSSD 资源构建一个大规模的解耦 KVCache 池,Mooncake 实现了更灵活的资源配置和更高的 KVCache 复用效率。

  • KVCache-centric 调度: 核心调度器 Conductor 能够智能地平衡 KVCache 复用、实例负载和 SLO 要求,通过缓存感知和热点迁移策略,显著降低 TTFT

  • 长上下文优化: 引入分块流水线并行(CPP)和逐层预填充(Layer-wise Prefill),高效处理长上下文请求,同时减少网络通信和 VRAM 占用。

  • 过载处理: 针对 MaaS 平台常见的过载问题,开发了基于预测的早期拒绝策略,有效减少了因请求被拒绝而导致的资源浪费,并稳定了系统负载。

  • 卓越性能: 实验结果表明,Mooncake 在长上下文场景下,吞吐量相较 vLLM 最高可提升 525%;在真实工作负载下,处理请求量增加了 75%,同时保持了高 SLO 满足率,尤其在 TBT 方面远超基线。

    总而言之,MooncakeLLM 服务提供了一个高效、稳健且适应性强的解决方案,特别适用于处理大规模、高并发且具有严格 SLO 要求的生产环境。

7.2. 局限性与未来工作

论文作者指出了 Mooncake 当前的局限性并提出了未来的研究方向:

  • 异构加速器利用: 当前旗舰加速器在计算、内存带宽和容量之间寻求平衡,但可能在某些单一指标上并非最优。未来计划探索使用异构加速器(例如,内存导向设备,如 GDDRLPDDRPIMHybrid Bonding 技术),这些设备在带宽和容量方面具有成本优势,可用于优化解码阶段的内存密集型操作。
  • 更细粒度的算子解耦: 考虑将注意力算子(在解码阶段通常是内存密集型)从其他线性算子中分离,以进一步提高资源利用率。
  • KVCache 优化技术集成: 结合其他 KVCache 缩减技术(如压缩、重要词元选择、跨层共享)来增加批处理大小并提高 KVCache 命中率。
  • 高级调度策略: 开发更复杂的调度策略,以处理不同请求优先级和具有不同 TTFT/TBT SLO 的场景。
  • KVCache 管理优化: 改进 KVCache 的复制、迁移和专门的淘汰策略(例如针对部分命中和过期场景)。
  • 动态资源平衡与卸载: 动态平衡预填充和解码实例的资源分配,并探索在工作负载波动时利用闲置资源进行批处理任务卸载(batch-oriented offloading tasks)。
  • 请求级别预测: 探索更准确的请求级别输出长度预测,以进一步优化调度决策。

7.3. 个人启发与批判

7.3.1. 个人启发

  1. KVCache 的核心价值重估: MooncakeKVCache 从一个仅仅是中间数据结构提升到系统架构和调度的核心,这提供了一个全新的视角。通过解耦 KVCache 存储并进行中心化管理和智能调度,极大地释放了其复用潜力和系统吞吐量。
  2. 解耦架构的深度思考: 论文不仅将预填充和解码阶段解耦,还深入考虑了 KVCache 的物理存储解耦(利用 CPU DRAMSSD),以及通过 CPP 和逐层预填充在计算和传输层面的解耦,这展示了多层次解耦的强大潜力。
  3. 过载场景的实战价值: 多数学术研究关注理想或资源充足的情况,而 Mooncake 直面 MaaS 平台最棘手的“过载”问题。其早期拒绝和基于预测的拒绝策略,对于保障生产系统的稳定性和有效吞吐量具有极高的实践价值。这提醒我们,在设计系统时,不仅要考虑“最佳情况”,更要考虑“最坏情况”或“常态化挑战”。
  4. 长上下文的系统级解决方案: 随着 LLM 上下文窗口的不断扩大,长上下文推理的性能瓶颈日益突出。Mooncake 提出的 CPP 和逐层预填充,提供了在系统层面解决这一挑战的有效途径,特别是其对网络带宽和 VRAM 占用的优化,具有前瞻性。
  5. 资源利用的精细化: 利用 GPU 服务器中 CPUDRAMSSD 这些常被忽视的“闲置”资源来存储 KVCache,是一种非常巧妙且成本效益高的资源利用方式。这启发我们在设计大规模系统时,应更全面地审视所有可用的异构资源。

7.3.2. 批判与潜在改进

  1. 预测准确性与鲁棒性: 基于预测的早期拒绝策略的有效性高度依赖于预测模型的准确性。尤其是在 LLM 工作负载动态变化、用户行为不可预测的真实环境中,系统级预测(目前 Mooncake 采用的)可能存在局限性。未来的请求级别预测虽然困难,但若能实现,将进一步提升系统性能。预测失败可能导致不必要的拒绝或 SLO 违反。
  2. 预填充与解码实例的动态比例调整: 论文提到 Mooncake-[2P+2D] 配置性能不佳是由于预填充和解码实例负载不平衡。目前系统需要预设实例比例。在动态工作负载下,如何实现预填充和解码实例数量的弹性伸缩和自动负载平衡,将是一个重要的挑战和改进方向。
  3. KVCache 热点迁移的策略深度: 论文中的 KVCache 热点迁移采用启发式方法。虽然有效,但在更复杂的网络拓扑、更精细的负载预测以及更严格的 SLO 约束下,可能需要更具决策理论基础的迁移策略,例如结合强化学习或更复杂的预测模型来优化迁移时机和目标。
  4. 异构加速器集成的复杂性: 论文提及未来探索异构加速器。这无疑是正确的方向,但实际集成过程中,如何协调不同类型加速器(计算导向 vs. 内存导向)的调度、数据传输、编程模型和故障处理,将是一个巨大的工程挑战。
  5. KVCache 压缩与剪枝的深度融合: 论文提到了 KVCache 压缩等算法作为未来工作。如果能将这些算法深度融入到 KVCache-centric 架构中,例如在 KVCache Pool 层实现智能的压缩/解压缩、生命周期管理和优先级剪枝,将可能带来更大的内存和带宽效率提升。
  6. 通用性评估: 尽管使用了多种数据集和真实工作负载,但 Kimi 的工作负载具有“长上下文”的特点。Mooncake 在短上下文、高 RPS 但低 KVCache 复用率的场景下,其解耦和 KVCache-centric 的优势是否依然显著,需要更广泛的验证。

相似论文推荐

基于向量语义检索推荐的相关论文。

暂时没有找到相似论文。