基于 openYuanrong 的 DeepSeek-V4-Flash-w8a8-mtp 8机 A2 大EP PD分离部署

概述

本指南提供在 8 台 Atlas 800I A2 服务器上部署 DeepSeek-V4-Flash-w8a8-mtp 模型,使用 PD 分离架构(4*1P - 1*4D)并叠加 openYuanrong Datasystem 作为 KV Pool 后端的详细步骤。

PD 分离架构下,Prefill 节点与 Decode 节点各司其职,通过 MultiConnector 组合 KV Transfer 与 KV Pool 能力,同时通过 AscendStoreConnector(openYuanrong 后端)实现外部 KV 缓存池,支持前缀缓存复用,降低重复前缀场景下的首 token 时延。

部署全景流程:

前置检查:环境要求确认

  1. 准备模型权重

  2. 拉取镜像与创建容器

  3. 安装 openYuanrong Datasystem

  4. 安装并启动 etcd

  5. 启动 openYuanrong Worker

  6. 启动 PD 分离推理服务

  7. 功能验证

环境要求

硬件要求

  • 8 × Atlas 800I A2 服务器,每台配备 8 张 NPU 卡(每张 64G 显存)

  • 已配置 RoCE 网络以获得最佳性能

软件要求

采用模型配套的 Docker 镜像,软件版本与 Docker 镜像内置版本保持一致,确保 HDK、固件等软件在配套范围内。 此外:CANN 版本要求至少高于 8.5.0,HDK 版本要求至少高于 25.2.3(启用 RH2D 通过 RoCE 传输时,HDK 版本需要 25.5.0 以上)。

环境信息

组件

版本

备注

服务器硬件

Atlas 800I A2 × 8

4机P + 4机D

vLLM-Ascend

vllm-ascend:v0.20.2rc1

CANN

≥ 8.5.0

HDK

≥ 25.2.3(启用 RH2D 需 ≥ 25.5.0)

RH2D 通过 RoCE 需要 HDK ≥ 25.5.0

DeepSeek-V4-Flash-w8a8-mtp 权重

w8a8-mtp

部署步骤

1. 准备模型权重

下载 DeepSeek-V4-Flash-w8a8-mtp 模型权重并放置到指定目录,如 /home/models/DeepSeek-V4-Flash-w8a8-mtp/。

模型下载地址:魔搭社区

2. 拉取镜像与创建容器

拉取镜像

本教程使用的 Docker 镜像版本为 vllm-ascend:v0.20.2rc1。如本地尚未下载,可执行以下命令:

docker pull quay.io/ascend/vllm-ascend:v0.20.2rc1

如果下载较慢,可将 quay.io 替换为 m.daocloud.io/quay.io 或 quay.nju.edu.cn 以加速拉取。更多镜像说明可参考安装文档。

创建容器

在所有 8 个节点上分别保存同一份 start-docker.sh:

#!/bin/bash

IMAGES_ID="$1"
NAME="$2"

if [ $# -ne 2 ]; then
    echo "error: 需要传入2个参数,格式:$0 <镜像ID> <容器名>"
    exit 1
fi

if ! docker images --format "{{.ID}}" | grep -q "^${IMAGES_ID:0:12}$"; then
    echo "error: 镜像ID $IMAGES_ID 不存在"
    exit 1
fi

docker run --name "${NAME}" -it -d --net=host --shm-size=800g \
    --privileged=true \
    -w /home \
    --device=/dev/davinci_manager \
    --device=/dev/hisi_hdc \
    --device=/dev/devmm_svm \
    --entrypoint=bash \
    -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
    -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 /usr/local/sbin:/usr/local/sbin \
    -v /etc/hccn.conf:/etc/hccn.conf \
    -v /home:/home \
    -v /mnt:/mnt \
    -v /tmp:/tmp \
    -v /data:/data \
    -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \
    -e http_proxy="$http_proxy" \
    -e https_proxy="$https_proxy" \
    "${IMAGES_ID}"

查看镜像 ID:

docker images | grep vllm-ascend

在每个节点分别创建容器:

# 在每个节点执行(替换为实际镜像ID)

bash start-docker.sh <镜像ID> ds_v4_flash_yr

进入容器:

docker exec -it ds_v4_flash_yr bash

3. 安装 openYuanrong Datasystem

wget https://gitcode.com/openeuler/yuanrong-datasystem/releases/download/v0.7.6.rc1/openyuanrong_datasystem-0.7.6rc1-cp311-cp311-manylinux_2_35_aarch64.whl

pip install openyuanrong_datasystem-0.7.6rc1-cp311-cp311-manylinux_2_35_aarch64.whl

验证安装:

python -c "import yr.datasystem; print('Yuanrong Datasystem 安装成功')"

4. 安装并启动 etcd

示例为单实例部署,etcd 只需在**节点0(P主节点)**安装和启动,其他节点无需操作。

安装 etcd

后续 openYuanrong 服务启动脚本依赖 etcd 和 etcdctl。至少在 P 主节点安装。

ETCD_VERSION="v3.5.12"
if [ "$(uname -m)" = "aarch64" ]; then
  ETCD_ARCH="linux-arm64"
else
  ETCD_ARCH="linux-amd64"
fi
wget https://github.com/etcd-io/etcd/releases/download/${ETCD_VERSION}/etcd-${ETCD_VERSION}-${ETCD_ARCH}.tar.gz
tar -xvf etcd-${ETCD_VERSION}-${ETCD_ARCH}.tar.gz
cd etcd-${ETCD_VERSION}-${ETCD_ARCH}
cp etcd etcdctl /usr/local/bin/

验证安装:

etcd --version
etcdctl version

启动 etcd

创建启动脚本 run_etcd.sh,在节点0(P主节点)启动 etcd:

#!/bin/bash

export ETCD_IP=`hostname -I|awk -F " " '{print$1}'`
export ETCD_PORT=2379
export ETCD_PEER_PORT=2380

etcd \
  --name etcd-single \
  --data-dir /tmp/etcd-data \
  --listen-client-urls http://<IP_ADDRESS>:${ETCD_PORT} \
  --advertise-client-urls http://${ETCD_IP}:${ETCD_PORT} \
  --listen-peer-urls http://<IP_ADDRESS>:${ETCD_PEER_PORT} \
  --initial-advertise-peer-urls http://${ETCD_IP}:${ETCD_PEER_PORT} \
  --initial-cluster etcd-single=http://${ETCD_IP}:${ETCD_PEER_PORT} \
  > /tmp/etcd.log 2>&1 &

sleep 3

etcdctl --endpoints "${ETCD_IP}:${ETCD_PORT}" put key "value"
etcdctl --endpoints "${ETCD_IP}:${ETCD_PORT}" get key

echo "ETCD start finished, log dir: /tmp/etcd.log"

验证:

# 方式1,预期输出:{"health":"true","reason":""}

etcdctl --endpoints "${ETCD_IP}:${ETCD_PORT}" endpoint health

# 方式2,预期输出:100.100.xxx.xxx:2379 is healthy: successfully committed proposal: took = 1.43913ms

curl -L http://${ETCD_IP}:${ETCD_PORT}/health

etcd 参数说明:

参数

值

说明

name

etcd-single

etcd 节点名称,集群中必须唯一

data-dir

/tmp/etcd-data

数据存储目录,用于持久化保存 etcd 数据

listen-client-urls

http://<IP_ADDRESS>:2379

监听客户端请求的 URL 地址

advertise-client-urls

http://${ETCD_IP}:2379

对外广播的客户端 URL

listen-peer-urls

http://<IP_ADDRESS>:2380

监听集群节点间通信的 URL 地址

initial-advertise-peer-urls

http://${ETCD_IP}:2380

对外广播的集群通信 URL

initial-cluster

etcd-single=http://${ETCD_IP}:2380

初始集群配置

参考文档:etcd 官方文档

生产环境建议:上述示例为单实例部署,适用于测试和开发环境。对于可靠性要求较高的生产环境,建议部署 etcd 集群(通常 3 或 5 个节点)。

5. 启动 openYuanrong Worker

8 机场景需要在所有 8 个节点都启动 Datasystem Worker,并连接步骤5中启动的 etcd。

每个节点创建启动脚本 run_yr_worker.sh:

#!/bin/bash

export HOST_IP=`hostname -I|awk -F " " '{print$1}'`
export ETCD_IP="修改为ETCD的节点IP"
export WORKER_PORT=18481
export ETCD_PORT=2379
export SHM_SIZE=512000
export NODE_TIMEOUT=30
export NODE_DEAD_TIMEOUT=60
export LIVENESS_PATH=/workspace/liveness

dscli start -t 600 -w \
  --worker_address ${HOST_IP}:${WORKER_PORT} \
  --etcd_address ${ETCD_IP}:${ETCD_PORT} \
  --shared_memory_size_mb ${SHM_SIZE} \
  --node_timeout_s ${NODE_TIMEOUT} \
  --node_dead_timeout_s ${NODE_DEAD_TIMEOUT} \
  --liveness_check_path ${LIVENESS_PATH}

echo "Yuanrong service start finished!"

如需开通 RH2D 功能,参考附录:开启 RH2D。

Datasystem Worker 参数说明:

参数

值

说明

worker_address

\({HOST_IP}:\){WORKER_PORT}

Worker 服务地址和端口

etcd_address

\({ETCD_IP}:\){ETCD_PORT}

etcd 服务发现地址

shared_memory_size_mb

512000

共享内存大小(500 GB)

node_timeout_s

30

节点超时时间(秒)

node_dead_timeout_s

60

节点死亡超时时间(秒)

rpc_thread_num

16

处理线程数量

enable_worker_worker_batch_get

false

批量传输key

liveness_check_path

/workspace/liveness

存活检查路径

6. PD分离部署VLLM服务

部署说明

部署形态
  • 8机、4*1P-1*4D + Yuanrong

4*1P表示共有4个P实例,每个实例占用一台机器;1*4D表示共有1个D实例,每个实例占用4台机器

并行策略
  • P节点:DP2,TP4(共4机,每机 2 个数据并行副本,组成4个独立的本地DP组,全局8个Prefill实例)

  • D节点:DP32,TP1(共4机,每机 8 个数据并行副本,4机共同组成1个全局DP32通信组)

节点分配

节点

角色

IP(示例)

需要文件

节点 0

P 主节点

<P0_IP>

launch_online_dp.py、run_dp_template.sh、server.sh、proxy.sh、load_balance_proxy_server_example.py

节点 1

P 从节点

<P1_IP>

launch_online_dp.py、run_dp_template.sh、server.sh

节点 2

P 从节点

<P2_IP>

launch_online_dp.py、run_dp_template.sh、server.sh

节点 3

P 从节点

<P3_IP>

launch_online_dp.py、run_dp_template.sh、server.sh

节点 4

D 主节点

<D0_IP>

launch_online_dp.py、run_dp_template.sh、server.sh

节点 5

D 从节点

<D1_IP>

launch_online_dp.py、run_dp_template.sh、server.sh

节点 6

D 从节点

<D2_IP>

launch_online_dp.py、run_dp_template.sh、server.sh

节点 7

D 从节点

<D3_IP>

launch_online_dp.py、run_dp_template.sh、server.sh

脚本说明:

详细说明见:external_online_dp README

部署流程

P节点

run_dp_template.sh 模板,请按实际情况修改 nic_name、权重路径/home/117_share/weight/DeepSeek-V4-Flash-w8a8-mtp/:

unset ftp_proxy
unset https_proxy
unset http_proxy
rm -rf ~/ascend/log

nic_name="enp67s0f0np0"
local_ip=`hostname -I|awk -F " " '{print$1}'`

# # jemalloc

export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD

# # AIV

export HCCL_OP_EXPANSION_MODE="AIV"
export TASK_QUEUE_ENABLE=1
export VLLM_RPC_TIMEOUT=3600000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export HCCL_EXEC_TIMEOUT=204
export HCCL_CONNECT_TIMEOUT=1200

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 PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_BUFFSIZE=1024
export ASCEND_RT_VISIBLE_DEVICES=$1
export TASK_QUEUE_ENABLE=1
export VLLM_ASCEND_APPLY_DSV4_PATCH=1


vllm serve /home/117_share/weight/DeepSeek-V4-Flash-w8a8-mtp/ \
    --host <IP_ADDRESS> \
    --port $2 \
    --data-parallel-size $3 \
    --data-parallel-rank $4 \
    --data-parallel-address $5 \
    --data-parallel-rpc-port $6 \
    --tensor-parallel-size $7 \
    --enable-expert-parallel \
    --seed 1024 \
    --served-model-name deepseek_v4 \
    --max-model-len 1048576 \
    --max-num-batched-tokens 8192 \
    --max-num-seqs 16 \
    --block-size 128 \
    --enforce-eager \
    --async-scheduling \
    --no-disable-hybrid-kv-cache-manager \
    --enable-prefix-caching \
    --trust-remote-code \
    --gpu-memory-utilization 0.9 \
    --quantization ascend \
    --safetensors-load-strategy 'prefetch' \
    --model-loader-extra-config='{"enable_multithread_load": "true", "num_threads": 128}' \
    --tokenizer-mode deepseek_v4 \
    --tool-call-parser deepseek_v4 \
    --enable-auto-tool-choice \
    --reasoning-parser deepseek_v4 \
    --additional-config '{"enable_cpu_binding": true, "enable_shared_expert_dp": true}' \
    --speculative-config '{"num_speculative_tokens": 1, "method": "mtp","enforce_eager": true}' \
    --kv-transfer-config \
    '{
        "kv_connector": "MultiConnector",
        "kv_role": "kv_producer",
        "engine_id": "0",
        "kv_connector_extra_config": {
            "connectors": [
                {
                    "kv_connector": "MooncakeHybridConnector",
                    "kv_role": "kv_producer",
                    "kv_port": "30000",
                    "kv_connector_extra_config": {
                        "use_ascend_direct": true,
                        "prefill": {
                            "dp_size": 2,
                            "tp_size": 4
                        },
                        "decode": {
                            "dp_size": 32,
                            "tp_size": 1
                        }
                    }
                },
                {
                    "kv_connector": "AscendStoreConnector",
                    "kv_role": "kv_producer",
                    "kv_connector_extra_config": {
                        "lookup_rpc_port": "0",
                        "backend": "yuanrong"
                    }
                }
            ]
        }
    }'

server.sh:P节点 DP8、TP4(每机2个DP副本)

每个P节点分别执行如下对应命令

# <P0_IP> P 主节点

python launch_online_dp.py --dp-size 2 --tp-size 4 --dp-size-local 2 --dp-rank-start 0 --dp-address <P0_IP> --dp-rpc-port 12321 --vllm-start-port 7100

# <P1_IP> P 从节点

python launch_online_dp.py --dp-size 2 --tp-size 4 --dp-size-local 2 --dp-rank-start 0 --dp-address <P1_IP> --dp-rpc-port 12321 --vllm-start-port 7100

# <P2_IP> P 从节点

python launch_online_dp.py --dp-size 2 --tp-size 4 --dp-size-local 2 --dp-rank-start 0 --dp-address <P2_IP> --dp-rpc-port 12321 --vllm-start-port 7100

# <P3_IP> P 从节点

python launch_online_dp.py --dp-size 2 --tp-size 4 --dp-size-local 2 --dp-rank-start 0 --dp-address <P3_IP> --dp-rpc-port 12321 --vllm-start-port 7100
D节点

run_dp_template.sh 模板,请按实际情况修改 nic_name、权重路径/home/117_share/weight/DeepSeek-V4-Flash-w8a8-mtp/:

unset ftp_proxy
unset https_proxy
unset http_proxy
rm -rf ~/ascend/log

nic_name="enp67s0f0np0"
local_ip=`hostname -I|awk -F " " '{print$1}'`

# jemalloc

export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD

# # AIV

export HCCL_OP_EXPANSION_MODE="AIV"
export TASK_QUEUE_ENABLE=1
export VLLM_ASCEND_APPLY_DSV4_PATCH=1
export VLLM_RPC_TIMEOUT=3600000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export HCCL_EXEC_TIMEOUT=204
export HCCL_CONNECT_TIMEOUT=1200

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 PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_BUFFSIZE=1024

export ASCEND_RT_VISIBLE_DEVICES=$1

vllm serve /home/117_share/weight/DeepSeek-V4-Flash-w8a8-mtp/ \
    --host <IP_ADDRESS> \
    --port $2 \
    --data-parallel-size $3 \
    --data-parallel-rank $4 \
    --data-parallel-address $5 \
    --data-parallel-rpc-port $6 \
    --tensor-parallel-size $7 \
    --enable-expert-parallel \
    --seed 1024 \
    --served-model-name deepseek_v4 \
    --max-model-len 1048576 \
    --max-num-batched-tokens 60 \
    --max-num-seqs 30 \
    --async-scheduling \
    --block-size 128 \
    --no-disable-hybrid-kv-cache-manager \
    --no-enable-prefix-caching \
    --trust-remote-code \
    --gpu-memory-utilization 0.9 \
    --quantization ascend \
    --safetensors-load-strategy 'prefetch' \
    --model-loader-extra-config='{"enable_multithread_load": "true", "num_threads": 128}' \
    --tokenizer-mode deepseek_v4 \
    --tool-call-parser deepseek_v4 \
    --enable-auto-tool-choice \
    --reasoning-parser deepseek_v4 \
    --speculative-config '{"num_speculative_tokens": 1, "method": "mtp","enforce_eager": true}' \
    --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
    --kv-transfer-config \
        "{
        \"kv_connector\": \"MultiConnector\",
        \"kv_role\": \"kv_consumer\",
        \"kv_connector_extra_config\": {
            \"connectors\": [
                {
                    \"kv_connector\": \"MooncakeHybridConnector\",
                    \"kv_role\": \"kv_consumer\",
                    \"kv_port\": \"30100\",
                    \"kv_connector_module_path\": \"vllm_ascend.distributed.mooncake_connector\",
                    \"kv_connector_extra_config\": {
                        \"use_ascend_direct\": true,
                        \"prefill\": {
                            \"dp_size\": 2,
                            \"tp_size\": 4
                        },
                        \"decode\": {
                            \"dp_size\": 32,
                            \"tp_size\": 1
                        }
                    }
                },
                {
                    \"kv_connector\": \"AscendStoreConnector\",
                    \"kv_role\": \"kv_consumer\",
                    \"kv_connector_extra_config\": {
                        \"lookup_rpc_port\": \"$4\",
                        \"backend\": \"yuanrong\"
                    }
                }
            ]
        }
    }" \
    --additional-config '{
        "ascend_compilation_config":{
              "enable_npugraph_ex":true,
              "enable_static_kernel":false
        },
       "enable_cpu_binding":true,
       "multistream_overlap_shared_expert":true,
       "recompute_scheduler_enable":true
    }'

server.sh:D节点 DP32、TP1(每机8个DP副本)

每个D节点分别执行如下对应命令

# <D0_IP> D 主节点

python launch_online_dp.py --dp-size 32 --tp-size 1 --dp-size-local 8 --dp-rank-start 0 --dp-address <D0_IP> --dp-rpc-port 12321 --vllm-start-port 7100

# <D1_IP> D 从节点

python launch_online_dp.py --dp-size 32 --tp-size 1 --dp-size-local 8 --dp-rank-start 8 --dp-address <D1_IP> --dp-rpc-port 12321 --vllm-start-port 7100

# <D2_IP> D 从节点

python launch_online_dp.py --dp-size 32 --tp-size 1 --dp-size-local 8 --dp-rank-start 16 --dp-address <D2_IP> --dp-rpc-port 12321 --vllm-start-port 7100

# <D3_IP> D 从节点

python launch_online_dp.py --dp-size 32 --tp-size 1 --dp-size-local 8 --dp-rank-start 24 --dp-address <D3_IP> --dp-rpc-port 12321 --vllm-start-port 7100
启动proxy

proxy.sh:只存在于 P 主节点,在 P/D 节点服务启动成功后执行 bash proxy.sh > proxy.log &,根据实际情况修改组网 IP。

unset http_proxy
unset https_proxy

python load_balance_proxy_server_example.py \
  --port 18020 \
  --host <D0_IP> \
  --prefiller-hosts \
    <P0_IP> <P0_IP> \
    <P1_IP> <P1_IP> \
    <P2_IP> <P2_IP> \
    <P3_IP> <P3_IP> \
  --prefiller-ports \
    7100 7101 \
    7100 7101 \
    7100 7101 \
    7100 7101 \
  --decoder-hosts \
    <D0_IP> <D0_IP> <D0_IP> <D0_IP> <D0_IP> <D0_IP> <D0_IP> <D0_IP> \
    <D1_IP> <D1_IP> <D1_IP> <D1_IP> <D1_IP> <D1_IP> <D1_IP> <D1_IP> \
    <D2_IP> <D2_IP> <D2_IP> <D2_IP> <D2_IP> <D2_IP> <D2_IP> <D2_IP> \
    <D3_IP> <D3_IP> <D3_IP> <D3_IP> <D3_IP> <D3_IP> <D3_IP> <D3_IP> \
  --decoder-ports \
    7100 7101 7102 7103 7104 7105 7106 7107 \
    7100 7101 7102 7103 7104 7105 7106 7107 \
    7100 7101 7102 7103 7104 7105 7106 7107 \
    7100 7101 7102 7103 7104 7105 7106 7107 \
  >proxy_log.log 2>&1 &

配置参数说明

P节点参数

参数

值

说明

tensor-parallel-size

4

每节点使用 4 张 NPU 卡

data-parallel-size

8

数据并行大小(4 个 P 节点,每节点 2 副本)

max-model-len

1048576

最大上下文长度

max-num-batched-tokens

8192

最大批处理 token 数

max-num-seqs

16

最大并发序列数

gpu-memory-utilization

0.9

GPU 显存利用率

quantization

ascend

使用 Ascend 量化

enable-expert-parallel

(标志)

启用 MoE 专家并行

async-scheduling

(标志)

启用异步调度

kv_connector

MooncakeHybridConnector

使用 MooncakeHybridConnector

kv_role (P节点)

kv_producer

Prefill 节点作为 KV 生产者

kv_port

30000

Mooncake 传输端口

prefill dp_size

8

Prefill 数据并行大小

prefill tp_size

4

Prefill 张量并行大小

decode dp_size

32

Decode 数据并行大小

decode tp_size

1

Decode 张量并行大小

D节点参数

参数

值

说明

tensor-parallel-size

1

每个数据并行副本使用 1 张 NPU 卡

data-parallel-size

32

数据并行大小(32 个数据并行副本)

max-model-len

1048576

最大上下文长度

max-num-batched-tokens

60

最大批处理 token 数

max-num-seqs

30

最大并发序列数

gpu-memory-utilization

0.9

GPU 显存利用率

kv_connector

MooncakeHybridConnector

使用 MooncakeHybridConnector

kv_role (D节点)

kv_consumer

Decode 节点作为 KV 消费者

kv_port

30400

Mooncake 传输端口

prefill dp_size

2

Prefill 数据并行大小

prefill tp_size

4

Prefill 张量并行大小

decode dp_size

32

Decode 数据并行大小

decode tp_size

1

Decode 张量并行大小

cudagraph_mode

FULL_DECODE_ONLY

仅 Decode 阶段使用 CUDA Graph

环境变量说明

环境变量

值

说明

HCCL_OP_EXPANSION_MODE

AIV

HCCL 算子扩展模式(AI Vector 优化)

OMP_PROC_BIND

false

OpenMP 线程绑定配置

OMP_NUM_THREADS

10

OpenMP 线程数

HCCL_BUFFSIZE

1024

HCCL 缓冲区大小

PYTORCH_NPU_ALLOC_CONF

expandable_segments:True

NPU 显存分配策略(减少碎片)

VLLM_RPC_TIMEOUT

3600000

RPC 超时时间(毫秒)

VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS

30000

模型执行超时时间(秒)

HCCL_EXEC_TIMEOUT

204

HCCL 执行超时

HCCL_CONNECT_TIMEOUT

1200

HCCL 连接超时

TASK_QUEUE_ENABLE

1

启用任务队列(流水优化)

VLLM_ASCEND_APPLY_DSV4_PATCH

1

应用 DeepSeek-V4 补丁

MooncakeHybridConnector 配置结构说明

MooncakeHybridConnector 的 kv-transfer-config JSON 结构如下:

{
    "kv_connector": "MooncakeHybridConnector",
    "kv_role": "kv_producer" | "kv_consumer",
    "kv_port": "端口号",
    "engine_id": "可选,用于区分不同引擎实例",
    "kv_connector_extra_config": {
        "prefill": {
            "dp_size": N,
            "tp_size": M
        },
        "decode": {
            "dp_size": N,
            "tp_size": M
        }
    }
}

关键注意事项:

  1. kv_role 一致性:P 节点为 kv_producer,D 节点为 kv_consumer

  2. kv_port 区分:MooncakeHybridConnector 的 kv_port 在 Prefill 和 Decode 节点应不同(如 30000 vs 30400)

  3. engine_id:用于区分不同引擎实例,确保 P 和 D 节点的 engine_id 配置正确

  4. 并行配置:prefill 和 decode 的 dp_size 和 tp_size 需与实际部署配置一致

叠加特性优化

优化特性

使能方法

W8A8模型量化

ModelScope权重

异步调度

--async-scheduling

jemalloc内存优化

export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD

AIV通信优化

export HCCL_OP_EXPANSION_MODE="AIV"

多线程模型加载

--model-loader-extra-config='{"enable_multithread_load": "true", "num_threads": 128}'

DeepSeek-V4补丁

export VLLM_ASCEND_APPLY_DSV4_PATCH=1

MTP推测解码

--speculative-config '{"num_speculative_tokens": 1, "method": "mtp","enforce_eager": true}'

CPU亲和性绑定

--additional-config '{"enable_cpu_binding": true}'

共享专家DP

--additional-config '{"enable_shared_expert_dp": true}'

共享专家多流

--additional-config '{"multistream_overlap_shared_expert": true}'

流水优化

export TASK_QUEUE_ENABLE=1

FULL_DECODE_ONLY(仅D节点)

--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}'

7. 功能验证

服务启动后,验证部署是否成功。

测试推理

curl -H "Accept: application/json" \
    -H "Content-type: application/json" \
    -X POST \
    -d '{
        "model": "deepseek_v4",
        "messages": [{
            "role": "user",
            "content": "你好,请介绍一下人工智能的未来发展趋势。"
        }],
        "stream": false,
        "ignore_eos": false,
        "temperature": 0,
        "max_tokens": 200
    }' http://localhost:18020/v1/chat/completions

缓存命中率监控

查看 vLLM 日志

按需修改日志文件路径vllm_log.log

# 查看最新日志

tail -f vllm_log.log

# 实时监控命中率相关日志

tail -f vllm_log.log | grep -E "Prefix cache hit rate|External prefix cache hit rate|num_computed_tokens"
使用脚本持续监控命中率

如果当前环境包含 vllm-ascend 仓库源码,可以使用仓库自带脚本持续观测命中率:

bash tools/watch_cache_hit_rate.sh -u http://localhost:18020/metrics -i 10

# 如需将结果同时保存到文件

bash tools/watch_cache_hit_rate.sh \
  -u http://localhost:18020/metrics \
  -i 10 \
  -o cache_hit_rate.log

常用字段:

  • local_win:vLLM 本地 Prefix Cache 的窗口命中率

  • local_total:vLLM 本地 Prefix Cache 的累计命中率

  • ext_win:openYuanrong 外部 KV Cache 的窗口命中率

  • ext_total:openYuanrong 外部 KV Cache 的累计命中率

  • eff_total:综合本地和外部缓存后的端到端有效命中率

缓存命中率指标说明

指标

说明

统计方式

Prefix cache hit rate

**HBM(本地显存)**命中率

滑动窗口:最近 1000 个请求

External prefix cache hit rate

**openYuanrong(外部 KV Cache)**命中率

累计统计:从服务启动到当前时刻

TTFT (Time to First Token)

首个 token 延迟

单次请求指标,命中率高时 TTFT 显著降低

查看 openYuanrong 外部缓存命中率:

curl http://localhost:18020/metrics | grep external_prefix_cache

查看单次请求是否命中:

grep "num_computed_tokens" $LOG_FILE

如果 num_computed_tokens > 0,表示该请求命中了缓存。

可靠性检查

可靠性方案介绍

在8机大EP部署场景中,可靠性方案主要依赖健康检查实现。建议使用监控系统通过存活探针周期性针对vllm服务、元戎、ETCD进行存活检测,若检测失败则重启推理服务容器,进行一次完整推理部署操作。 健康检查脚本目录结构如下图所示:

image-20260526154318108

注意事项:

  • 就绪探针中仅检查vllm服务状态

  • 存活探针中检查vllm服务、元戎、ETCD状态

就绪探针检查脚本

拉起服务后进行首次可用性检查,脚本执行操作如下:

  • 在主节点构造http协议请求模型服务(v1/chat/comoletions);

  • 判断请求是否正确返回;

vllm_probe.py内容如下:

import sys
import subprocess
import requests
import socket
import logging
import json

logging.basicConfig(
    format='%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    level=logging.INFO,
    filename='./health_check_probe.log',
    filemode='a'
)

if __name__ == "__main__":
    hostname = socket.gethostname()
    local_ip = socket.gethostbyname(hostname)
    api_url = f"http://{local_ip}:18020/v1/chat/completions"

    headers = {
        'Content-Type': 'application/json',
    }
    request_data = {
        "model": "deepseek_v4",
        "messages": [{"role": "user", "content": "hello"}],
        "stream": False,
        "max_tokens": 2,
        "temperature": 0.6,
        "chat_template_kwargs": {"enable_thinking": False}
    }

    try:
        response = requests.post(
            api_url,
            json=request_data,
            headers=headers,
            stream=False,
            timeout=1200
        )
    except Exception as e:
        logging.error(f"requests post failed, Exception: {e}")
        sys.exit(1)

    if response.status_code != 200:
        logging.error(f"Response error, status code: {response.status_code}, text: {response.text}")
        sys.exit(1)

    try:
        response_info = json.loads(response.text)
        if len(response_info['choices'][0]['message']['content']) == 0:
            logging.error("response content len is 0")
            sys.exit(1)
        print("vLLM serve check success!")
    except Exception as e:
        logging.error(f"json parse failed, text: {response.text}, Exception: {e}")
        sys.exit(1)

    logging.info(f"health check success, response: {response.text}")
    logging.info("Master node health check completed")

vllm_probe.py用法:


# 主节点执行:

python vllm_probe.py

预期输出:(详细日志查看health_check_probe.log)

vLLM serve check success!

存活探针检查脚本

部署过程中可手动执行以下脚本验证各组件状态;部署后运行期间,可将这些脚本加入监控系统中周期性执行。

脚本执行流程如下:

  • 执行元戎worker健康检查;

  • 在主节点执行ETCD健康检查;

  • 在主节点构造http协议请求模型服务(v1/chat/comoletions);

  • 判断请求是否正确返回;

vllm_probe_yr.py内容如下:

import sys
import subprocess
import socket
import requests
import logging
import json

logging.basicConfig(
    format='%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    level=logging.INFO,
    filename='./health_check_probe.log',
    filemode='a'
)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        logging.error("Please specify node role: master or slave")
        sys.exit(1)

    node_role = sys.argv[1].lower()
    if node_role not in ["master", "slave"]:
        logging.error(f"Invalid node role: {node_role}. Please use 'master' or 'slave'")
        sys.exit(1)

    # 1、Check yuanrong
    try:
        ret = subprocess.run(["bash", "./yr_liveness_check.sh"])
        if ret.returncode == 1:
            logging.error("yuanrong check fail !")
            sys.exit(1)

    except Exception as e:
        logging.error(f"yuanrong check failed, Exception: {e}")
        sys.exit(1)

    logging.info("yuanrong check success !")

    # only master node need to check etcd & vllm serve
    if node_role == "slave":
        logging.info("Slave node health check completed (only yuanrong check)")
        sys.exit(0)
    logging.info("Master node health check start")

    local_ip = socket.gethostbyname(socket.gethostname())

    # 2、Check ETCD:Master node should check etcd
    etcd_port = 12379
    try:
        ret = subprocess.run(["bash", "./etcd_liveness_check.sh", f"{local_ip}:{etcd_port}"])
        if ret.returncode == 1:
            logging.error("etcd check fail !")
            sys.exit(1)
    except Exception as e:
        logging.error(f"etcd check failed, Exception: {e}")
        sys.exit(1)
    logging.info("yuanrong etcd check success !")

    # Check vllm serve
    api_url = f"http://{local_ip}:18020/v1/chat/completions"

    headers = {
        'Content-Type': 'application/json',
    }
    request_data = {
        "model": "deepseek_v4",
        "messages": [{"role": "user", "content": "hello"}],
        "stream": False,
        "max_tokens": 2,
        "temperature": 0.6,
        "chat_template_kwargs": {"enable_thinking": False}
    }

    try:
        response = requests.post(
            api_url,
            json=request_data,
            headers=headers,
            stream=False,
            timeout=1200
        )
    except Exception as e:
        logging.error(f"requests post failed, Exception: {e}")
        sys.exit(1)

    if response.status_code != 200:
        logging.error(f"response error, status code: {response.status_code}, text: {response.text}")
        sys.exit(1)

    try:
        response_info = json.loads(response.text)
        if len(response_info["choices"][0]["message"]["content"]) == 0:
            logging.error("response content len is 0")
            sys.exit(1)
        print("vLLM serve check success!")
    except Exception as e:
        logging.error(f"json parse failed, text: {response.text}, Exception: {e}")
        sys.exit(1)

    logging.info(f"health check success, response: {response.text}")

    logging.info("end")

vllm_probe_yr.py脚本依赖utils.sh、etcd_liveness_check.sh、yr_liveness_check.sh, 内容如下:

创建脚本utils.sh

#!/bin/bash

# Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.

# # Licensed under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance with the License.

# You may obtain a copy of the License at

# # http://www.apache.org/licenses/LICENSE-2.0

# # Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

set -e

shopt -s expand_aliases

readonly UTILS_WORK_DIR=$(dirname "$(readlink -f "$0")")
readonly UTILS_LOG_FILE=${WORKER_LOG_DIR}/container.log
readonly UTILS_LOCK_FILE=${WORKER_LOG_DIR}/.loglock
readonly UTILS_LOCK_DIR=${WORKER_LOG_DIR}/.loglockdir
readonly UTILS_MAX_LOG_SIZE=10485760 # 10MB
readonly UTILS_MAX_LOG_COUNT=9 # not include the current log file.
readonly UTILS_PREFIX=${UTILS_LOG_FILE%.*}
readonly UTILS_SUFFIX=${UTILS_LOG_FILE##*.}
alias ilog='utils_log I ${BASH_SOURCE##*/}:$LINENO'
alias wlog='utils_log W ${BASH_SOURCE##*/}:$LINENO'
alias elog='utils_log E ${BASH_SOURCE##*/}:$LINENO'

function utils_log_impl() {
    echo -e "$(date -u '+%Y-%m-%dT%H:%M:%S.%6N') | $1 | $2 |  | $$ |  |  | $3" >> ${UTILS_LOG_FILE}
    if [ "$1" == "E" -o "$1" == "W" ]; then
        echo -e "$3" >&2
    fi
}

function utils_rm_logfile() {
    local files=($(ls ${UTILS_PREFIX}.*.${UTILS_SUFFIX}))
    local to_del_count=$((${#files[@]} - $UTILS_MAX_LOG_COUNT))
    for file in "${files[@]}"; do
        if [ ${to_del_count} -lt 1 ]; then
            break
        fi
        to_del_count=$((to_del_count-1))
        utils_log_impl I ${BASH_SOURCE##*/}:$LINENO "rm log file ${file}"
        rm ${file}
    done
}

# rotate the logs if log file exceeds the max size

function utils_rotate_logfile() {
    local cur_time_str=$(date -u "+%Y%m%d%H%M%S")
    local new_log_file=${UTILS_PREFIX}.${cur_time_str}.${UTILS_SUFFIX}
    local file_size=$((du -b ${UTILS_LOG_FILE} 2>/dev/null |  | echo 0) | awk '{print $1}')
    if [ ${file_size} -gt ${UTILS_MAX_LOG_SIZE} ]; then
        mv ${UTILS_LOG_FILE} ${new_log_file}
        touch ${UTILS_LOG_FILE}
        utils_rm_logfile
    fi
}

function utils_trylock_exec() {
    local cmd="$1"
    if command -v flock >/dev/null 2>&1; then
        flock -n ${UTILS_LOCK_FILE} -c "$cmd"
    else
        # using create dir to simulate flock.
        if mkdir "${UTILS_LOCK_DIR}" 2>/dev/null; then
            ${cmd} |  | true
            rmdir "${UTILS_LOCK_DIR}"
        else
            # remove dir if the lock dir was created 30s ago.
            local current_time=$(date +%s)
            local update_time=$(stat -c %Z ${UTILS_LOCK_DIR} 2>/dev/null |  | echo ${current_time})
            local timeout=30
            if [[ $((current_time - update_time)) -gt $timeout ]]; then
                utils_log_impl I ${BASH_SOURCE##*/}:$LINENO "rm timeout lock dir ${UTILS_LOCK_DIR}"
                rmdir "${UTILS_LOCK_DIR}" 2>/dev/null
	        fi
        fi
    fi
}

function utils_log() {
    utils_log_impl "$@"
    local file_size=$((du -b ${UTILS_LOG_FILE} 2>/dev/null |  | echo 0) | awk '{print $1}')
    if [ ${file_size} -gt ${UTILS_MAX_LOG_SIZE} ]; then
        utils_trylock_exec "bash ${UTILS_WORK_DIR}/utils.sh ROTATE_LOG" |  | true
    fi
    chmod 640 ${UTILS_LOG_FILE} 2>/dev/null |  | true
}

# get value from datasystem_worker args, like: --key=value

function utils_get_worker_arg_value() {
    local key="$1"
    ps -ef | awk -v key="${key}" '/datasystem_worker/ {
        for (i = 1; i <= NF; i++) {
            idx = index($i, "=")
            if(idx > 1 && substr($i, 0, idx - 1) == "--" key) {
                print substr($i, idx + 1)
                exit
            }
        }
    }'
}

if [ "${1}" == "ROTATE_LOG" ]; then
    utils_rotate_logfile
fi

创建脚本 etcd_liveness_check.sh,用于etcd 健康检查:

#!/usr/bin/env bash

set -euo pipefail

ETCD_ADDR="${1:-<IP_ADDRESS>:2379}"

if etcdctl --endpoints="http://${ETCD_ADDR}" endpoint health >/dev/null 2>&1; then
    echo "etcd is ready: ${ETCD_ADDR}"
    exit 0
fi

echo "etcd is not ready: ${ETCD_ADDR}" >&2
exit 1

创建脚本 yr_liveness_check.sh, 用于 openYuanrong Worker 健康检查:

set -e

readonly USAGE="Options:
-f location of the liveness probe file, it must be set.
  For example, set to \"../datasystem/liveness\"
-t liveness probe timeout in seconds.
"
readonly WORK_DIR=$(dirname "$(readlink -f "$0")")
source ${WORK_DIR}/utils.sh

function main() {
    PROBE_PATH=/workspace/liveness
    PROBE_TIMEOUT=30

    while getopts 'f:t:' OPT; do
        case "${OPT}" in
            f)
                PROBE_PATH="${OPTARG}"
                ;;
            t)
                PROBE_TIMEOUT="${OPTARG}"
                ;;
            ?)
                echo -e "${USAGE}"
                exit 1
                ;;
        esac
    done

    if [ ! -e "${PROBE_PATH}" ]; then
        elog "liveness probe file ${PROBE_PATH} not exists!"
        exit 1
    fi

    content="$(cat ${PROBE_PATH})"
    if ! grep -q "liveness check success" "${PROBE_PATH}"; then
        elog "liveness probe ${PROBE_PATH} check failed: ${content}"
        exit 1
    fi

    PROBE_LAST_UPDATE_TIME=$(stat -c %Y ${PROBE_PATH})
    CURRENT_TIME=$(date +%s)
    if [[ $((CURRENT_TIME - PROBE_LAST_UPDATE_TIME)) -gt $PROBE_TIMEOUT ]]; then
        elog "liveness probe not update in ${PROBE_TIMEOUT}"
        exit 1
    fi
}
main "$@"

vllm_probe_yr.py用法:


# 主节点执行:

python vllm_probe_yr.py master

# 从节点执行

python vllm_probe_yr.py slave

预期输出:(详细日志查看health_check_probe.log)

yuanrong check success !
etcd is ready: <IP_ADDRESS>:12379
vLLM serve check success!

附录

openYuanrong 性能优化

使用大页内存

1. 配置大页内存

1)检查是否分配

grep -i huge /proc/meminfo
  • HugePages_Total显示为0表示未分配

  • Hugepagesize表示单个页大小,通常为2MB

2)检查当前可用内存,要求 MemAvailable 大于要分配的内存大小:

grep MemAvailable /proc/meminfo

3)分配大页(此处分配250页,共500G,按需调整):

"echo 250000 > /proc/sys/vm/nr_hugepages"

4)验证分配结果:

grep -i huge /proc/meminfo

预期配置:HugePages_Total 达到或接近目标值(250000)。

2. 服务端(openYuanrong Worker)使用大页

在 run_yr_worker.sh 的 dscli start 命令中调整超时时间,添加 --arena_per_tenant、enable_huge_tlb 参数:

export NODE_TIMEOUT=300
export NODE_DEAD_TIMEOUT=600

dscli start -t 600 -w \
  ......
  --arena_per_tenant 1 \
  --enable_huge_tlb true

新增参数说明:

参数

示例值

说明

arena_per_tenant

1

每个 tenant 的 arena 数量,初始建议值为 1,在保证功能的前提下提供最快的启动速度

enable_huge_tlb

true

开启共享内存大页内存,可有效提升内存的分配与拷贝性能。共享内存大于 21G 时需开启,并需提前配置系统大页

完整的 openYuanrong worker启动脚本 run_yr_worker.sh如下:

#!/bin/bash

export HOST_IP="<当前节点IP>"
export ETCD_IP="<ETCD_IP>"
export WORKER_PORT=18481
export ETCD_PORT=2379
export SHM_SIZE=512000
export NODE_TIMEOUT=300
export NODE_DEAD_TIMEOUT=600
export LIVENESS_PATH=/workspace/liveness

dscli start -t 600 -w \
  --worker_address ${HOST_IP}:${WORKER_PORT} \
  --etcd_address ${ETCD_IP}:${ETCD_PORT} \
  --shared_memory_size_mb ${SHM_SIZE} \
  --node_timeout_s ${NODE_TIMEOUT} \
  --node_dead_timeout_s ${NODE_DEAD_TIMEOUT} \
  --liveness_check_path ${LIVENESS_PATH} \
  --arena_per_tenant 1 \
  --enable_huge_tlb true

echo "Yuanrong service start finished!"

开启RH2D

RH2D(Remote Host to Device)是一种基于昇腾 NPU 的跨节点数据传输机制,支持从远端节点主机侧共享内存到设备侧 HBM 内存的直接传输,可显著提升 KV Cache 跨节点传输性能。

前提条件:HDK 版本需 ≥ 25.5.0,CANN 版本需 ≥ 8.5.0。

1.开启大页

开启 RH2D 需要启用大页内存(--enable_huge_tlb true),需先在系统中完成大页内存配置。参考附录:使用大页内存

2. 服务端(openYuanrong Worker)开启 RH2D

在 run_yr_worker.sh 的 dscli start 命令中调整超时时间,添加 --remote_h2d_device_ids 、arena_per_tenant、enable_huge_tlb参数:

export NODE_TIMEOUT=300
export NODE_DEAD_TIMEOUT=600

dscli start -t 600 -w \
  ......
  --arena_per_tenant 1 \
  --remote_h2d_device_ids "0,1,2,3,4,5,6,7" \
  --enable_huge_tlb true

新增参数说明:

参数

示例值

说明

arena_per_tenant

1

每个 tenant 的 arena 数量,初始建议值为 1,在保证功能的前提下提供最快的启动速度

remote_h2d_device_ids

“0,1,2,3,4,5,6,7”

Worker 使用的 NPU 设备 ID 列表,逗号分隔。赋值即启用 RH2D,默认为空表示不启用。建议配置所有可用 NPU 以轮询建立传输连接,提高总传输带宽

enable_huge_tlb

true

开启共享内存大页内存,可有效提升内存的分配与拷贝性能。共享内存大于 21G 时需开启,并需提前配置系统大页

完整的 openYuanrong worker启动脚本 run_yr_worker.sh如下:

#!/bin/bash

export HOST_IP="<当前节点IP>"
export ETCD_IP="<ETCD_IP>"
export WORKER_PORT=18481
export ETCD_PORT=2379
export SHM_SIZE=512000
export NODE_TIMEOUT=300
export NODE_DEAD_TIMEOUT=600
export LIVENESS_PATH=/workspace/liveness

dscli start -t 600 -w \
  --worker_address ${HOST_IP}:${WORKER_PORT} \
  --etcd_address ${ETCD_IP}:${ETCD_PORT} \
  --shared_memory_size_mb ${SHM_SIZE} \
  --node_timeout_s ${NODE_TIMEOUT} \
  --node_dead_timeout_s ${NODE_DEAD_TIMEOUT} \
  --liveness_check_path ${LIVENESS_PATH} \
  --arena_per_tenant 1 \
  --remote_h2d_device_ids "0,1,2,3,4,5,6,7" \
  --enable_huge_tlb true

echo "Yuanrong service start finished!"

3. 客户端(vLLM)开启 RH2D

在 Prefill 和 Decode 节点的启动脚本中添加环境变量export DS_ENABLE_REMOTE_H2D=1, 启用客户端侧 RH2D 功能, 该环境变量需在启动 vLLM 服务之前设置,修改P节点/D节点run_dp_template.sh 模板。完整的 openYuanrong 相关环境变量配置如下:

# openYuanrong Datasystem

export DS_WORKER_ADDR="${local_ip}:18481"
export DS_ENABLE_REMOTE_H2D=1
unset GOOGLE_LOGTOSTDERR GOOGLE_ALSOLOGTOSTDERR

注意:启用RH2D功能最大会占用300M左右HBM显存用于建链传输。

常见问题

  1. etcd 连接失败

    确保 etcd 正在运行且可访问:

   etcdctl --endpoints "${ETCD_IP}:2379" endpoint health
  1. Worker 注册失败

    检查 Worker 地址是否正确配置:

   netstat -tlnp | grep 18481
  1. KV Cache 未找到

    验证 PYTHONHASHSEED 设置一致:

   echo $PYTHONHASHSEED

所有节点必须设置为 0。

  1. yr.datasystem 导入错误

    确保 openyuanrong-datasystem 已安装:

   pip install openyuanrong-datasystem
   python -c "from yr.datasystem.hetero_client import HeteroClient; print('OK')"
  1. 64 KB 页大小机器无法直接使用默认 openYuanrong 安装包

    检查页大小:

   getconf PAGE_SIZE

如果输出为 65536,请使用针对 64 KB 页大小单独编译的 openYuanrong 安装包。

  1. 引擎启动超时

    增加 VLLM_ENGINE_READY_TIMEOUT_S 的值:

   export VLLM_ENGINE_READY_TIMEOUT_S=3600
  1. 节点时间不一致

    8 机场景下,建议所有节点的系统时间保持一致,否则可能影响日志对齐、问题定位以及部分依赖时间戳的排障判断。

   date
   timedatectl
  1. transformers 版本过低

    升级 transformer 版本:

   pip install transformers==5.2.0 --no-deps --force-reinstall
   pip install huggingface_hub==1.5.0 --no-deps --force-reinstall
  1. 加了 rot.safetensors,报错 KeyError: 'rot'

    rot 的权重要放在其他目录,不能和 W8A8 的放一起。

  2. 部署上下文 200K,报超出模型最大支持长度

    将 --max-model-len 参数调低,官方宣称最大支持 200K 上下文,实测最大只能到 198K。

  3. PP并行策略报错

    模型不支持 PP 并行策略,改用 DP+TP 并行策略。

  4. yuanrong_backend报错’Failed to get xx keys.’ 、’[key not found]’等类似错误。

​ 非正常退出,导致数据有残留。建议每次启动前将 openYuanrong 的client日志、worker数据目录、etcd数据目录清除

​ client日志:~/.datasystem

​ worker数据目录:run_yr_worker.sh启动目录下的datasystem目录

    etcd数据目录:/tmp/etcd-data

建议通过优雅退出方式停止worker,执行dscli stop命令

dscli stop --worker_address ${HOST_IP}:${WORKER_PORT}

参考资料