· 陈宸,仇实 · technical · 16 min read

LMCache&xPU.IO:当LMCache遇上直通存储

随着Agent成为主流,推理要处理的上下文已经增长到1M级别。Phoenix为LMCache提供了一个高性能直通存储后端,在生产trace回放中把高并发下的平均TTFT压低了5.6×,推理系统QPS提升2x以上。

概述

随着Agent成为主流,推理要处理的上下文已经增长到1M级别,单条会话的KV Cache涨到几十GB。HBM和DRAM的容量有限,价格还在一路上涨。

把KV Cache卸载到NVMe SSD是更划算的选择:单机就能有100TB级容量,成本也低得多。但SSD是离GPU最远的一层,数据取回来的延迟一高,GPU只能空等,利用率随之下降。

GPU直通存储让存储设备直接向GPU显存传输数据,主机内存不参与数据搬运。

Phoenix是一个全栈开源直通存储I/O栈,支持POSIX接口,使用io_uring进行加速,且跨厂商,支持多种存储后端。Phoenix为LMCache提供了一个高性能直通存储后端,在生产trace回放中把高并发下的平均TTFT压低了5.6×,推理系统QPS提升2x以上。

💡 关于 xPU.IO

xPU.io由腾讯DCPD(数据计算平台部)发起,专注面向AI应用的xPU直通存储,包括Phoenix以及Tutti(GPU-centric KV cache存储)。


KV Cache 的容量与速度挑战

负载特征变化

当前KV Cache的负载已经从chatbot转向agent,agentic负载特征是长horizon的多轮loop,在推理和工具调用之间反复切换。

Codex在SWE-bench Pro上的真实trace数据:

  • 📊 到第30轮时上下文通常已增长到约 80K tokens
  • 📈 最长超过 180K tokens
  • 🔄 每轮真正新增的只有几百到几千token
  • 💾 Input/Output token比约为 131:1
  • ✅ 缓存命中率 94.2%

前缀缓存住,prefill在这部分几乎是免费的,每轮成本只剩增量输入的计算成本。

两个核心要求

📦 容量要求

100K token的上下文动辄几十GB级,一台实例上挂着大量长会话,HBM和DRAM很快就会触发淘汰,而淘汰意味着下次回来要从零重算整段前缀。

SSD是唯一能承载这个量级的介质,单机100TB级,长会话数据可长期留存。

⚡ 速度要求

Trace里轮与轮之间的间隔中位数只有**几秒**,这就是留给加载的全部窗口:几十GB级的KV要在这几秒内回到显存。

缓存能否带来收益,取决于取回一段KV的耗时是否显著低于重算它;加载太慢,命中率再高也换不来时间。


现有路径:KV 需要经主机内存中转

问题分析

现有LMCache的文件存储方案,将SSD当作DRAM缓存,这种分层结构的特性恰好和需求相反:

容量最大的那层,离GPU最远、带宽最窄

数据两次穿越PCIe,中间多一次拷贝,整个过程还要CPU全程参与发起、同步、回调。

buffer = malloc(len);              // 主机内存做跳板
cudaMalloc(&devPtr, len);
pread(fd, buffer, len, offset);   // 盘 → 主机内存
cudaMemcpy(devPtr, buffer, len, H2D); // 主机内存 → 显存

性能损失

实测数据(4块PCIe 4.0 NVMe RAID 0):

指标数值说明
🔷 底层NVMe带宽25 GB/siostat观测
🔶 端到端KV加载10.2 GB/s实测性能
📉 带宽损失<40%不到裸盘的四成

Codex SWE-bench回放测试(20,230条请求):

  • 平均prompt长度:~68K tokens
  • TTFT均值:1101 ms
    • SSD加载时间:~600 ms(蓝色部分)
    • GPU prefill:313 ms
  • 主机内存中转导致了额外延迟

Phoenix:去掉伪缓冲区的直通存储栈

核心理念

Phoenix是一个开源的GPU直通存储中间件,最初发表在SC’25上。

它解决的核心问题是:传统上存储设备(如NVMe SSD)里的数据要先经过CPU和内存、再复制进GPU显存,路径长、开销大。

Phoenix让存储数据”绕过”CPU,一步直达GPU显存,从而显著提升数据加载速度、释放CPU算力。

技术优势

✅
不绑定厂商

构建在操作系统标准I/O栈之上,不依赖私有驱动

✅
兼容现有体系

无需修改应用和文件系统的使用方式

✅
低部署门槛

不需要umount/mount等操作,通过io_uring/libaio充分利用NVMe带宽

✅
跨厂商支持

已在NVIDIA、沐曦等厂商上验证


LMCache 集成 Phoenix

GDS L1框架

LMCache原生支持直通存储,提供了一套开放的GDS L1框架。它将NVMe上的slab file作为L1存储,对标CPU pinned DRAM以及Device-DAX。

GDS L1框架自顶向下可以分为两层:

🔷 DMA驱动层

  • ✦ 核心:进程全局的GDSContext
  • ✦ 驱动GPU和slab file之间的DMA
  • ✦ 维护小型staging buffer
  • ✦ 通过stream保证操作有序性

🔷 后端抽象层

  • ✦ 提供统一的GDS Backend抽象
  • ✦ 允许不同直通存储方案接入
  • ✦ GDSContext对具体Backend无感知
  • ✦ 只与标准API打交道

Stream Ordered I/O

Phoenix专门实现了对Stream Ordered I/O的支持。基于加速器runtime的LaunchHostFunc原语,Phoenix把一段由Host发起的DMA read/write包装成一个host callback挂到调用方的stream上。

顺序语义保证:

  • 📍 一次DMA Read之后排的kernel,一定看得到DMA搬回来的数据
  • 📍 一次DMA Write之前排的gather kernel,一定已经跑完,DMA读到的是稳定的数据
  • 📍 不需要额外的同步原语,同一条流上连续提交的DMA按提交顺序执行

集成方式

受益于GDS L1的开放性,向LMCache集成Phoenix的过程非常自然且轻量。

Phoenix项目为LMCache专门实现了一个API冻结的用户态库libphxfile,并基于这一用户态库实现了后端抽象层所需的接口,GDSContext就能够顺畅地通过Phoenix来直接进行GPU和NVMe之间的DMA了。


Phoenix Backend架构

层级结构

应用与框架
  vLLM / LMCache / 自定义应用
         ↓
应用适配器
  phxloader / phxcache / phxfile
         ↓
用户态 libphoenix
  设备发现、显存注册、地址解析
  同步/批量/异步 I/O ↔ phoenixfs
         ↓
Linux 文件系统与块层
  pread/pwrite 或 io_uring
  → NVMe/RDMA DMA

关键特性

🔌 Adapter 层

对接AI应用,Phoenix通过Adapter把能力交给应用:

  • ▸ libphxfile:纯C库,面向LMCache KV Cache卸载
  • ▸ phxloader:pybind11扩展,面向vLLM模型权重加载

Adapter这一层同时是解耦点:无论Phoenix内部怎么演进,应用侧都不感知

📂 I/O 层

复用Linux原生I/O栈:

  • ✓ GPU显存变成Linux I/O可直达的内存
  • ✓ 直接使用pread/pwrite、io_uring、线程池
  • ✓ 基于io_uring的批量I/O接口,一次系统调用下发N个请求
  • ✓ 4块PCIe 4.0 NVMe在512并发下能完全吃满硬件带宽

🔧 内核层

让显存成为内核认识的内存:

  • ◆ 借助Linux 4.3引入的ZONE_DEVICE机制
  • ◆ 为GPU显存建立struct page
  • ◆ 显存指针成为合法地址,不需要伪缓冲区
  • ◆ I/O直接走标准的文件系统、块层和原生NVMe驱动

🌐 兼容性

存储与GPU之间的万能Hub:

  • ★ 内核侧抽象显存的P2P映射
  • ★ 用户态侧抽象设备查找与显存拷贝原语
  • ★ 接入新加速卡只需补两个实现文件
  • ★ 支持ext4/xfs/NFS/BeeGFS/Lustre等文件系统

性能结果

测试配置

测试环境:

  • 🖥️ 硬件:8×H20(每卡96GB HBM)+ 4块NVMe Gen4 RAID 0
  • 🤖 模型:TP=8,256K上下文
  • 📊 Trace:生产trace(11,596条请求)
  • 👥 用户:请求次数6~476,平均长度70K,最大256K
  • 💾 KV Cache容量:约3.5TB

三种配置对比

🟠 DRAM Only

1TB DRAM
LRU淘汰策略
Cache miss重算

🔵 SSD中转

25TB SSD + 400GB DRAM
经主机内存中转
需要CPU参与

🔴 Phoenix

25TB SSD
GPU直通存储
无需主机内存

关键指标

🎯 性能提升

5.6×
TTFT改善
vs DRAM Only (高并发)
2.9×
QPS提升
vs SSD中转方案

服务能力对比(TTFT 5秒红线):

  • 🟠 DRAM Only: 7并发
  • 🔵 SSD中转: 13并发
  • 🔴 Phoenix: 37并发

性能分析

为什么Phoenix更快?

  1. 省掉主机内存中转 → 单次加载耗时直接降低
  2. 同样时间喂进GPU的KV更多 → 吞吐量提升
  3. 调度优化重新生效 → KV加载和推理可以overlap
  4. 加载快于计算 → 气泡被压进计算间隙
  5. 并发越高,曲线越平 → 规模化优势明显

LMCache+Phoenix 使用方法

快速开始(三步启动)

# ① 构建并安装 Phoenix(内核模块 + libphoenix)
git clone https://github.com/xPU-IO/Phoenix.git && cd Phoenix
mkdir -p build && cd build && cmake .. && make -j && sudo make install
nvidia-smi  # 先确保厂商驱动已加载
sudo make insmod  # 加载 phoenixfs 内核模块

# ② 构建并安装 LMCache 适配层(libphxfile.so)
bash adapters/LMCache/phxfile/install.sh

# ③ 启动 LMCache,指定后端
LMCache server ... \
  --gds-l1-backend phx \
  --gds-l1-path /mnt/nvme/LMCache_gds

说明:

  • --gds-l1-path 指向任意一个可写目录,slab就是那里的一个普通文件
  • LMCache侧只与libphxfile.so交互,libphoenix对它透明
  • phxFile*这套ABI已冻结,Phoenix的内部演进均在shim层吸收
  • 当前Phoenix已经支持5.0+的Linux内核

结语

💫 总结

📦 KV Cache需要更大的容量,SSD是当下唯一划算的选择

⚡ 容量解决了,速度还没有:数据从盘里取回显存要先在主机内存过一道,带宽打折、CPU陪跑

🔧 LMCache提供了开放、可灵活扩展的KV Cache管理框架,让不同存储后端能够方便地接入推理系统

🚀 Phoenix把这段路拉直,让存储直接向显存写数据。加载快了,L1就不必再靠昂贵的DRAM撑着

💰 用SSD做L1:容量更大、成本更低,同样的硬件和延迟要求下还能接更多并发


参考链接


🎉

感谢阅读!

欢迎加入 xPU.IO 社区,共同探索 AI 基础设施的未来

Share:
Back to Blog

Related Posts

View All Posts »