UCM存储部署指南#
为何使用UCM#
统一缓存管理器(UCM)为vLLM/vLLM-Ascend中的前缀缓存场景提供外部KV缓存存储层。与仅通过聚合设备内存扩展前缀缓存容量、因此仍受HBM/DRAM大小限制且缺乏持久性的KV池化不同,UCM将计算与存储解耦,采用分层设计。每个节点使用本地DRAM作为快速缓存,而共享后端(如NFS、3FS或企业级存储)则作为持久化KV存储。
使用UCM的主要优势:
突破设备内存容量限制:传统前缀缓存受限于HBM/DRAM大小。UCM通过将KV缓存卸载到外部存储来消除这一上限,使缓存容量随存储系统而非计算资源扩展。
持久可靠的KV缓存:UCM提供持久的KV缓存存储,确保缓存的prefix块在服务重启、实例故障或调度迁移后仍然存活。这对生产级推理系统至关重要。
多场景加速:UCM不仅支持前缀缓存,还提供免训练的稀疏注意力方法(如GSA、CacheBlend)用于处理超长序列推理任务。此外,UCM基于存算分离架构提供PD分离解决方案,实现异构计算资源的灵活管理。
显著性能提升:与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)而非去中心化设计,原因如下:
简单性:避免了去中心化架构中复杂的亲和性调度
解耦:保持推理实例独立,无需向调度器报告KV缓存状态
无数据孤岛:集中式存储防止跨隔离实例的冗余KV缓存积累
更好的兼容性:与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安装#
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实例,请为每个实例修改--port、kv_port和ASCEND_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实例,请为每个实例修改--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混合推理是指标准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_ip和dp_rank_start执行run_multi_dp.sh:
192.168.10.1:
dp_rank_start=0192.168.10.2:
dp_rank_start=1192.168.10.3:
dp_rank_start=2192.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_ip和dp_rank_start执行run_multi_dp.sh:
192.168.10.5:
dp_rank_start=0192.168.10.6:
dp_rank_start=2192.168.10.7:
dp_rank_start=4192.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 缓存:
预填充阶段:发送 128 个请求,输入长度 =
target_input_length × 0.8,输出长度 = 1,以建立 KV 缓存前缀测试阶段:发送 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 实例的吞吐量,从而提升了整体系统吞吐量。