前言
之前接手了一个 8 卡 910B 的华为服务器集群,性能看上去还是可以的,但是平时几乎没啥人用(可能是华为卡真的很难用吧),闲来无事,拉了几台机器来玩玩(反正我使用 kubernetes 部署的,想要让出来直接 ),主要是用于自己部署一些开源大模型。kubectl delete 就是了
本文主要就是分享一下部署过程中我所使用的脚本而已,并不会深入讲解具体的配置细节,因为我也不是做这方面的,纯粹是好玩(
背景
首先介绍一下每台服务器上的配置:
$ npu-smi info
+------------------------------------------------------------------------------------------------+
| npu-smi 25.3.rc1 Version: 25.3.rc1 |
+---------------------------+---------------+----------------------------------------------------+
| NPU Name | Health | Power(W) Temp(C) Hugepages-Usage(page)|
| Chip | Bus-Id | AICore(%) Memory-Usage(MB) HBM-Usage(MB) |
+===========================+===============+====================================================+
| 0 910B3 | OK | 96.7 32 0 / 0 |
| 0 | 0000:C1:00.0 | 0 0 / 0 60056/ 65536 |
+===========================+===============+====================================================+
| 1 910B3 | OK | 93.7 30 0 / 0 |
| 0 | 0000:C2:00.0 | 0 0 / 0 60050/ 65536 |
+===========================+===============+====================================================+
| 2 910B3 | OK | 92.7 30 0 / 0 |
| 0 | 0000:81:00.0 | 0 0 / 0 60050/ 65536 |
+===========================+===============+====================================================+
| 3 910B3 | OK | 89.0 31 0 / 0 |
| 0 | 0000:82:00.0 | 0 0 / 0 60051/ 65536 |
+===========================+===============+====================================================+
| 4 910B3 | OK | 88.7 36 0 / 0 |
| 0 | 0000:01:00.0 | 0 0 / 0 60050/ 65536 |
+===========================+===============+====================================================+
| 5 910B3 | OK | 90.1 35 0 / 0 |
| 0 | 0000:02:00.0 | 0 0 / 0 60050/ 65536 |
+===========================+===============+====================================================+
| 6 910B3 | OK | 94.4 34 0 / 0 |
| 0 | 0000:41:00.0 | 0 0 / 0 60051/ 65536 |
+===========================+===============+====================================================+
| 7 910B3 | OK | 86.4 33 0 / 0 |
| 0 | 0000:42:00.0 | 0 0 / 0 60051/ 65536 |
+===========================+===============+====================================================+
+---------------------------+---------------+----------------------------------------------------+
| NPU Chip | Process id | Process name | Process memory(MB) |
+===========================+===============+====================================================+
| 0 0 | 3329455 | VLLMWorker_TP | 56683 |
+===========================+===============+====================================================+
| 1 0 | 3329456 | VLLMWorker_TP | 56683 |
+===========================+===============+====================================================+
| 2 0 | 3329457 | VLLMWorker_TP | 56683 |
+===========================+===============+====================================================+
| 3 0 | 3329458 | VLLMWorker_TP | 56683 |
+===========================+===============+====================================================+
| 4 0 | 3329459 | VLLMWorker_TP | 56683 |
+===========================+===============+====================================================+
| 5 0 | 3329460 | VLLMWorker_TP | 56683 |
+===========================+===============+====================================================+
| 6 0 | 3329461 | VLLMWorker_TP | 56683 |
+===========================+===============+====================================================+
| 7 0 | 3329465 | VLLMWorker_TP | 56683 |
+===========================+===============+====================================================+每台机器上都配备了 8 张 910B3 加速卡,每张卡的显存大小是 64GB,不同机器之间采用 25GbE 高速以太网互联,每节点配备 4 × 25GbE 端口,单节点网络带宽合计 100Gbps。
不同机器的共用存储位于 /user-storage,相当于一个高性能的 nfs 实现,具体技术细节我就不清楚了。
部署
下载
在部署模型之前,首先应该做的当然是下载模型,这里我采用 modelscope 来下载模型,比如下载 glm-5.1-w8a8 模型:
modelscope download \
--model Eco-Tech/GLM-5.1-w8a8 \
--local_dir /user-storage/models/GLM-5.1-w8a8 存放在公共存储,这样多节点多实例部署的时候就不用每台机器都下载一遍了。
配置
推理框架我所使用的是 vllm-ascend,主要是看在这个推理框架的文档比较丰富,遇到疑难杂症的可能性应该会比较小。
为了减少对本机环境的干扰(毕竟还是要最终给别人用的),我使用官方推荐的 Docker 镜像 quay.io/ascend/vllm-ascend:v0.18.0rc1 来进行部署。
因为国内访问镜像仓库速率太慢或者干脆直接被墙了,所以我采用 m.daocloud.io 镜像源来拉取镜像:
docker pull m.daocloud.io/quay.io/ascend/vllm-ascend:v0.18.0rc1然后把 910B 设备和共用存储挂载到容器中并运行:
docker run --rm \
--name vllm-ascend \
--net host \
--shm-size 16g \
--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/davinci_manager \
--device /dev/devmm_svm \
--device /dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /user-storage:/user-storage \
-v /user-storage/models/.cache:/root/.cache \
-it m.daocloud.io/quay.io/ascend/vllm-ascend:v0.18.0rc1 bash进入到容器后,首先第一步就是必须执行以下命令:
pip install transformers==5.2.0先把 transformers 库更新到某个版本,否则之后运行什么模型都会报错。
需要注意的是,执行这条指令可能也会报错,但是不用管,直接 clear 眼不见心为快,之后的模型也能跑,就很神奇。
glm-5.1-w8a8
最开始我想跑的是 glm-5.1,当时最强的开源编程模型,这个模型还是挺大的,总模型参数量达 754B,如果不量化的话至少要用到 4 台机器,但是在我试验了很多次后,不知道为什么这个模型的 tps 低的离谱,只有个位数,遂放弃转而跑 w8a8 的量化版本。
这个量化版本的 glm-5.1 只需要 2 台机器就行了,其执行的指令分别为:
# node 1
export HCCL_IF_IP=172.20.1.2
export HCCL_SOCKET_IFNAME=vlan0.12,vlan1.12
export GLOO_SOCKET_IFNAME=vlan0.12
export TP_SOCKET_IFNAME=vlan0.12
export RANK_TABLE_FILE=/user-storage/models/hccl_16p.json
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=1
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=200
export HCCL_INTRA_PCIE_ENABLE=1
export HCCL_INTRA_ROCE_ENABLE=0
export HCCL_CONNECT_TIMEOUT=300
export TASK_QUEUE_ENABLE=1
export VLLM_ASCEND_ENABLE_MLAPO=1
export VLLM_ASCEND_BALANCE_SCHEDULING=1
export VLLM_ASCEND_ENABLE_FUSED_MC2=1
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1
vllm serve /user-storage/models/GLM-5.1-w8a8 \
--host 0.0.0.0 \
--port 8000 \
--tensor-parallel-size 16 \
--enable-expert-parallel \
--dtype bfloat16 \
--max-model-len 32768 \
--gpu-memory-utilization 0.96 \
--max-num-seqs 8 \
--max-num-batched-tokens 1024 \
--trust-remote-code \
--quantization ascend \
--enable-chunked-prefill \
--enable-prefix-caching \
--nnodes 2 \
--node-rank 0 \
--master-addr 172.20.1.2 \
--master-port 29500 \
--async-scheduling \
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
--additional-config '{"fuse_muls_add": true, "multistream_overlap_shared_expert": true, "enable_shared_expert_dp": true}' \
--speculative-config '{"num_speculative_tokens": 1, "method": "deepseek_mtp"}' \
--chat-template-content-format string \
--served-model-name glm-5.1 \
--reasoning-parser glm45 \
--enable-auto-tool-choice \
--tool-call-parser glm47 2>&1 | tee ./vllm-ascend-$(date +%Y%m%d-%H%M%S).log# node 2
export HCCL_IF_IP=172.20.1.5
export HCCL_SOCKET_IFNAME=vlan0.12,vlan1.12
export GLOO_SOCKET_IFNAME=vlan0.12
export TP_SOCKET_IFNAME=vlan0.12
export RANK_TABLE_FILE=/user-storage/models/hccl_16p.json
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=1
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=200
export HCCL_INTRA_PCIE_ENABLE=1
export HCCL_INTRA_ROCE_ENABLE=0
export HCCL_CONNECT_TIMEOUT=300
export TASK_QUEUE_ENABLE=1
export VLLM_ASCEND_ENABLE_MLAPO=1
export VLLM_ASCEND_BALANCE_SCHEDULING=1
export VLLM_ASCEND_ENABLE_FUSED_MC2=1
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1
vllm serve /user-storage/models/GLM-5.1-w8a8 \
--host 0.0.0.0 \
--port 8000 \
--tensor-parallel-size 16 \
--enable-expert-parallel \
--dtype bfloat16 \
--max-model-len 32768 \
--gpu-memory-utilization 0.96 \
--max-num-seqs 8 \
--max-num-batched-tokens 1024 \
--trust-remote-code \
--quantization ascend \
--enable-chunked-prefill \
--enable-prefix-caching \
--nnodes 2 \
--node-rank 1 \
--headless \
--master-addr 172.20.1.2 \
--master-port 29500 \
--async-scheduling \
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
--additional-config '{"fuse_muls_add": true, "multistream_overlap_shared_expert": true, "enable_shared_expert_dp": true}' \
--speculative-config '{"num_speculative_tokens": 1, "method": "deepseek_mtp"}' \
--chat-template-content-format string \
--served-model-name glm-5.1 \
--reasoning-parser glm45 \
--enable-auto-tool-choice \
--tool-call-parser glm47 2>&1 | tee ./vllm-ascend-$(date +%Y%m%d-%H%M%S).log其中 /user-storage/models/hccl_16.json 的内容如下:
{
"version": "1.0",
"server_count": "2",
"server_list": [
{
"server_id": "172.20.2.2",
"device": [
{"device_id": "0", "device_ip": "172.20.0.2", "rank_id": "0"},
{"device_id": "1", "device_ip": "172.20.0.3", "rank_id": "1"},
{"device_id": "2", "device_ip": "172.20.0.4", "rank_id": "2"},
{"device_id": "3", "device_ip": "172.20.0.5", "rank_id": "3"},
{"device_id": "4", "device_ip": "172.20.0.6", "rank_id": "4"},
{"device_id": "5", "device_ip": "172.20.0.7", "rank_id": "5"},
{"device_id": "6", "device_ip": "172.20.0.8", "rank_id": "6"},
{"device_id": "7", "device_ip": "172.20.0.9", "rank_id": "7"}
],
"host_nic_ip": "reserve"
},
{
"server_id": "172.20.2.3",
"device": [
{"device_id": "0", "device_ip": "172.20.0.10", "rank_id": "8"},
{"device_id": "1", "device_ip": "172.20.0.11", "rank_id": "9"},
{"device_id": "2", "device_ip": "172.20.0.12", "rank_id": "10"},
{"device_id": "3", "device_ip": "172.20.0.13", "rank_id": "11"},
{"device_id": "4", "device_ip": "172.20.0.14", "rank_id": "12"},
{"device_id": "5", "device_ip": "172.20.0.15", "rank_id": "13"},
{"device_id": "6", "device_ip": "172.20.0.16", "rank_id": "14"},
{"device_id": "7", "device_ip": "172.20.0.17", "rank_id": "15"}
],
"host_nic_ip": "reserve"
}
],
"status": "completed"
}如果你需要自己尝试跑的话,主要需要修改的点就是所有 910B 设备的 IP,以及各个环境变量里的 IP 和设备号了,这我不是很懂,所以不好详细说明。
这样跑起来模型能跑个单请求 20tps 的速率,已经是一个很不错的数字了,但是最大最大的问题就是,这个 vllm-ascend 好像不太支持 kv cache offload,一旦我打开了,这个模型就跑不起来,但是如果我不开的话,这个模型最多只能跑 32k 的上下文,因为显存不够!
我也试过各种各样的办法,问过各种 AI 有什么解决办法,但是无论什么办法,在保持至少 20tps 的速率下,都不能做到有效降低显存提高上下文长度,这就很难受了,因为这就意味着,这个模型的上下文太短,接入不了主流的 claude code 等 AI agent 工具,只能拿来进行简单的对话。
qwen2.5-coder-32b-instruct
不过接着我发现,与其指望跑一个编程用的大模型,为什么不来跑一个用于 FIM(Fill In the Middle)的简单的补全用的模型,这样至少还有点用。
因此,接下来我就尝试跑 qwen2.5-coder-32b-instruct 这个参数显著降低的补全用的模型,只需要 1 机就能跑起来:
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export OMP_NUM_THREADS=1
export TASK_QUEUE_ENABLE=1
export HCCL_CONNECT_TIMEOUT=300
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=200
vllm serve /user-storage/models/Qwen2.5-Coder-32B-Instruct \
--host 0.0.0.0 \
--port 8000 \
--tensor-parallel-size 8 \
--dtype bfloat16 \
--max-model-len 32768 \
--gpu-memory-utilization 0.90 \
--max-num-seqs 16 \
--max-num-batched-tokens 4096 \
--trust-remote-code \
--enable-chunked-prefill \
--enable-prefix-caching \
--served-model-name qwen2.5-coder-32b \
--async-scheduling \
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
2>&1 | tee ./vllm-qwen-$(date +%Y%m%d-%H%M%S).log这下模型的速率能跑到单请求 60tps,勉强够用。
总结
这篇文章主要就是分享一下我在用华为 910B 卡跑模型时的脚本,因为我在跑模型的时候总是能遇到各种环境上莫名其妙的问题,和 AI 大战 800 回合才解决,现在终于能跑起来了就分享给各位,省的你们也和 AI 大战 800 回合才能解决。