UCM 存储部署指南¶
为什么使用 UCM¶
统一缓存管理器(UCM)为 vLLM/vLLM-Ascend 中的前缀缓存场景提供了外部 KV 缓存存储层。与仅通过聚合设备内存来扩展前缀缓存容量、因此仍受 HBM/DRAM 大小限制且缺乏持久性的 KV 池化不同,UCM 将计算与存储解耦,并采用分层设计。每个节点使用本地 DRAM 作为快速缓存,而共享后端(如 NFS、3FS 或企业级存储)则作为持久化 KV 存储。
使用 UCM 的主要优势:
-
突破设备内存容量限制:传统前缀缓存受限于 HBM/DRAM 大小。UCM 通过将 KV 缓存卸载到外部存储来消除这一上限,使缓存容量能够随存储系统而非计算资源扩展。
-
持久且可靠的 KV 缓存:UCM 提供持久的 KV 缓存存储,确保缓存的前缀块在服务重启、实例故障或调度迁移后仍然存在。这对于生产级推理系统至关重要。
-
多场景加速:UCM 不仅支持前缀缓存,还提供无需训练的稀疏注意力方法(例如 GSA、CacheBlend),用于处理超长序列推理任务。此外,UCM 还提供基于存算分离架构的 PD 分离解决方案,支持异构计算资源的灵活管理。
-
显著的性能提升:与 vLLM 集成后,UCM 在多轮对话和长上下文推理等多种场景下实现了**3-10 倍的推理延迟降低**。基准测试显示,在前缀缓存场景中,TTFT 最高可提升 8 倍。
UCM 工作原理¶
架构¶
UCM 采用**集中式架构**进行 KV 缓存管理,构建了三层缓存层次结构:
这种三层设计实现了:
- HBM(第 1 层):为活跃推理计算提供最快访问
- DRAM(第 2 层):为频繁访问的 KV 块提供高速本地缓存
- 存储后端(第 3 层):持久化存储层,包括本地 SSD、NFS 挂载存储或 3FS 等专用系统,实现无限容量扩展
UCM 选择集中式方法(类似于 DeepSeek 的 3FS)而非去中心化设计,原因如下:
- 简单性:避免了去中心化架构中复杂的亲和性调度
- 解耦性:保持推理实例独立,无需向调度器报告 KV 缓存状态
- 无数据孤岛:集中式存储防止了跨隔离实例的冗余 KV 缓存累积
- 更好的兼容性:与 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 安装¶
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 实例,请为每个实例修改 --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_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 日志以获取缓存命中信息:
示例:结合大规模专家并行的 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.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 前缀缓存在大规模专家并行 PD 分离场景中的有效性。
测试配置:
- 总请求数:128
- 请求并发数:128
- 约束:总请求数保持在 Prefill 实例可用于 KV 缓存存储的 HBM 容量范围内
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前缀缓存 |
性能结果:
| 输入长度 | 输出长度 | 重新计算 | 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 实例的吞吐量,从而提升了整个系统的吞吐量。