一、为什么要做PD分离?

做过大模型推理优化的朋友都知道,Prefill和Decode这两个阶段的性质完全不同:

Prefill阶段就像是读完整本书做笔记——需要把用户输入的完整prompt编码成隐藏状态,同时生成KV Cache。这个过程计算量大,吃算力。

Decode阶段更像是一个字一个字往外蹦——每次只生成一个token,一直重复到结束。这个过程主要瓶颈在显存带宽,属于典型的访存密集型任务。

两个阶段混在一起跑,就会出现资源利用不均的问题。PD分离部署方案把这两个阶段拆开,让Prefill和Decode各自在最适合的硬件环境中运行,配合vLLM的PagedAttention技术管理KV缓存,能大幅提升整体吞吐。

本文记录了在昇腾NPU平台上部署DeepSeek-V3-w8a8量化模型的完整过程,希望能帮到正在做类似工作的同学。

二、硬件与软件环境

硬件配置

项目 配置
硬件平台 2台Atlas 800I A2服务器(每台16卡×64GB)
操作系统 Ubuntu 22.04
驱动版本 25.2.0
Python版本 3.11

软件版本清单

组件 版本 说明
CANN 8.2.RC1 昇腾计算架构
torch 2.5.1+cpu CPU版本
torch_npu 2.5.1.post1.dev20250619 NPU适配版本
torchvision 0.20.1 随torch自动安装
vLLM 0.9.1 推理引擎
vLLM-ascend 0.9.1-dev NPU适配版本

三、环境准备工作

3.1 NPU设备检查

在开始部署前,先确认NPU设备和网络状态正常。下面这组命令建议都跑一遍:

# 查看NPU设备状态
npu-smi info

# 检查物理连接
for i in {0..15}; do hccn_tool -i $i -lldp -g | grep Ifname; done

# 确认以太网端口状态(应该都是up)
for i in {0..15}; do hccn_tool -i $i -link -g ; done

# 检查网络健康状况(应该显示success)
for i in {0..15}; do hccn_tool -i $i -net_health -g ; done

# 查看IP配置
for i in {0..15}; do hccn_tool -i $i -netdetect -g ; done

# 查看网关配置
for i in {0..15}; do hccn_tool -i $i -gateway -g ; done

# 检查TLS配置一致性
for i in {0..15}; do hccn_tool -i $i -tls -g ; done | grep switch

# 关闭TLS校验(这一步很重要)
for i in {0..15};do hccn_tool -i $i -tls -s enable 0;done

# 获取各NPU的IP地址
for i in {0..15}; do hccn_tool -i $i -ip -g;done

# 测试跨节点连通性(替换<NPU-IP>为实际IP)
for i in {0..15}; do hccn_tool -i $i -ping -g address <NPU-IP>;done

3.2 创建Docker容器

容器环境能避免很多依赖冲突的问题。如果不是root用户,先切换:

sudo su - root
mkdir /home/<your_name>

在这里插入图片描述
出现如上所示结果,然后输入密码后,mkdir /home/<your_name>输入指令,这里替换路径中的<your_name>,换成我们自己的

创建容器(注意替换路径中的<your_name>):

docker run -it --privileged --name=vllm_deepseek_pd \
  --net=host --shm-size=500g \
  --device=/dev/davinci_manager \
  --device=/dev/hisi_hdc \
  --device=/dev/devmm_svm \
  --device=/dev/davinci0 \
  --device=/dev/davinci1 \
  --device=/dev/davinci2 \
  --device=/dev/davinci3 \
  --device=/dev/davinci4 \
  --device=/dev/davinci5 \
  --device=/dev/davinci6 \
  --device=/dev/davinci7 \
  --device=/dev/davinci8 \
  --device=/dev/davinci9 \
  --device=/dev/davinci10 \
  --device=/dev/davinci11 \
  --device=/dev/davinci12 \
  --device=/dev/davinci13 \
  --device=/dev/davinci14 \
  --device=/dev/davinci15 \
  -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
  -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
  -v /usr/local/sbin/:/usr/local/sbin/ \
  -v /var/log/npu/slog/:/var/log/npu/slog \
  -v /usr/local/dcmi:/usr/local/dcmi \
  -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
  -v /etc/ascend_install.info:/etc/ascend_install.info \
  -v /var/log/npu/profiling/:/var/log/npu/profiling \
  -v /var/log/npu/dump/:/var/log/npu/dump \
  -v /var/log/npu/:/usr/slog \
  -v /etc/hccn.conf:/etc/hccn.conf \
  -v /home/:/home \
  -w /home/<your_name> \
  mindie:2.1.RC1-800I-A2-py311-ubuntu22.04-x86_64 \
  /bin/bash

进入容器后配置网络代理,用curl www.baidu.com测试网络是否正常。

3.3 安装软件依赖

安装CANN套件

昇腾社区下载三个安装包:

  • Ascend-cann-toolkit_*.run (开发套件)
  • Ascend-cann-kernels-*.run (算子包)
  • Ascend-cann-nnal_*.run (神经网络加速库)

安装前确保目标目录有10GB以上可用空间:

chmod a+x Ascend-cann-kernels-910b_8.2.RC1_linux-x86_64.run
chmod a+x Ascend-cann-nnal_8.2.RC1_linux-x86_64.run
chmod a+x Ascend-cann-toolkit_8.2.RC1_linux-x86_64.run

# 先做检查
./Ascend-cann-toolkit_8.2.RC1_linux-x86_64.run --check
./Ascend-cann-toolkit_8.2.RC1_linux-x86_64.run --install --install-path=/home/<your_name>/cann_8.2.rc1

./Ascend-cann-kernels-910b_8.2.RC1_linux-x86_64.run --check
./Ascend-cann-kernels-910b_8.2.RC1_linux-x86_64.run --install --install-path=/home/<your_name>/cann_8.2.rc1

./Ascend-cann-nnal_8.2.RC1_linux-x86_64.run --check
./Ascend-cann-nnal_8.2.RC1_linux-x86_64.run --install --install-path=/home/<your_name>/cann_8.2.rc1

# 配置环境变量(每次进容器都要执行)
source /home/<your_name>/cann_8.2.rc1/ascend-toolkit/set_env.sh
source /home/<your_name>/cann_8.2.rc1/nnal/atb/set_env.sh
安装PyTorch和torch_npu

先配置pip镜像源,然后安装:

pip config set global.extra-index-url "https://download.pytorch.org/whl/cpu/ https://mirrors.huaweicloud.com/ascend/repos/pypi"

pip install attrs cython numpy==1.26.4 decorator sympy==1.13.1 \
  cffi pyyaml pathlib2 psutil protobuf==6.31.1 scipy requests absl-py

pip install torchvision==0.20.1  # 会自动安装torch==2.5.1+cpu
pip install torch-npu==2.5.1.post1.dev20250619
安装vLLM和vLLM-ascend

从GitHub拉取代码并安装:

# 安装vLLM
git clone https://github.com/vllm-project/vllm.git
cd vllm
git checkout releases/v0.9.1
VLLM_TARGET_DEVICE=empty pip install -v -e .

# 安装vLLM-ascend
cd ..
git clone https://github.com/vllm-project/vllm-ascend
cd vllm-ascend
git checkout v0.9.1-dev
pip install -v -e .

如果遇到SSL证书问题,执行:

export GIT_SSL_NO_VERIFY=1
git config --global http.sslVerify false

四、部署流程

4.1 生成ranktable配置文件

在两台设备上都执行这个脚本,生成集群拓扑配置:

cd /home/<your_name>/vllm-ascend/examples/disaggregate_prefill_v1/

bash gen_ranktable.sh \
  --ips 141.61.41.163 141.61.41.164 \
  --npus-per-node 16 \
  --network-card-name ens3f0 \
  --prefill-device-cnt 16 \
  --decode-device-cnt 16

参数解释:

  • ips: P节点和D节点的IP,P在前D在后
  • npus-per-node: 每台机器的NPU数量
  • network-card-name: 网卡名称(用ifconfig查看)
  • prefill-device-cnt: Prefill用的卡数
  • decode-device-cnt: Decode用的卡数

4.2 编写Prefill启动脚本

在P节点创建start_prefill.sh:

#!/bin/bash

# 环境变量配置
export HCCL_IF_IP=141.61.41.163
export GLOO_SOCKET_IFNAME="ens3f0"
export TP_SOCKET_IFNAME="ens3f0"
export HCCL_SOCKET_IFNAME="ens3f0"
export DISAGGREGATED_PREFILL_RANK_TABLE_PATH=/home/<your_name>/vllm-ascend/examples/disaggregate_prefill_v1/ranktable.json
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=32
export VLLM_USE_V1=1
export VLLM_LLMDD_RPC_PORT=5559

# 启动Prefill服务
vllm serve /home/models/DeepSeek-V3.1-w8a8-rot-mtp \
  --host 0.0.0.0 \
  --port 20002 \
  --data-parallel-size 1 \
  --data-parallel-size-local 1 \
  --api-server-count 1 \
  --data-parallel-address 141.61.41.163 \
  --data-parallel-rpc-port 13356 \
  --tensor-parallel-size 16 \
  --enable-expert-parallel \
  --quantization ascend \
  --seed 1024 \
  --served-model-name deepseek \
  --max-model-len 32768 \
  --max-num-batched-tokens 32768 \
  --max-num-seqs 64 \
  --trust-remote-code \
  --enforce-eager \
  --gpu-memory-utilization 0.9 \
  --kv-transfer-config '{
    "kv_connector": "LLMDataDistCMgrConnector",
    "kv_buffer_device": "npu",
    "kv_role": "kv_producer",
    "kv_parallel_size": 1,
    "kv_port": "20001",
    "engine_id": "0",
    "kv_connector_module_path": "vllm_ascend.distributed.llmdatadist_c_mgr_connector"
  }'

4.3 编写Decode启动脚本

在D节点创建start_decode.sh:

#!/bin/bash

# 环境变量配置
export HCCL_IF_IP=141.61.41.164
export GLOO_SOCKET_IFNAME="ens3f0"
export TP_SOCKET_IFNAME="ens3f0"
export HCCL_SOCKET_IFNAME="ens3f0"
export DISAGGREGATED_PREFILL_RANK_TABLE_PATH=/home/<your_name>/vllm-ascend/examples/disaggregate_prefill_v1/ranktable.json
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=32
export VLLM_USE_V1=1
export VLLM_LLMDD_RPC_PORT=5659

# 启动Decode服务
vllm serve /home/models/DeepSeek-V3.1-w8a8-rot-mtp \
  --host 0.0.0.0 \
  --port 20002 \
  --data-parallel-size 1 \
  --data-parallel-size-local 1 \
  --api-server-count 1 \
  --data-parallel-address 141.61.41.164 \
  --data-parallel-rpc-port 13356 \
  --tensor-parallel-size 16 \
  --enable-expert-parallel \
  --quantization ascend \
  --seed 1024 \
  --served-model-name deepseek \
  --max-model-len 8192 \
  --max-num-batched-tokens 256 \
  --max-num-seqs 64 \
  --trust-remote-code \
  --gpu-memory-utilization 0.9 \
  --kv-transfer-config '{
    "kv_connector": "LLMDataDistCMgrConnector",
    "kv_buffer_device": "npu",
    "kv_role": "kv_consumer",
    "kv_parallel_size": 1,
    "kv_port": "20001",
    "engine_id": "0",
    "kv_connector_module_path": "vllm_ascend.distributed.llmdatadist_c_mgr_connector"
  }' \
  --additional-config '{"torchair_graph_config": {"enabled":true}}'

4.4 启动服务

分别在两个节点执行启动脚本:

# P节点
bash start_prefill.sh

# D节点  
bash start_decode.sh

看到Application startup complete.就说明启动成功了。
在这里插入图片描述

4.5 启动负载均衡代理

在P节点开一个新的终端窗口,先配置环境变量:

source /home/<your_name>/cann_8.2.rc1/ascend-toolkit/set_env.sh
source /home/<your_name>/cann_8.2.rc1/nnal/atb/set_env.sh

然后运行代理服务:

cd /home/<your_name>/vllm-ascend/examples/disaggregate_prefill_v1/

python load_balance_proxy_server_example.py \
  --host 141.61.41.163 \
  --port 1025 \
  --prefiller-hosts 141.61.41.163 \
  --prefiller-ports 20002 \
  --decoder-hosts 141.61.41.164 \
  --decoder-ports 20002

启动成功后会显示初始化的prefill和decode客户端数量:
在这里插入图片描述

五、功能验证

5.1 API接口测试

开一个新的终端,发送测试请求:

curl http://141.61.41.163:1025/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek",
    "prompt": "how is it today",
    "max_tokens": 50,
    "temperature": 0
  }'

加上-v参数可以看详细的请求响应过程。返回结果中的choice/text就是模型生成的文本:
在这里插入图片描述

5.2 性能压测

在P节点运行benchmark脚本:

source /home/<your_name>/cann_8.2.rc1/ascend-toolkit/set_env.sh
source /home/<your_name>/cann_8.2.rc1/nnal/atb/set_env.sh

cd /home/<your_name>/vllm/benchmarks/

python benchmark_serving.py \
  --backend vllm \
  --dataset-name random \
  --random-input-len 10 \
  --random-output-len 100 \
  --num-prompts 10 \
  --ignore-eos \
  --model deepseek \
  --tokenizer /home/models/DeepSeek-V3.1-w8a8-rot-mtp \
  --host 141.61.41.163 \
  --port 1025 \
  --endpoint /v1/completions \
  --max-concurrency 4 \
  --request-rate 4

测试结果会显示吞吐量、延迟等关键指标:
在这里插入图片描述

六、踩过的坑

问题1: 找不到torch-npu包

使用pip 25.1.1安装时提示找不到匹配的版本:
在这里插入图片描述

解决办法: 配置正确的镜像源

pip uninstall torch
pip config set global.trusted-host "download.pytorch.org mirrors.huaweicloud.com mirrors.aliyun.com"
pip config set global.extra-index-url "https://download.pytorch.org/whl/cpu/ https://mirrors.huaweicloud.com/ascend/repos/pypi"
pip install torchvision==0.20.1
pip install torch-npu==2.5.1.post1.dev20250619

问题2: torch和torch-npu依赖冲突

安装vllm-ascend时报错:Cannot install torch-npu==2.5.1.post1 and torch>=2.5.1 because these package versions have conflicting dependencies.
在这里插入图片描述

解决办法: 清理环境后重装

pip uninstall torch==2.5.1 torch-npu==2.5.1.post1.dev20250619 -y
pip cache purge
pip config unset global.extra-index-url
pip config set global.extra-index-url "https://download.pytorch.org/whl/cpu/ https://mirrors.huaweicloud.com/ascend/repos/pypi"
pip install torch==2.5.1
pip install torch-npu==2.5.1.post1.dev20250619

# 验证安装
pip show torch torch-npu | grep Version

问题3: NPU显存溢出

启动服务时报错:RuntimeError: NPU out of memory. Tried to allocate 898.00 MiB...
在这里插入图片描述

原因: 没有按量化模式加载模型
解决办法: 在vllm serve命令中加上--quantization ascend

问题4: 量化算子不支持float16

报错信息:Tensor scale not implemented for DT_FLOAT16, should be in dtype support list [DT_UINT64,DT_BFLOAT16,DT_INT64,DT_FLOAT,].

在这里插入图片描述

原因: aclnnQuantMatmulV4算子不支持float16类型
解决办法: 修改模型config.json文件,把torch_dtypefloat16改成bfloat16

问题5: HCCL通信初始化失败

报错:RuntimeError: createHCCLComm:torch_npu/csrc/distributed/ProcessGroupHCCL.cpp:2166 HCCL function error...
在这里插入图片描述

原因: HCCL_IF_IP环境变量配置错误
解决办法: 检查并修正启动脚本中的HCCL_IF_IP,确保和本机IP一致

总结

PD分离部署对大模型推理性能提升确实有明显效果,但配置过程比较繁琐,需要注意的点也很多。希望这份实战记录能帮大家少踩一些坑。

如果在部署过程中遇到其他问题,建议先查看官方文档和社区讨论,很多常见问题都有解决方案。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐