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缓存存储,确保缓存的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(第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分离

Prefill-Decode分离,支持多种模式:P2P、集中式PD、NPGD和xPYD

ReRoPE

支持旋转位置嵌入扩展

支持平台:

  • CUDA(NVIDIA H100、H20、L40、L20)

  • CANN(Ascend 910C、910B)

  • MUSA(Mthreads S5000)

  • MACA(MetaX C500)

支持框架:

  • vLLM(main分支)

  • vLLM-Ascend(main分支)

  • SGLang(main分支)

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

部署指南#

前提条件#

  • 操作系统:Linux

  • 配备Ascend NPU的硬件,通常为Atlas 800 A2系列。

  • vLLM:main分支

  • vLLM Ascend:main分支

UCM安装#

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

PD分离场景#

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

类型

KV传输方式

特点

集中式PD

通过统一存储后端(NFS/3FS)

架构简单、完全解耦、无状态实例

分布式PD(P2P)

通过Mooncake + UCM前缀缓存直接传输

更低延迟,适用于同构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_connector_module_path": "ucm.integration.vllm.ucm_connector",
        "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_connector_module_path": "ucm.integration.vllm.ucm_connector",
        "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主服务

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

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_module_path": "ucm.integration.vllm.ucm_connector",
                    "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_connector_module_path": "ucm.integration.vllm.ucm_connector",
        "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主服务

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

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_module_path": "ucm.integration.vllm.ucm_connector",
                    "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)上使用适当的local_ipdp_rank_start执行run_multi_dp.sh

  • 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)上使用适当的local_ipdp_rank_start执行run_multi_dp.sh

  • 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实例可用HBM容量范围内以存储KV缓存

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 前缀缓存

性能结果:

Input Length Output Length Recalculation 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 实例的吞吐量,从而提升了整体系统吞吐量。