KV缓存CPU卸载指南#

概述#

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

该功能基于vLLM的OffloadingConnector框架构建,并提供了Ascend NPU专用实现(NPUOffloadingSpec),使用专用NPU流在NPU和CPU之间进行高效的异步数据传输。

关键概念#

  • CPU块池:预分配的CPU内存块池(可选锁定),用于存储卸载的KV缓存数据。

  • 异步传输:NPU到CPU(D2H)和CPU到NPU(H2D)传输在独立的NPU流上执行,与计算重叠以最小化延迟影响。

  • LRU淘汰:CPU端块池使用LRU(最近最少使用)淘汰策略来高效管理有限的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={
        "num_cpu_blocks": 1000,
        "block_size": 128,
        "spec_name": "NPUOffloadingSpec",
        "spec_module_path": "vllm_ascend.kv_offload.npu",
    },
)

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": {
            "num_cpu_blocks": 1000,
            "block_size": 128,
            "spec_name": "NPUOffloadingSpec",
            "spec_module_path": "vllm_ascend.kv_offload.npu"
        }
    }'

配置参数#

  • kv_connector:必须设置为"OffloadingConnector"

  • kv_role:设置为"kv_both"以同时启用KV缓存的存储和加载。

  • num_cpu_blocks:在CPU内存中分配的块数。对于更长上下文场景,请增加此值。每个块消耗的内存与block_size × num_layers × (key_size + value_size)成正比。

  • block_size:CPU端块大小。应为NPU端块大小的倍数。典型值:128

  • spec_name:对于Ascend NPU,必须为"NPUOffloadingSpec"

  • spec_module_path:必须为"vllm_ascend.kv_offload.npu"

工作原理#

  1. 正常推理:KV缓存块照常在NPU上计算和存储。

  2. 卸载到CPU:当NPU内存已满且需要新块时,非活跃的KV缓存块通过专用D2H NPU流异步复制到CPU内存。

  3. 前缀缓存命中(CPU):当请求与先前计算的数据共享前缀,且NPU上未找到前缀缓存但CPU内存中存在时,KV缓存块通过专用H2D NPU流从CPU异步加载回NPU。

  4. LRU管理:当CPU内存已满时,CPU块池使用LRU淘汰策略丢弃最近最少使用的块。

可选:KV缓存事件#

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

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内存调整num_cpu_blocks。使用过多块可能导致主机内存不足错误。

  • 在可用时使用锁定(页锁定)内存以获得最佳传输性能。

  • gpu_memory_utilization参数控制为KV缓存保留的NPU内存量。较低的值会为KV缓存留下较少的NPU内存,使卸载更加活跃。

  • 对于生产工作负载,请使用真实请求模式进行基准测试,以找到最佳的num_cpu_blocksblock_size设置。