跳转至

KV Cache CPU 卸载指南

概述

KV Cache CPU 卸载功能可将不活跃的 KV cache 块从 NPU 内存卸载到 CPU 内存,从而在 NPU 内存有限时,让 vLLM 能够处理更长的上下文或更多的并发请求。当 NPU 上发生前缀缓存未命中,但数据存在于 CPU 内存中时,KV cache 会被异步加载回 NPU,从而降低重计算延迟。

该功能基于 vLLM 的 OffloadingConnector 框架构建。上游的 CPUOffloadingSpec 和 TieringOffloadingSpec 名称已注册到 Ascend NPU 实现中,这些实现使用专用 NPU 流在 NPU 与 CPU 之间进行高效的异步数据传输。

核心概念

  • CPU 块池:预先分配的 CPU 内存块池。仅使用 CPU 的 spec 在可用时使用固定(pinned)张量;多层级 spec 使用共享的 mmap 区域,以便调度器和二级层级可以访问相同的字节。
  • 异步传输:NPU 到 CPU(D2H)和 CPU 到 NPU(H2D)传输在独立的 NPU 流上执行,与计算重叠,以最大程度减少延迟影响。
  • LRU 淘汰:CPU 侧块池使用 LRU(最近最少使用)淘汰策略来高效管理有限的 CPU 内存。
  • 多层级卸载:TieringOffloadingSpec 复用 vLLM 的分层管理器,支持 CPU 主层级,并可选配二级层级,例如文件系统存储。

使用方法

Python API

from vllm import LLM, SamplingParams
from vllm.config import KVTransferConfig

kv_transfer_config = KVTransferConfig(
    kv_connector="OffloadingConnector",
    kv_role="kv_both",
    kv_connector_extra_config={
        "cpu_bytes_to_use": 8 * (1 << 30),
        "blocks_per_chunk": 8,
        "spec_name": "CPUOffloadingSpec",
    },
)

llm = LLM(
    model="Qwen/Qwen3-0.6B",
    gpu_memory_utilization=0.5,
    kv_transfer_config=kv_transfer_config,
)

sampling_params = SamplingParams(max_tokens=100, temperature=0.0)
outputs = llm.generate(["Hello, my name is"], sampling_params)
for output in outputs:
    print(f"Prompt: {output.prompt!r}")
    print(f"Generated: {output.outputs[0].text!r}")

在线服务

vllm serve Qwen/Qwen3-0.6B \
    --gpu-memory-utilization 0.5 \
    --kv-transfer-config '{
        "kv_connector": "OffloadingConnector",
        "kv_role": "kv_both",
        "kv_connector_extra_config": {
            "cpu_bytes_to_use": 8589934592,
            "blocks_per_chunk": 8,
            "spec_name": "CPUOffloadingSpec"
        }
    }'

多层级卸载

kv_transfer_config = KVTransferConfig(
    kv_connector="OffloadingConnector",
    kv_role="kv_both",
    kv_connector_extra_config={
        "cpu_bytes_to_use": 8 * (1 << 30),
        "blocks_per_chunk": 8,
        "spec_name": "TieringOffloadingSpec",
        "secondary_tiers": [
            {
                "type": "fs",
                "root_dir": "/tmp/vllm_kv_offload",
            }
        ],
    },
)

配置参数

  • kv_connector:必须设置为 "OffloadingConnector"。
  • kv_role:设置为 "kv_both" 以同时启用 KV cache 的存储和加载。
  • cpu_bytes_to_use:所有 worker 为 CPU 层级预留的总字节数。这是 vLLM 卸载 spec 所必需的。
  • blocks_per_chunk:每个被卸载的 chunk 中包含的 NPU KV-cache 块数量。该值必须大于零。另外,当所有 KV-cache 组使用相同 block size 时,block_size 可以指定以 token 为单位的 chunk 大小;这两个选项互斥。
  • spec_name:使用上游名称 "CPUOffloadingSpec" 进行仅 CPU 卸载,或使用 "TieringOffloadingSpec" 进行多层级卸载。vLLM Ascend 会将它们透明地映射到 NPU 实现。
  • secondary_tiers:TieringOffloadingSpec 使用的可选 vLLM 分层后端列表。每个条目是一个 dict;常用键:
    • type:后端类型。使用 "fs" 表示文件系统存储。
    • root_dir:该层级写入块文件的目录。
    • n_read_threads / n_write_threads:该层级 I/O 的线程池大小。对于高带宽后端(例如基于 RDMA 的 3FS),增加这些值有助于充分利用并行带宽。

调优文件系统(SSD / 3FS)二级层级

fs 层级复用 vLLM 的批处理文件系统实现。它在启动时检测 O_DIRECT,当文件系统拒绝直接 I/O 时自动回退到缓冲 I/O。要获得最佳的磁盘/3FS 卸载吞吐量:

  • 增大 blocks_per_chunk,以传输更大的 chunk 并降低元数据开销,同时要考虑由此带来的较粗的缓存命中粒度。
  • 提高 n_read_threads / n_write_threads 以匹配后端的并行度(与本地 SSD 相比,基于 RDMA 的 3FS 可以从更高的并发中获益)。
  • 保持 CPU 主层级(cpu_bytes_to_use)足够大,使得较慢的磁盘层级仅在处理真正的冷数据时才会被访问——只有当工作集超过 CPU 容量时,二级层级才会提升性能。
  • 文件系统(SSD / 3FS)二级层级的 kvcache 淘汰策略仍在开发中,将在未来版本中提供支持。

工作原理

  1. 正常推理:KV cache 块照常计算并存储在 NPU 上。
  2. 卸载到 CPU:当 NPU 内存已满且需要新块时,不活跃的 KV cache 块会通过专用 D2H NPU 流异步复制到 CPU 内存。
  3. 前缀缓存命中(CPU):当请求与之前计算的数据共享前缀,且 NPU 上未找到前缀缓存但 CPU 内存中存在该数据时,KV cache 块会通过专用 H2D NPU 流从 CPU 异步加载回 NPU。
  4. LRU 管理:当 CPU 内存已满时,CPU 块池使用 LRU 淘汰策略来丢弃最近最少使用的块。

可选:KV Cache 事件

您可以启用 KV cache 事件发布以进行监控或调试:

from vllm.config import KVEventsConfig

kv_events_config = KVEventsConfig(
    enable_kv_cache_events=True,
    publisher="zmq",
    endpoint="tcp://*:5555",
    topic="kv_events",
)

llm = LLM(
    model="Qwen/Qwen3-0.6B",
    gpu_memory_utilization=0.5,
    kv_transfer_config=kv_transfer_config,
    kv_events_config=kv_events_config,
)

注意事项

  • 此功能需要 vLLM v1 引擎。
  • 根据可用的 CPU 内存调整 cpu_bytes_to_use。保留过多可能会导致宿主机出现内存不足(out-of-memory)错误。
  • CPUOffloadingSpec 在可用时使用固定(页锁定)张量。TieringOffloadingSpec 必须使用 vLLM 的共享 mmap 主层级;CANN 没有提供与 CUDA 任意 mmap 主机注册在内存拷贝方面兼容的等效机制,因此其 NPU↔CPU 带宽必须在目标宿主机和对应的 CANN 版本上单独进行基准测试。
  • gpu_memory_utilization 参数控制为 KV 缓存保留多少 NPU 内存。较低的值会为 KV 缓存留下更少的 NPU 内存,从而使卸载更加频繁。
  • 对于生产工作负载,请使用真实的请求模式进行基准测试,以找到最佳的 cpu_bytes_to_use 和 blocks_per_chunk 设置。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 vl/vllm-ascend