SAC:面向稀疏注意力大模型的 CXL 解耦 KV Cache 系统

本文翻译并整理自论文 SAC: Disaggregated KV Cache System for Sparse Attention LLMs with CXL(arXiv:2606.19746v1,2026 年 6 月 18 日)。原论文采用 CC BY 4.0 许可。为适应博客阅读,本文省略参考文献列表中的完整出版信息,但保留正文结构、关键论证、实验结果与附录要点。 随着大模型进入长上下文与稀疏注意力时代,推理系统的主要瓶颈正从算力转向内存容量。传统 RDMA 解耦 KV Cache 系统会在解码前把完整前缀 KV Cache 搬回本地;但稀疏注意力每一步只访问少量 top-k 条目,这种“全量搬运、少量使用”的方式会同时浪费网络带宽和本地内存。 SAC 的核心思路是:使用 CXL 的低延迟、缓存行粒度 load/store 语义,把 KV Cache 留在解耦内存池中,只在计算时按需读取被选中的 top-k 条目。论文在 DeepSeek-V3.2 与 SGLang 上的实验显示,相比 RDMA 基线,SAC 可实现最高约 2.1 倍吞吐量、9.7 倍更低的 TTFT,以及 1.8 倍更低的 TBT。 摘要 大模型向长上下文推理扩展,使服务系统的主要瓶颈从计算能力转向内存容量。面向稠密注意力模型的传统方案通常采用基于 RDMA 的解耦内存池,在解码开始前,以粗粒度方式将整个前缀 KV Cache 从远端存储取回本地内存。 然而,这种方法并不适合新兴的稀疏注意力模型。解码过程中虽然只有很少一部分 KV 条目真正活跃,系统仍然要把完整 KV Cache 拉回本地,从而造成严重的传输瓶颈和本地内存浪费。 ...

2026年8月28日 · 5 分钟 · Hellokitty

NVIDIA Dynamo 源码阅读(三):KV-aware Router 如何选择 Worker

普通负载均衡只关心哪个 Worker 更空闲。LLM 推理还需要回答另一个问题:哪个 Worker 已经缓存了当前请求的最长前缀?如果忽略缓存局部性,相同 system prompt、文档或多轮会话会在不同 GPU 上反复 Prefill。 Dynamo 的 KV-aware Router 将缓存命中与运行负载放进同一次决策。本文基于提交 27f09d5,重点阅读 lib/kv-router 与 lib/llm/src/kv_router。 一、路由问题如何形式化 设请求 token 被按固定 block size 切成若干块: [t0 ... t15] [t16 ... t31] [t32 ... t47] [剩余 token] B0 B1 B2 每个完整块计算链式哈希。Router 维护如下关系: B0 -> {worker 1, worker 3} B1 -> {worker 1} B2 -> {worker 1} 如果新请求具有相同前三块,Worker 1 的重叠长度最大。但它可能已经非常繁忙,因此最终决策不是简单的最长前缀匹配,而是 locality 与 load 的权衡。 二、为什么使用链式 block hash compute_block_hash_for_seq 不会孤立地哈希每个 token 块,而是把前一个块的 hash 纳入下一个块。这使相同内容出现在不同前缀后时不会被错误视为同一缓存位置。 ...

2026年8月26日 · 2 分钟 · Hellokitty

Mini-SGLang 源码阅读(三):Paged KV Cache 与 Radix Prefix Cache

KV Cache 是在线 LLM 推理中最重要的状态。它避免 Decode 每轮重新计算全部历史 token,却也通常成为显存容量和并发数的主要限制。 本文先解释 KV Cache、分页管理和前缀复用的基本原理,再阅读 Mini-SGLang 的 MHAKVCache、CacheManager 与 RadixPrefixCache。源码基于提交 9a91cfa。 一、为什么需要 KV Cache 自回归 Attention 在第 t 步需要当前 Query 与位置 0...t 的 Key、Value 做注意力。如果每轮都重新计算历史 K、V,生成 n 个 token 会重复执行大量投影计算。 KV Cache 将每层历史 K、V 保存下来: 第 1 轮:计算 K0,V0,保存 第 2 轮:只计算 K1,V1,读取 [K0,K1] 第 3 轮:只计算 K2,V2,读取 [K0,K1,K2] 缓存大小大致为: 2 × 层数 × token 数 × KV head 数 × head_dim × 元素字节数 其中 2 表示 Key 和 Value。长上下文、大 batch 和高精度都会快速放大显存消耗。 ...

2026年8月25日 · 3 分钟 · Hellokitty

vLLM 与 Mooncake 对接源码解读:Prefill/Decode 分离中的 KV Cache 如何跨节点传输

深入分析 vLLM 内置 MooncakeConnector:从代理拆分请求、Scheduler 元数据、GPU KV Cache 注册,到 Mooncake Transfer Engine 通过 RDMA 将 Prefill KV 直接搬到 Decode 节点。

2026年8月24日 · 9 分钟 · Hellokitty

Mooncake Store 源码阅读(三):Get、副本选择与淘汰回收

写入建立对象,读取和淘汰决定缓存系统能否长期稳定运行。本篇沿 Get、Remove 与后台 Eviction 三条路径,观察 Mooncake Store 如何维护副本可读性和容量平衡。 源码基线仍为 777cc77。 一、Get 首先读取的是元数据 Client 不知道对象当前在哪台机器,也不应缓存一份永远不变的地址。 读取开始时,Client 向 Master 请求副本列表。核心入口之一是 MasterService::GetReplicaList。 Master 查找 key 对应的 ObjectMetadata,然后筛选当前允许读取的副本。返回结果包含 Segment、offset、长度和介质等信息。 随后 Client 才通过 Transfer Engine 把对象复制到本地 Buffer。 二、不是列表里的每个副本都可读 一个对象可能同时存在以下副本: 已完成并可读的内存副本。 正在复制的动态副本。 写入失败、等待清理的副本。 位于本地盘的副本。 所在 Segment 正在卸载的副本。 因此 Get 不能只检查 replicas 是否非空。源码中的 HasReadableReplica 以及各种状态判断,负责把控制面中的暂态副本排除掉。 读取正确性的一个重要来源,就是“只从已提交的副本集合中选择”。 三、副本选择优化什么 拥有多个可读副本后,系统还要选择来源。 理想选择通常考虑: 是否位于本机或同一故障域。 介质是 DRAM、VRAM 还是磁盘。 传输协议和拓扑成本。 副本是否正在被回收。 是否能满足本次 Buffer 类型。 Mooncake 将元数据筛选与实际传输分开,使选择策略可以持续演进。Master 保证候选集合合法,Client 和 Transfer Engine 完成具体数据路径。 四、读取失败不等于对象不存在 控制面返回副本后,数据面仍可能失败。例如节点刚好退出、网络断开,或 Segment 已经不可访问。 ...

2026年8月24日 · 2 分钟 · Hellokitty

Mooncake Store 源码阅读(二):Put 写入链路与对象原子性

Mooncake Store 的 Put 不是一次 RPC。它是一段跨越 Client、Master、分配器和 Transfer Engine 的两阶段流程。 本文继续使用提交 777cc77。阅读重点是 real_client.cpp 与 master_service.cpp 中的写入路径。 一、为什么 Put 必须拆成两段 如果 Master 收到 Put 请求后立刻把对象标记为可读,其他 Client 可能读到尚未传完的数据。 如果等所有数据都发送给 Master,再由 Master 落到目标节点,控制面又会成为数据面瓶颈。 Mooncake Store 的做法是:Master 先预留副本,Client 直接传输,最后由 Master 提交状态。 PutStart -> 返回目标副本 -> 直接传输对象 -> PutEnd 这相当于围绕一次数据面操作建立轻量级提交协议。 二、Client 侧的准备工作 Put 开始前,RealClient 需要确定源 Buffer 的位置和长度。源数据可能来自普通主机内存,也可能来自已经注册的加速器内存。 Client 会把大对象切成适合传输的任务。每个任务包含本地地址、远端 Segment、远端 offset 和长度,然后交给 Transfer Engine。 Store 不重复实现 RDMA、TCP 或 GPU Direct 细节。它只把“对象副本”翻译成 Transfer Engine 能执行的传输描述。 ...

2026年8月24日 · 2 分钟 · Hellokitty

Mooncake Store 源码阅读(一):从对象存储接口到控制面与数据面

Mooncake Transfer Engine 解决的是“怎样快速搬数据”,Mooncake Store 解决的则是更上层的问题:一个对象叫什么、放在哪些节点、有哪些副本、何时可读、空间不足时淘汰谁,以及 Master 重启后怎样恢复这些事实。 本文使用 Mooncake 仓库提交 777cc77 作为源码基线。这个版本的 Store 已经远超早期原型,包含多租户配额、内存与本地盘分层、动态副本、批量淘汰、快照和热备等能力。 一、先看整体分层 Mooncake Store 可以拆成四层。 第一层是上层调用者。vLLM、SGLang 或其他推理系统通过 Python、C++、Rust、Go 等接口访问对象。 第二层是 Client。RealClient 负责本地缓冲区、Master RPC、数据传输、重试和资源清理。 第三层是 Master。MasterService 保存对象元数据,管理 Segment、分配副本、维护租户配额,并驱动淘汰和复制。 第四层是数据资源。DRAM、VRAM、本地 SSD 或其他后端提供真正保存字节的空间,Transfer Engine 执行跨节点传输。 数据不会先发送到 Master,再由 Master 转发。Master 只告诉 Client 应该访问哪些副本,真正的大块数据直接在 Client 与目标内存之间移动。 二、源码目录怎样阅读 建议先抓住以下文件。 mooncake-store/include/real_client.h:Client 的主要状态和接口。 mooncake-store/src/real_client.cpp:Put、Get、Remove 与初始化流程。 mooncake-store/include/master_service.h:Master 的核心数据结构。 mooncake-store/src/master_service.cpp:元数据状态机和控制逻辑。 mooncake-store/include/replica.h:副本描述与状态。 mooncake-store/include/segment.h:可分配存储资源。 mooncake-store/src/allocation_strategy.cpp:副本放置策略。 mooncake-store/src/allocator.cpp:具体空间分配。 mooncake-store/src/transfer_task.cpp:Store 到 Transfer Engine 的任务封装。 不要一开始就顺序阅读体量巨大的 master_service.cpp。更有效的方法是从 RPC 接口出发,沿 PutStart、PutEnd、GetReplicaList 和 Remove 四条链路向下追踪。 ...

2026年8月24日 · 2 分钟 · Hellokitty

Mooncake Transfer Engine 源码阅读(一):统一传输 API 与整体架构

Mooncake Transfer Engine(简称 TE)是 Mooncake 数据平面的基础组件。它不负责决定 KV Cache 应该放在哪里,而是提供统一接口,把一段本地内存搬到远端 Segment,或者从远端 Segment 读取到本地内存。 本文基于 Mooncake 官方仓库: commit: 777cc7782417b6e554cf7c2d53210d0d8f89f5cc commit date: 2026-08-21 当前仓库同时保留经典 Transfer Engine 和下一代 TENT。前三篇先阅读经典实现,第四篇再分析 TENT 如何重构控制面、调度和传输后端。 一、源码布局 核心目录为 mooncake-transfer-engine/: 路径 作用 include/transfer_engine.h 对外 C++ API include/transfer_engine_impl.h 经典实现内部接口 include/transport/transport.h Transport 抽象、请求和状态 include/transfer_metadata.h Segment、Buffer 与元数据接口 src/transfer_engine.cpp 公共 API 转发层,同时兼容经典 TE 与 TENT src/transfer_engine_impl.cpp 初始化、内存注册、Segment 与批次管理 src/multi_transport.cpp 安装和选择具体 Transport src/transport/ RDMA、TCP、NVLink、NVMe-oF、EFA 等后端 tent/ Transfer Engine Next 实现 TE 的经典架构可以概括为: 应用 / Mooncake Store │ ▼ TransferEngine │ ▼ TransferEngineImpl ┌────┼──────────────┐ ▼ ▼ ▼ Metadata MultiTransport Batch 生命周期 │ ┌──────┼───────────────┐ ▼ ▼ ▼ ▼ RDMA TCP NVLink NVMe-oF ... 二、公共 API 是一层门面 TransferEngine 类本身很薄,大多数函数转发给 TransferEngineImpl: ...

2026年8月21日 · 3 分钟 · Hellokitty