跳转至

UCM 存储部署指南

为什么使用 UCM

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

使用 UCM 的主要优势:

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

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

  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(第 1 层):为活跃推理计算提供最快访问
  • DRAM(第 2 层):为频繁访问的 KV 块提供高速本地缓存
  • 存储后端(第 3 层):持久化存储层,包括本地 SSD、NFS 挂载存储或 3FS 等专用系统,实现无限容量扩展

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

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

功能

UCM 目前提供以下功能:

能力 描述
前缀缓存 持久化KV缓存存储,支持NFS存储、3FS存储和流水线存储
稀疏注意力 免训练的稀疏注意力方法,包括GSA(基于图的稀疏注意力)和CacheBlend,用于长上下文加速
PD分离 预填充-解码分离,支持多种模式:P2P、集中式PD、NPGD和xPYD
ReRoPE 支持旋转位置编码扩展

支持的平台:

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

支持的框架:

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

注意:有关完整和最新的支持矩阵,请参阅 UCM 支持矩阵

部署指南

前提条件

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

UCM 安装

请参考 Ascend NPU 的官方 UCM 安装指南

PD 分离场景

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

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

集中式 PD 分离

在集中式 PD 分离中,KV 缓存通过统一存储池传输。预填充节点将 KV 缓存卸载到存储后端,解码节点以高前缀缓存命中率检索它。这种方法实现了最高程度的解耦,并简化了调度逻辑。

重要:对于跨节点部署,所有预填充和解码节点必须能够访问**共享存储后端**(例如 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 负责通过高速网络将 KV 缓存直接从 Prefill 节点传输到 Decode 节点,而 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 主服务

在任意节点(例如 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

在每个节点上准备 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 实例,请为每个实例修改 --portkv_portASCEND_RT_VISIBLE_DEVICES(例如第二个实例使用端口 9001 和 kv_port 20002)。

步骤 3:运行 Decode 服务

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}
        }
    }'

要在同一节点上启动多个 Decode 实例,请为每个实例修改 --portkv_portASCEND_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 混合推理是指标准的 vLLM 服务模式,其中不同请求的 Prefill 和 Decode 阶段在同一实例内并发处理。与将 Prefill 和 Decode 物理分离到专用实例的 PD 分离部署不同,PD 混合模式在统一的调度器中处理两个阶段,允许交错执行:当一个请求处于 Decode 阶段时,另一个请求可以同时进行 Prefill。

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 分离部署

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

部署配置:

  • Prefill 实例:4 个节点 (192.168.10.1-4),DP4TP8(4 个 DP 进程,每个进程 TP8)
  • Decode 实例: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.shlocal_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.shlocal_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 前缀缓存在大规模专家并行 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 实例的吞吐量,从而提升了整个系统的吞吐量。