Sparse KV Offload 部署指南 ​

1. 概述 ​

在昇腾 A3 上部署 PD 分离 推理,并在 Decode 启用 Sparse KV Offload(可选 小包聚合)。适用 DeepSeek-V3.2 等带 index_topk 的 DSA / SFA 模型。

  • Sparse KV Offload:完整 Decode KV 放 Host DDR(MemFabric SHARED),NPU 仅保留 Indexer 与 top-K 热缓冲,miss 时 H2D onload。Prefill 可用 Layerwise(memcache)省 HBM;P→D 经 SfaRemoteD2HConnector 直写 Decode Host pool。
  • 小包聚合(可选):eager 路径下 TP0 聚包后一次 H2D,再 broadcast/scatter,降低离散小包 DMA 开销。代码在私仓分支,未合入官方 v0.26.0rc1;常规部署用官方 releases/v0.26.0rc。私仓:https://github.com/zd1204/vllm-ascend/tree/group_aggregation_cpu
  • 组件:vLLM / vLLM-Ascend、MemFabric、MemCache(仅 P)、PD Proxy。

社区说明:https://docs.vllm.ai/projects/ascend/en/latest/user_guide/feature_guide/layerwise_and_sparse_kv_cache_offloading.html

2. 环境准备 ​

KEYVALUE
服务器建议 2 台昇腾 A3(一台 P、一台 D)
操作系统openEuler(与镜像匹配)
容器镜像quay.io/ascend/vllm-ascend:v0.26.0rc1-a3-openeuler
vLLM / vLLM-Ascendreleases/v0.26.0 / 官方 releases/v0.26.0rc(小包聚合可选私仓 group_aggregation_cpu)
MemFabric / MemCacherelease/1.2(MemCache 仅 P)
模型示例/data/models/DeepSeek-V3.2-W8A8

P/D 需互通。下文示例 P=10.0.1.10、D=10.0.1.11。nic_name / local_ip 在容器外用 ip addr 查看后填入。

3. 部署流程 ​

3.1 启动容器(P、D) ​

--network=host;-v /nvme1n1:/data 可按需改;--device /dev/davinci* 按实际 NPU 增减。

shell
docker run \
  --ipc=host \
  -u 0 \
  --name vllm-offloading-test \
  --privileged \
  --network=host \
  --device /dev/davinci0 \
  --device /dev/davinci1 \
  --device /dev/davinci2 \
  --device /dev/davinci3 \
  --device /dev/davinci4 \
  --device /dev/davinci5 \
  --device /dev/davinci6 \
  --device /dev/davinci7 \
  --device /dev/davinci8 \
  --device /dev/davinci9 \
  --device /dev/davinci10 \
  --device /dev/davinci11 \
  --device /dev/davinci12 \
  --device /dev/davinci13 \
  --device /dev/davinci14 \
  --device /dev/davinci15 \
  --device=/dev/davinci_manager \
  --device=/dev/devmm_svm \
  --device=/dev/hisi_hdc \
  -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
  -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
  -v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
  -v /usr/local/sbin/:/usr/local/sbin/ \
  -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \
  -v /var/log/npu/slog/:/var/log/npu/slog \
  -v /var/log/npu/profiling/:/var/log/npu/profiling \
  -v /var/log/npu/dump/:/var/log/npu/dump \
  -v /usr/local/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \
  -v /nvme1n1:/data \
  -e GIT_SSL_NO_VERIFY=true \
  -dit \
  quay.io/ascend/vllm-ascend:v0.26.0rc1-a3-openeuler \
  bash

3.2 编译安装依赖(P、D;MemCache 仅 P) ​

shell
pip uninstall -y vllm
pip uninstall -y vllm-ascend

# vLLM
git clone https://gh-proxy.org/https://github.com/vllm-project/vllm.git -b releases/v0.26.0
pip install setuptools_rust
cd vllm/
VLLM_TARGET_DEVICE=empty pip install -v -e . --no-build-isolation -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
pip install matplotlib msguard openpyxl tzdata -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
cd ..

# vLLM-Ascend(官方;不含小包聚合,见第 4 节)
git clone https://gh-proxy.org/https://github.com/vllm-project/vllm-ascend.git -b releases/v0.26.0rc
cd vllm-ascend/
pip install -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple \
  --trusted-host mirrors.huaweicloud.com \
  --extra-index-url https://mirrors.huaweicloud.com/ascend/repos/pypi \
  -v -e .
cd ..

# MemFabric
pip uninstall -y memfabric_hybrid
git clone https://gitcode.com/Ascend/memfabric_hybrid.git -b release/1.2
cd memfabric_hybrid/
bash script/build_and_pack_run.sh
bash output/memfabric_hybrid-1.2.1_linux_aarch64.run
cd ..

# MemCache(仅 P)
pip uninstall -y memcache_hybrid
git clone https://gitcode.com/Ascend/memcache.git -b release/1.2
cd memcache/
git submodule init
git submodule update
cd 3rdparty/
rm -rf memfabric_hybrid
git clone https://gitcode.com/Ascend/memfabric_hybrid.git -b release/1.2
cd ..
bash script/build_and_pack_run.sh
bash output/memcache_hybrid-1.2.0_linux_aarch64.run
cd ..

P 节点编辑 /usr/local/memcache_hybrid/latest/config/mmc-local.conf:

配置项建议值
ock.mmc.local_service.protocolhost_shm
ock.mmc.local_service.dram.size10G(按内存调整)

3.3 环境变量(P、D) ​

追加到 ~/.bashrc(改 nic_name / local_ip;MEMFABRIC_HYBRID_EXTEND_LIB_PATH 版本号与安装包一致),然后 source ~/.bashrc:

shell
nic_name="xxxxxx"   # 容器外 ip addr
local_ip=x.x.x.x

export HCCL_IF_IP=$local_ip
export HCCL_IF_BASE_PORT=50000
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export HCCL_BUFFSIZE=400
export HCCL_OP_EXPANSION_MODE="AIV"

export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=3000
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=1
export VLLM_USE_V1=1
export VLLM_WORKER_MULTIPROC_METHOD=spawn

source /usr/local/memfabric_hybrid/set_env.sh
export MMC_LOCAL_CONFIG_PATH=/usr/local/memcache_hybrid/latest/config/mmc-local.conf
export MEMFABRIC_HYBRID_EXTEND_LIB_PATH=/usr/local/memfabric_hybrid/1.2.1/aarch64-linux/lib64
export PYTHONHASHSEED=0

3.4 启动 MemCache Meta(仅 P) ​

shell
mkdir -p /workdir
cd /workdir

创建 start_meta.sh:

shell
#!/bin/bash
source /usr/local/memcache_hybrid/set_env.sh
source /usr/local/memfabric_hybrid/set_env.sh
export MMC_META_CONFIG_PATH=/usr/local/memcache_hybrid/latest/config/mmc-meta.conf
python -c "from memcache_hybrid import MetaService; MetaService.main()"
shell
chmod +x ./start_meta.sh
nohup ./start_meta.sh 2>&1 &

3.5 启动 Prefill(P) ​

--tensor-parallel-size 与 NPU 数一致;端口需与代理一致。SfaRemoteD2HConnector 写 Decode Host pool;AscendStoreConnector + use_layerwise 为 Prefill Layerwise。

shell
vllm serve /data/models/DeepSeek-V3.2-W8A8 \
  --host 0.0.0.0 \
  --port 29180 \
  --tensor-parallel-size 16 \
  --served-model-name deepseek-v3.2 \
  --max-num-seqs 4 \
  --block-size 128 \
  --max-model-len 132096 \
  --trust-remote-code \
  --gpu-memory-utilization 0.95 \
  --quantization ascend \
  --enable-chunked-prefill \
  --max-num-batched-tokens 1024 \
  --enable-prefix-caching \
  --enable-expert-parallel \
  --speculative-config '{"method": "mtp", "num_speculative_tokens": 3}' \
  --kv-transfer-config '{
    "kv_connector": "MultiConnector",
    "kv_role": "kv_producer",
    "kv_connector_extra_config": {
      "connectors": [
        {
          "kv_connector": "SfaRemoteD2HConnector",
          "kv_role": "kv_producer",
          "kv_connector_extra_config": {
            "transfer_backend": "memfabric"
          }
        },
        {
          "kv_connector": "AscendStoreConnector",
          "kv_role": "kv_producer",
          "kv_connector_extra_config": {
            "backend": "memcache",
            "use_layerwise": true,
            "layerwise_num_shared_buffers": 3,
            "layerwise_independent_layers": [0]
          }
        }
      ]
    }
  }' \
  --safetensors-load-strategy 'prefetch' \
  --additional-config '{
    "enable_mlapo": false
  }'

3.6 启动 Decode(D,含 Sparse KV Offload) ​

  • kv_role: kv_consumer;sparse_kv_offload_config.enabled: true
  • topk_buffer_size ≥ index_topk 且能被 block_size 整除(实践可取 2 * index_topk)
  • dram_size_per_dp_GB 须能放下该 DP 完整 KV;配置非法会导致启动/运行失败
shell
vllm serve /data/models/DeepSeek-V3.2-W8A8 \
  --host 0.0.0.0 \
  --port 29181 \
  --tensor-parallel-size 16 \
  --served-model-name deepseek-v3.2 \
  --max-num-seqs 4 \
  --block-size 128 \
  --max-model-len 132096 \
  --trust-remote-code \
  --gpu-memory-utilization 0.95 \
  --quantization ascend \
  --enable-chunked-prefill \
  --max-num-batched-tokens 120 \
  --no-enable-prefix-caching \
  --enable-expert-parallel \
  --speculative-config '{"method": "mtp", "num_speculative_tokens": 3}' \
  --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
  --kv-transfer-config '{
    "kv_connector": "SfaRemoteD2HConnector",
    "kv_role": "kv_consumer",
    "kv_port": 20050,
    "kv_connector_extra_config": {
      "transfer_backend": "memfabric",
      "use_layerwise": true
    }
  }' \
  --safetensors-load-strategy 'prefetch' \
  --additional-config '{
    "enable_mlapo": false,
    "sparse_kv_offload_config": {
      "enabled": true,
      "topk_buffer_size": 4096,
      "dram_size_per_dp_GB": 512
    }
  }'

3.7 启动 PD 代理(P 容器)与压测 ​

客户端访问 http://<P_IP>:21600。长序列(如 >64K / 128K)更易观察 Offload 收益;关注 tpot 与吞吐。

shell
cd /workspace/vllm-ascend/examples/disaggregated_prefill_v1
# 若源码在其它路径,请改为实际 vllm-ascend 目录下的 examples 路径

python load_balance_proxy_layerwise_server_example.py \
    --host 10.0.1.10 \
    --port 21600 \
    --prefiller-hosts 10.0.1.10 \
    --prefiller-ports 29180 \
    --decoder-hosts 10.0.1.11 \
    --decoder-ports 29181
shell
vllm bench serve \
  --backend openai \
  --base-url http://10.0.1.10:21600 \
  --endpoint /v1/completions \
  --model deepseek-v3.2 \
  --tokenizer /data/models/DeepSeek-V3.2-W8A8 \
  --trust-remote-code \
  --skip-chat-template \
  --dataset-name custom \
  --dataset-path long_prompts99/prompts_128k_8_prefix_cache99.jsonl \
  --percentile-metrics ttft,tpot \
  --metric-percentiles 0,50,90,99,100 \
  --custom-output-len 1024 \
  --num-prompts 1 \
  --max-concurrency 1 \
  --ignore-eos \
  --temperature 0

3.8 约束 ​

  1. 仅支持带 index_topk 的稀疏注意力;不支持 compress ratio、CP、PP、Model Runner V2(以当前实现为准)。
  2. 生产路径为 PD Decode(kv_consumer)。
  3. MemCache Meta / mmc-local.conf 仅 P;D 侧重 MemFabric + Sparse Offload。

4. 小包聚合(可选) ​

叠加在 Decode Sparse Offload onload 上。官方 v0.26.0rc1 不含此能力,需私仓:https://github.com/zd1204/vllm-ascend/tree/group_aggregation_cpu

shell
pip uninstall -y vllm-ascend

# 国内可加 https://gh-proxy.org/ 前缀
git clone https://github.com/zd1204/vllm-ascend.git -b group_aggregation_cpu
cd vllm-ascend/
pip install -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple \
  --trusted-host mirrors.huaweicloud.com \
  --extra-index-url https://mirrors.huaweicloud.com/ascend/repos/pypi \
  -v -e .
cd ..

Decode 启动前:

shell
export VLLM_ASCEND_ENABLE_CPU_GATHER_H2D=1
export VLLM_ASCEND_CPU_GATHER_THREADS=4
export VLLM_ASCEND_CPU_GATHER_BUFFER_BYTES=8388608

关闭:

shell
export VLLM_ASCEND_ENABLE_CPU_GATHER_H2D=0

然后按 3.6 启动 Decode(须已开 Offload),再按 3.7 代理与压测。对比开关时仅改环境变量并重启 Decode。

注意:仅 Decode;多 TP 时仅 TP0 pack+H2D 再 broadcast;pack 失败 fallback 离散 sparse_copy;eager-only(ACL Graph 回退离散路径);官方包仅设环境变量无效。VLLM_ASCEND_CPU_GATHER_THREADS 建议 4 或 8;VLLM_ASCEND_CPU_GATHER_BUFFER_BYTES 为 packed 下限(默认 8 MiB)。

5. Mooncake 基线(可选) ​

不用 MemFabric Sparse Offload 时,可用 Mooncake Layerwise 作基线(P/D 均无 sparse_kv_offload_config)。其余参数同 3.5 / 3.6,仅替换 --kv-transfer-config;代理与 bench 同 3.7。

Prefill:

shell
  --kv-transfer-config '{
    "kv_connector": "MooncakeLayerwiseConnector",
    "kv_role": "kv_producer",
    "kv_port": 25000,
    "kv_connector_extra_config": {
      "prefill": {"dp_size": 1, "tp_size": 16},
      "decode": {"dp_size": 1, "tp_size": 16}
    }
  }'

Decode:

shell
  --kv-transfer-config '{
    "kv_connector": "MooncakeLayerwiseConnector",
    "kv_role": "kv_consumer",
    "kv_port": 26000,
    "kv_connector_extra_config": {
      "prefill": {"dp_size": 1, "tp_size": 16},
      "decode": {"dp_size": 1, "tp_size": 16}
    }
  }'