跳转至

UCM Store 部署指南

为什么要使用 UCM

统一缓存管理器(UCM)提供了一个外部 KV 缓存存储层,专为 vLLM/vLLM-Ascend 中的前缀缓存场景而设计。与 KV Pooling 仅通过聚合设备内存来扩展前缀缓存容量、因此仍受限于 HBM/DRAM 大小且缺乏持久性不同,UCM 将计算与存储解耦,并采用分层设计。每个节点使用本地 DRAM 作为快速缓存,而共享后端(如 NFS、3FS 或企业级存储)则作为持久化 KV 存储。

使用 UCM 的关键优势:

  1. 打破设备内存容量限制:传统前缀缓存受限于 HBM/DRAM 大小。UCM 通过将 KV 缓存卸载到外部存储来消除这一上限,使缓存容量能够随存储系统而非计算资源进行扩展。

  2. 持久化且可靠的 KV 缓存:UCM 提供持久的 KV 缓存存储,确保缓存的 prefix 块能够在服务重启、实例故障或调度迁移后仍然存在。这对于生产级推理系统至关重要。

  3. 多场景加速:UCM 不仅支持前缀缓存,还提供免训练的稀疏注意力方法(如 GSA、CacheBlend),用于处理超长序列推理任务。此外,UCM 还提供基于存算分离架构的 PD 分离解决方案,支持异构计算资源的灵活管理。

  4. 显著的性能提升:与 vLLM 集成后,UCM 在多轮对话和长上下文推理等各类场景中实现 3-10 倍的推理延迟降低。基准测试显示,在前缀缓存场景中 TTFT 最高可提升 8 倍。

UCM 工作原理

架构

UCM 采用集中式架构进行 KV 缓存管理,构建三层缓存层次结构:

HBM (GPU Memory) → DRAM (Local Cache) → Storage Backend (SSD/NFS/3FS)

这一三层设计能够实现:

  • HBM(第一层):为活跃推理计算提供最快的访问速度
  • DRAM(第二层):为频繁访问的 KV 块提供高速本地缓存
  • 存储后端(第三层):持久化存储层,包括本地 SSD、NFS 挂载存储或 3FS 等专用系统,支持无限容量扩展

UCM 选择集中式方案(类似于 DeepSeek 的 3FS)而非去中心化设计,原因如下:

  1. 简单性:避免了去中心化架构中所需的复杂亲和性调度
  2. 解耦:保持推理实例独立,无需向调度器上报 KV 缓存状态
  3. 无数据孤岛:集中式存储可避免跨隔离实例的冗余 KV 缓存累积
  4. 更好的兼容性:与 PD 分离及大规模部署具有更优的兼容性

功能特性

UCM 目前提供以下功能:

功能 描述
Prefix Cache 持久化 KV 缓存存储,支持 NFS Store、3FS Store 和 Pipeline Store
Sparse Attention 免训练的稀疏注意力方法,包括 GSA(基于图的稀疏注意力)和 CacheBlend,用于长上下文加速
PD Disaggregation Prefill-Decode 分离,支持多种模式:P2P、集中式 PD、NPGD 和 xPYD
ReRoPE 支持旋转位置编码扩展

支持的平台:

  • CUDA(NVIDIA H100、H20、L40、L20)
  • CANN(Atlas A2 推理产品、Atlas A3 推理产品)
  • MUSA(Mthreads S5000)
  • MACA(MetaX C500)

支持的框架:

  • vLLM(main 分支)
  • vLLM-Ascend(main 分支)
  • SGLang(main 分支)

注意:完整的支持矩阵及最新信息,请参阅 UCM Support Matrix。

部署指南

前提条件

  • 操作系统:Linux
  • 配备 Ascend NPU 的硬件,通常为 Atlas 800 A2 系列
  • vLLM:main 分支
  • vLLM Ascend:main 分支

UCM 安装

请参阅 Ascend NPU 官方 UCM 安装指南

PD 分离场景

UCM 支持两种类型的 PD 分离架构:

类型 KV 传输方式 特点
Centralized PD 通过统一存储后端(NFS/3FS)传输 架构简单、完全解耦、实例无状态
Distributed PD(P2P) 通过 Mooncake + UCM prefix cache 直接传输 延迟更低,适用于同构 P/D 节点

集中式 PD 分离

在集中式 PD 分离架构中,KV 缓存通过统一存储池进行传输。Prefill 节点将 KV 缓存卸载到存储后端,Decode 节点以高前缀缓存命中率进行读取。这种方式实现了最高程度的解耦,并简化了调度逻辑。

重要:对于跨节点部署,所有 Prefill 和 Decode 节点必须能够访问共享存储后端(例如 NFS 挂载目录或 3FS)。在继续之前,请确保所有节点都能访问该存储路径。

示例:2P2D 部署

假设节点 192.168.10.1 上有 2 个 Prefill 实例(端口 7800、7801),节点 192.168.10.2 上有 2 个 Decode 实例(端口 7802、7803),共享 NFS 存储位于 /mnt/test1。

步骤 1:准备 UCM 配置文件

使用 PipelineStore 创建配置文件(例如 ucm_config_example.yaml):

ucm_connectors:
  - ucm_connector_name: "UcmPipelineStore"
    ucm_connector_config:
      store_pipeline: "Cache|Posix"
      storage_backends: "/mnt/test1"
      cache_buffer_capacity_gb: 64
enable_event_sync: true
use_layerwise: false

关键配置参数:

  • storage_backends:所有节点均可访问的共享存储目录(例如 NFS 挂载路径或 3FS)。对于跨节点 PD 分离,该路径必须是共享存储路径。

注意:PipelineStore 是 UCM 推荐的连接器。它将 Cache Store(设备 ↔ 主机)与 Posix Store(主机 ↔ 存储后端)链接起来,以获得最佳传输性能。更多配置选项请参阅 UCM PipelineStore 文档。

步骤 2:运行 Prefill 服务器

export PYTHONHASHSEED=123456
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3
vllm serve /models/QwQ-32B \
    --host 0.0.0.0 \
    --port 7800 \
    --gpu-memory-utilization 0.92 \
    --data-parallel-size 1 \
    --tensor-parallel-size 4 \
    --seed 1024 \
    --max-model-len 17000 \
    --max-num-batched-tokens 8000 \
    --max-num-seqs 20 \
    --trust-remote-code \
    --enforce-eager \
    --kv-transfer-config \
    '{
        "kv_connector": "UCMConnector",
        "kv_role": "kv_both",
        "kv_connector_extra_config": {"UCM_CONFIG_FILE": "/path/to/ucm_config_example.yaml"}
    }'

要在同一节点上启动第二个 Prefill 实例,请相应修改 --port(例如端口 7801)和 ASCEND_RT_VISIBLE_DEVICES。

步骤 3:运行 Decode 服务器

export PYTHONHASHSEED=123456
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3
vllm serve /models/QwQ-32B \
    --host 0.0.0.0 \
    --port 7802 \
    --gpu-memory-utilization 0.92 \
    --data-parallel-size 1 \
    --tensor-parallel-size 4 \
    --seed 1024 \
    --max-model-len 17000 \
    --max-num-batched-tokens 8000 \
    --max-num-seqs 20 \
    --trust-remote-code \
    --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
    --kv-transfer-config \
    '{
        "kv_connector": "UCMConnector",
        "kv_role": "kv_both",
        "kv_connector_extra_config": {"UCM_CONFIG_FILE": "/path/to/ucm_config_example.yaml"}
    }'

要在同一节点上启动第二个 Decode 实例,请相应修改 --port(例如端口 7803)和 ASCEND_RT_VISIBLE_DEVICES。

步骤 4:运行负载均衡服务

python /vllm-workspace/vllm-ascend/examples/disaggregated_prefill_v1/load_balance_proxy_server_example.py \
    --port 7805 \
    --host 0.0.0.0 \
    --prefiller-hosts 192.168.10.1 192.168.10.1 \
    --prefiller-ports 7800 7801 \
    --decoder-hosts 192.168.10.2 192.168.10.2 \
    --decoder-ports 7802 7803

步骤 5:性能测试

vllm bench serve \
    --backend vllm \
    --model /models/QwQ-32B \
    --host 192.168.10.1 \
    --port 7805 \
    --seed 123456 \
    --dataset-name random \
    --num-prompts 10 \
    --random-input-len 8000 \
    --random-output-len 1000 \
    --request-rate inf \
    --ignore-eos

分布式 PD 分离(P2P)

在 P2P 分布式 PD 分离中,Mooncake 通过高速网络处理从 Prefill 节点到 Decode 节点的直接 KV 缓存传输,而 UCM 在 Prefill 节点上提供前缀缓存以实现 KV 缓存复用。该模式适用于 P/D 节点同构且延迟要求较低的场景。

注意:从 vLLM-Ascend 0.11.0 开始,官方镜像中已预装 Mooncake。安装详情请参阅 kvcache-ai/Mooncake。

示例:2P2D 配置

假设节点 192.168.10.1 上有 2 个 Prefill 实例(端口 9000、9001),节点 192.168.10.2 上有 2 个 Decode 实例(端口 9000、9001)。

步骤 1:运行 Mooncake Master 服务

在任意节点(例如 192.168.10.1)上运行 Mooncake master:

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
mooncake_master --port 50088 \
    --eviction_high_watermark_ratio 0.9 \
    --eviction_ratio 0.1 \
    --default_kv_lease_ttl 11000

在每个节点上准备 mooncake.json:

{
    "metadata_server": "P2PHANDSHAKE",
    "protocol": "ascend",
    "device_name": "",
    "master_server_address": "192.168.10.1:50088",
    "global_segment_size": "1GB"
}

同时为 Prefill 节点准备用于前缀缓存的 UCM 配置文件(ucm_config_example.yaml):

ucm_connectors:
  - ucm_connector_name: "UcmPipelineStore"
    ucm_connector_config:
      store_pipeline: "Cache|Posix"
      storage_backends: "/mnt/test1"
      cache_buffer_capacity_gb: 64
enable_event_sync: true
use_layerwise: true

注意:更多配置选项请参阅 UCM PipelineStore 文档。

步骤 2:运行 Prefill 服务

export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$LD_LIBRARY_PATH
export PYTHONHASHSEED=0
export PYTHONPATH=$PYTHONPATH:/vllm-workspace/vllm
export MOONCAKE_CONFIG_PATH="./mooncake.json"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3

vllm serve /models/QwQ-32B \
    --host 0.0.0.0 \
    --port 9000 \
    --gpu-memory-utilization 0.92 \
    --data-parallel-size 1 \
    --tensor-parallel-size 4 \
    --seed 1024 \
    --max-model-len 17000 \
    --max-num-batched-tokens 8000 \
    --max-num-seqs 20 \
    --trust-remote-code \
    --enforce-eager \
    --kv-transfer-config \
    '{
        "kv_connector": "MultiConnector",
        "kv_role": "kv_producer",
        "kv_connector_extra_config": {
            "connectors": [
                {
                    "kv_connector": "MooncakeConnectorV1",
                    "kv_role": "kv_producer",
                    "kv_port": 20001,
                    "kv_connector_extra_config": {
                        "prefill": {"dp_size": 1, "tp_size": 4},
                        "decode": {"dp_size": 1, "tp_size": 4}
                    }
                },
                {
                    "kv_connector": "UCMConnector",
                    "kv_role": "kv_both",
                    "kv_connector_extra_config": {"UCM_CONFIG_FILE": "/vllm-workspace/unified-cache-management/examples/ucm_config_example.yaml"}
                }
            ]
        }
    }'

要在同一节点上启动多个 Prefill 实例,请为每个实例修改 --port、kv_port 和 ASCEND_RT_VISIBLE_DEVICES(例如,第二个实例使用端口 9001 和 kv_port 20002)。

步骤 3:运行解码服务

export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$LD_LIBRARY_PATH
export PYTHONHASHSEED=0
export PYTHONPATH=$PYTHONPATH:/vllm-workspace/vllm
export MOONCAKE_CONFIG_PATH="./mooncake.json"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3

vllm serve /models/QwQ-32B \
    --host 0.0.0.0 \
    --port 9000 \
    --data-parallel-size 1 \
    --tensor-parallel-size 4 \
    --seed 1024 \
    --max-model-len 17000 \
    --max-num-batched-tokens 8000 \
    --trust-remote-code \
    --max-num-seqs 4 \
    --gpu-memory-utilization 0.92 \
    --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
    --kv-transfer-config \
    '{
        "kv_connector": "MooncakeConnectorV1",
        "kv_role": "kv_consumer",
        "kv_port": 20001,
        "kv_connector_extra_config": {
            "prefill": {"dp_size": 1, "tp_size": 4},
            "decode": {"dp_size": 1, "tp_size": 4}
        }
    }'

要在同一节点上启动多个解码实例,请为每个实例修改 --port、kv_port 和 ASCEND_RT_VISIBLE_DEVICES(例如,第二个实例使用端口 9001 和 kv_port 20002)。

步骤 4:运行负载均衡服务

python /vllm-workspace/vllm-ascend/examples/disaggregated_prefill_v1/load_balance_proxy_server_example.py \
    --port 7850 \
    --host 0.0.0.0 \
    --prefiller-hosts 192.168.10.1 192.168.10.1 \
    --prefiller-ports 9000 9001 \
    --decoder-hosts 192.168.10.2 192.168.10.2 \
    --decoder-ports 9000 9001

步骤 5:性能测试

vllm bench serve \
    --backend vllm \
    --model /models/QwQ-32B \
    --host 192.168.10.1 \
    --port 7850 \
    --seed 123456 \
    --dataset-name random \
    --num-prompts 10 \
    --random-input-len 8000 \
    --random-output-len 1000 \
    --request-rate inf \
    --ignore-eos

PD 混合推理

PD 混合推理(PD-Mixed Inference)指的是标准 vLLM 服务模式,其中不同请求的预填充(Prefill)和解码(Decode)阶段在同一实例内并发处理。与将预填充和解码物理分离到专用实例的 PD 分离(PD Disaggregation)不同,PD 混合模式在统一调度器中处理两个阶段,允许交错执行:当一个请求处于解码阶段时,另一个请求可以同时进行预填充。

UCM 通过提供持久化 KV 缓存存储来增强 PD 混合模式,可实现:

  • 跨请求共享前缀的前缀缓存复用
  • 服务重启后 KV 缓存的持久化
  • 将 KV 缓存卸载到外部存储以降低 GPU 内存压力

步骤 1:准备 UCM 配置文件

创建包含 PipelineStore 的配置文件(例如 ucm_config_example.yaml):

ucm_connectors:
  - ucm_connector_name: "UcmPipelineStore"
    ucm_connector_config:
      store_pipeline: "Cache|Posix"
      storage_backends: "/mnt/test1"
      cache_buffer_capacity_gb: 64
enable_event_sync: true
use_layerwise: true

关键配置参数:

  • storage_backends:KV 缓存存储目录。可以是本地 SSD 或 NFS 挂载路径。

注意:更多配置选项,请参阅 UCM PipelineStore 文档。

步骤 2:运行 PD 混合服务

export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
vllm serve /models/QwQ-32B \
    --host 0.0.0.0 \
    --port 7800 \
    --gpu-memory-utilization 0.92 \
    --data-parallel-size 2 \
    --tensor-parallel-size 4 \
    --seed 1024 \
    --max-model-len 17000 \
    --max-num-batched-tokens 8000 \
    --max-num-seqs 20 \
    --trust-remote-code \
    --enforce-eager \
    --block-size 128 \
    --kv-transfer-config \
    '{
        "kv_connector": "UCMConnector",
        "kv_role": "kv_both",
        "kv_connector_extra_config": {"UCM_CONFIG_FILE": "/path/to/ucm_config_example.yaml"}
    }'

步骤 3:性能测试

运行两次基准测试以观察前缀缓存效果:

# First run - no cache hit
vllm bench serve \
    --backend vllm \
    --model /models/QwQ-32B \
    --host localhost \
    --port 7800 \
    --seed 123456 \
    --dataset-name random \
    --num-prompts 10 \
    --random-input-len 8000 \
    --random-output-len 1000 \
    --request-rate inf \
    --ignore-eos

# Second run - observe cache hit improvement
vllm bench serve \
    --backend vllm \
    --model /models/QwQ-32B \
    --host localhost \
    --port 7800 \
    --seed 123456 \
    --dataset-name random \
    --num-prompts 10 \
    --random-input-len 8000 \
    --random-output-len 1000 \
    --request-rate inf \
    --ignore-eos

第二次运行后,由于 UCM 前缀缓存命中,应观察到 TTFT 显著降低。请查看 vLLM 日志中的缓存命中信息:

INFO ucm_connector.py:xxx: request_id: xxx, total_blocks_num: xxx, hit hbm: 0, hit external: xxx

示例:大规模专家并行下的 PD 分离

本节演示了在大规模专家并行(Expert Parallelism)下,针对 MoE 模型的 PD 分离部署。MoE 模型需要启用数据并行,以将专家权重分布到多个节点。

部署配置:

  • 预填充实例:4 个节点(192.168.10.1-4),DP4TP8(4 个 DP 进程,每个使用 TP8)
  • 解码实例:4 个节点(192.168.10.5-8),DP8TP4(8 个 DP 进程,每个使用 TP4)
  • 总计:8 台 Atlas 800T A2 服务器,每台配备 8 张 Ascend 910B3 NPU 卡
  • 存储:8 台服务器通过 CE8875 交换机连接到 AI 存储设备 A800

注意:关于外部负载均衡的数据并行,请参阅 vLLM 官方文档:外部负载均衡的数据并行部署。

部署步骤

步骤 1:运行 Mooncake 主服务

在任意节点(例如 192.168.10.1)上运行 Mooncake 主服务:

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
mooncake_master --port 50088 \
    --eviction_high_watermark_ratio 0.9 \
    --eviction_ratio 0.1 \
    --default_kv_lease_ttl 11000

在所有 8 个节点上准备 mooncake.json:

{
    "metadata_server": "P2PHANDSHAKE",
    "protocol": "ascend",
    "device_name": "",
    "master_server_address": "192.168.10.1:50088",
    "global_segment_size": "1GB"
}

步骤 2:运行 Prefill 服务(DP4TP8)

首先,在 Prefill 节点(192.168.10.1-4)上为前缀缓存准备一个 UCM 配置文件(ucm_config_example.yaml):

ucm_connectors:
  - ucm_connector_name: "UcmPipelineStore"
    ucm_connector_config:
      store_pipeline: "Cache|Posix"
      storage_backends: "/mnt/test1"
      cache_buffer_capacity_gb: 64
enable_event_sync: true
use_layerwise: true

关键配置参数:

  • storage_backends:所有节点均可访问的共享存储目录(例如 NFS 挂载路径或 3FS)。

注意:更多配置选项请参阅 UCM PipelineStore 文档。

在 Prefill 节点(192.168.10.1-4)上准备 prefill.sh:

#!/bin/sh

export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$LD_LIBRARY_PATH
export PYTHONHASHSEED=0
export PYTHONPATH=$PYTHONPATH:/vllm-workspace/vllm
export MOONCAKE_CONFIG_PATH="./mooncake.json"

device_list=$1
local_ip=$2
nic_name=$3
server_port=$4
tp_size=$5
dp_size=$6
dp_rank=$7
dp_address=$8
dp_rpc_port=$9
mooncake_port=${10}

export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=10
export HCCL_BUFFSIZE=256
export ASCEND_RT_VISIBLE_DEVICES=$device_list

export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export TASK_QUEUE_ENABLE=1
export VLLM_USE_MODELSCOPE="True"

vllm serve /models/GLM-5.1-w4a8 \
    --host 0.0.0.0 \
    --port $server_port \
    --data-parallel-size $dp_size \
    --data-parallel-address $dp_address \
    --data-parallel-rpc-port $dp_rpc_port \
    --data-parallel-rank $dp_rank \
    --tensor-parallel-size $tp_size \
    --enable-expert-parallel \
    --seed 1024 \
    --max-model-len 17000 \
    --max-num-batched-tokens 8000 \
    --trust-remote-code \
    --max-num-seqs 4 \
    --gpu-memory-utilization 0.92 \
    --quantization ascend \
    --enforce-eager \
    --additional-config '{"enable_weight_nz_layout":true,"enable_prefill_optimizations":true}' \
    --kv-transfer-config \
    '{
        "kv_connector": "MultiConnector",
        "kv_role": "kv_producer",
        "kv_connector_extra_config": {
            "connectors": [
                {
                    "kv_connector": "MooncakeConnectorV1",
                    "kv_role": "kv_producer",
                    "kv_port": '$mooncake_port',
                    "kv_connector_extra_config": {
                        "prefill": {"dp_size": '$dp_size', "tp_size": '$tp_size'},
                        "decode": {"dp_size": 8, "tp_size": 4}
                    }
                },
                {
                    "kv_connector": "UCMConnector",
                    "kv_role": "kv_both",
                    "kv_connector_extra_config": {"UCM_CONFIG_FILE": "/path/to/ucm_config_example.yaml"}
                }
            ]
        }
    }' 2>&1 | tee "prefiller_dp_$dp_rank.log"

为 Prefill 节点准备 run_multi_dp.sh:

#!/bin/bash

local_ip="xxxx"           # IP of current node (192.168.10.1/2/3/4)
nic_name="xxxx"           # Network interface name corresponding to local_ip
tp_size=8
dp_size=4                 # Total DP engines for Prefill
dp_size_local=1           # 1 DP process per node (TP8 uses all 8 cards)
dp_rank_start=xxxx        # 0 for node1, 1 for node2, 2 for node3, 3 for node4
dp_address="192.168.10.1" # Master node for DP communication
dp_rpc_port=13395
server_port=9000
mooncake_port=20001
template_path="./prefill.sh"
cards_per_node=8

cards_per_process=$((cards_per_node / dp_size_local))

for ((i=0; i<dp_size_local; i++)); do
  dp_rank=$((dp_rank_start + i))
  server_port=$((server_port + i))
  mooncake_port=$((mooncake_port + i * tp_size))

  start_card=$((i * cards_per_process))
  device_list=$(seq -s, $start_card $((start_card + cards_per_process - 1)))

  bash $template_path $device_list $local_ip $nic_name $server_port $tp_size $dp_size $dp_rank $dp_address $dp_rpc_port $mooncake_port &
done

wait

在每个 Prefill 节点(192.168.10.1-4)上执行 run_multi_dp.sh,并配置相应的 local_ip 和 dp_rank_start:

  • 192.168.10.1:dp_rank_start=0
  • 192.168.10.2:dp_rank_start=1
  • 192.168.10.3:dp_rank_start=2
  • 192.168.10.4:dp_rank_start=3

步骤 3:运行 Decode 服务(DP8TP4)

在 Decode 节点(192.168.10.5-8)上准备 decode.sh:

#!/bin/sh

export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$LD_LIBRARY_PATH
export PYTHONHASHSEED=0
export PYTHONPATH=$PYTHONPATH:/vllm-workspace/vllm
export MOONCAKE_CONFIG_PATH="./mooncake.json"

device_list=$1
local_ip=$2
nic_name=$3
server_port=$4
tp_size=$5
dp_size=$6
dp_rank=$7
dp_address=$8
dp_rpc_port=$9
mooncake_port=${10}

export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=10
export HCCL_BUFFSIZE=256
export ASCEND_RT_VISIBLE_DEVICES=$device_list

export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export TASK_QUEUE_ENABLE=1
export VLLM_USE_MODELSCOPE="True"

vllm serve /models/GLM-5.1-w4a8 \
    --host 0.0.0.0 \
    --port $server_port \
    --data-parallel-size $dp_size \
    --data-parallel-address $dp_address \
    --data-parallel-rpc-port $dp_rpc_port \
    --data-parallel-rank $dp_rank \
    --tensor-parallel-size $tp_size \
    --enable-expert-parallel \
    --seed 1024 \
    --max-model-len 17000 \
    --max-num-batched-tokens 8000 \
    --trust-remote-code \
    --max-num-seqs 4 \
    --gpu-memory-utilization 0.92 \
    --quantization ascend \
    --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
    --kv-transfer-config \
    '{
        "kv_connector": "MooncakeConnectorV1",
        "kv_role": "kv_consumer",
        "kv_port": '$mooncake_port',
        "kv_connector_extra_config": {
            "prefill": {"dp_size": 4, "tp_size": 8},
            "decode": {"dp_size": '$dp_size', "tp_size": '$tp_size'}
        }
    }' 2>&1 | tee "decoder_dp_$dp_rank.log"

为 Decode 节点准备 run_multi_dp.sh:

#!/bin/bash

local_ip="xxxx"           # IP of current node (192.168.10.5/6/7/8)
nic_name="xxxx"           # Network interface name corresponding to local_ip
tp_size=4
dp_size=8                 # Total DP engines for Decode
dp_size_local=2           # 2 DP processes per node (TP4 uses 4 cards each)
dp_rank_start=xxxx        # 0 for node5, 2 for node6, 4 for node7, 6 for node8
dp_address="192.168.10.5" # Master node for DP communication
dp_rpc_port=13395
server_port=9000
mooncake_port=20001
template_path="./decode.sh"
cards_per_node=8

cards_per_process=$((cards_per_node / dp_size_local))

for ((i=0; i<dp_size_local; i++)); do
  dp_rank=$((dp_rank_start + i))
  server_port=$((server_port + i))
  mooncake_port=$((mooncake_port + i * tp_size))

  start_card=$((i * cards_per_process))
  device_list=$(seq -s, $start_card $((start_card + cards_per_process - 1)))

  bash $template_path $device_list $local_ip $nic_name $server_port $tp_size $dp_size $dp_rank $dp_address $dp_rpc_port $mooncake_port &
done

wait

在每个 Decode 节点(192.168.10.5-8)上执行 run_multi_dp.sh,并配置相应的 local_ip 和 dp_rank_start:

  • 192.168.10.5:dp_rank_start=0
  • 192.168.10.6:dp_rank_start=2
  • 192.168.10.7:dp_rank_start=4
  • 192.168.10.8:dp_rank_start=6

第 4 步:运行负载均衡服务

python /vllm-workspace/vllm-ascend/examples/disaggregated_prefill_v1/load_balance_proxy_server_example.py \
    --port 7850 \
    --host 0.0.0.0 \
    --prefiller-hosts 192.168.10.1 192.168.10.2 192.168.10.3 192.168.10.4 \
    --prefiller-ports 9000 9000 9000 9000 \
    --decoder-hosts 192.168.10.5 192.168.10.5 192.168.10.6 192.168.10.6 192.168.10.7 192.168.10.7 192.168.10.8 192.168.10.8 \
    --decoder-ports 9000 9001 9000 9001 9000 9001 9000 9001

基准测试结果

以下基准测试展示了 UCM 前缀缓存在大规模专家并行(EP)PD 分离场景中的有效性。

测试配置:

  • 总请求数:128
  • 请求并发数:128
  • 约束条件:总请求数保持在 Prefill 实例可用于 KV 缓存存储的 HBM 容量范围内

KV 缓存预置流程:

每次测试前,必须使用 0.8 的前缀比例预置 KV 缓存:

  1. 预置阶段:发送 128 个请求,输入长度 = target_input_length × 0.8,输出长度 = 1,以建立 KV 缓存前缀
  2. 测试阶段:发送 128 个请求,输入长度为目标输入长度,输出长度 = 1000

以 32k 输入场景为例:

  • 预置:128 个请求,包含 25600(32k × 0.8)个输入 token + 1 个输出 token
  • 测试:128 个请求,包含 32000 个输入 token + 1000 个输出 token

该流程确保在测量性能之前,前缀部分(输入的 80%)已被缓存,从而模拟真实场景中的前缀复用。

测试命令:

# Step 1: Pre-seed KV cache (25600 = 32000 * 0.8)
vllm bench serve \
    --backend vllm \
    --model /models/GLM-5.1-w4a8 \
    --host 192.168.10.1 \
    --port 7850 \
    --seed 123456 \
    --dataset-name random \
    --num-prompts 128 \
    --random-input-len 25600 \
    --random-output-len 1 \
    --request-rate inf \
    --ignore-eos

# Step 2: Run performance test
vllm bench serve \
    --backend vllm \
    --model /models/GLM-5.1-w4a8 \
    --host 192.168.10.1 \
    --port 7850 \
    --seed 123456 \
    --dataset-name random \
    --num-prompts 128 \
    --random-input-len 32000 \
    --random-output-len 1000 \
    --request-rate inf \
    --ignore-eos

测试场景:

场景 描述
重计算 无 UCM 的基线,禁用 HBM 前缀缓存(完全重计算)
HBM PC 无 UCM,启用 HBM 前缀缓存
UCM PC 启用 UCM 前缀缓存

性能结果:

输入长度 输出长度 重计算 HBM PC UCM PC
TTFT (ms) TPOT (ms) E2EL (ms) TTFT (ms) TPOT (ms) E2EL (ms) TTFT (ms) TPOT (ms) E2EL (ms)
32k 1k 140730 64 173820 108879 65 142228 51861 66 85615
64k 1k 181864 64 214988 144444 65 177561 69718 66 103752
128k 1k 268016 65 301648 267680 65 301135 105083 66 138946

注意:由于数据并行,测试阶段的请求可能不会路由到用于 KV 缓存预置的同一 DP 进程。因此,HBM PC 的实际缓存命中率低于预期的 0.8。UCM 通过将全部 KV 缓存存储在共享外部存储中来解决这一限制,确保无论请求由哪个 DP 进程处理,都能命中缓存数据。这保证了真实缓存命中率等于预置比例 0.8,相比 HBM PC 显著降低了 TTFT。TTFT 的改善有效提升了 Prefill 实例的吞吐量,从而提升了整体系统吞吐量。

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