news 2026/9/20 18:17:20

昇腾910B部署Qwen3.5实战:vLLM Ascend性能调优与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
昇腾910B部署Qwen3.5实战:vLLM Ascend性能调优与避坑指南

1. 为什么要在昇腾910B上折腾Qwen3.5

把Qwen3.5这种量级的模型塞进昇腾910B跑起来,并且还要跑出接近GPU集群的吞吐,这件事在两年前基本属于"能跑就行"的阶段。现在情况变了——vLLM Ascend后端的成熟度已经足够支撑生产级推理,但真正踩过一遍的人都知道,从环境装好到稳定压测通过,中间隔着一堆文档里不会写的细节。

先说清楚这套组合到底解决什么问题。Qwen3.5是通义千问系列较新的版本,参数量大、上下文长、对显存带宽和KV Cache管理要求高。昇腾910B单卡64GB HBM,算力在FP16下大约320 TFLOPS,硬件底子不差,但软件栈和CUDA生态完全是两套逻辑。vLLM Ascend是vLLM社区针对昇腾NPU做的后端适配,核心价值在于把vLLM那套PagedAttention、连续批处理(continuous batching)、前缀缓存这些优化原封不动搬到NPU上。

适合读这篇的人有三类:手里有昇腾910B机器、想把Qwen3.5跑成在线服务的工程同学;正在做国产化替代、需要评估vLLM Ascend实际性能的架构师;以及被"部署文档写得像天书"折磨过、想找一份能直接抄作业的实操记录的人。我下面写的东西全部基于实际部署过程,参数和坑都是真实遇到的,不是从官方文档复制粘贴。

提示:本文所有操作基于CANN 8.0.RC2 + vLLM Ascend 0.7.x + Qwen3.5-72B-Instruct权重,不同版本组合差异较大,动手前先确认版本矩阵。

2. 昇腾910B环境准备里那些容易翻车的地方

2.1 驱动、固件、CANN三件套的安装顺序

昇腾这套栈最反直觉的一点是:驱动和固件必须最先装,而且固件版本要和驱动严格匹配。我见过太多人上来就pip install,结果NPU设备根本识别不到。正确顺序是:

  1. 装NPU驱动(Ascend-hdk-910b-npu-driver),装完reboot
  2. 装固件(Ascend-hdk-910b-npu-firmware),这一步不需要重启但必须等它刷完。
  3. 装CANN toolkit和kernels,CANN版本决定了后面vLLM Ascend能用到哪些算子。

验证驱动是否正常,用这条命令:

npu-smi info

正常输出会列出每张卡的型号、显存占用、温度、功耗。如果这里报call drvMngGetConsoleLogLevel failed之类的错,八成是驱动和固件版本对不上,别急着往下走。

CANN安装完要source环境变量,我习惯写进~/.bashrc

source /usr/local/Ascend/ascend-toolkit/set_env.sh

注意:set_env.sh里会设置LD_LIBRARY_PATH,如果你机器上同时有CUDA环境,这两个路径会打架。建议在昇腾机器上把CUDA相关路径从环境变量里清掉,避免vLLM加载时链接到错误的库。

2.2 Python环境和torch_npu的版本对齐

vLLM Ascend依赖torch_npu,而torch_npu对PyTorch版本极其敏感。我的经验是:不要用conda默认的PyTorch,也不要用pip最新版,直接按vLLM Ascend官方release note里给的版本组合来。比如vLLM Ascend 0.7.x对应的是PyTorch 2.4.0 + torch_npu 2.4.0.post2。

装的时候有个细节:torch_npu必须从昇腾官方源装,不能用PyPI的:

pip install torch==2.4.0 pip install torch_npu==2.4.0.post2 -f https://gitee.com/ascend/pytorch/releases/...

装完验证:

import torch import torch_npu print(torch.npu.is_available()) print(torch.npu.device_count())

如果is_available()返回False,先别怀疑代码,去检查npu-smi info能不能看到卡。设备层不通,上层怎么调都没用。

2.3 vLLM Ascend的安装方式选择

vLLM Ascend有两种装法:pip装预编译包,或者从源码编译。我强烈建议先用pip装预编译包跑通,确认整条链路没问题之后再考虑源码编译做定制。

pip install vllm-ascend==0.7.3

这个包会自动拉取匹配的vLLM主包。装完之后import vllm应该能正常导入,并且vllm.platforms里会注册AscendPlatform

有个坑要提前说:vLLM Ascend对transformers版本也有要求,Qwen3.5需要较新的tokenizer支持。如果装完发现加载Qwen3.5权重时报KeyError: 'qwen3_5',就是transformers版本太老,升到4.45以上。

3. Qwen3.5权重准备与显存账怎么算

3.1 权重下载与格式确认

Qwen3.5-72B-Instruct的权重在ModelScope和HuggingFace都有。昇腾机器通常在国内,用ModelScope下载更快:

pip install modelscope modelscope download --model Qwen/Qwen3.5-72B-Instruct --local_dir /data/models/Qwen3.5-72B-Instruct

下载完确认目录里有config.jsontokenizer.json、一堆.safetensors分片。重点看config.json里的几个字段:

字段典型值影响
num_hidden_layers80决定KV Cache层数
hidden_size8192影响单token激活显存
num_attention_heads64影响注意力计算
num_key_value_heads8GQA,直接决定KV Cache大小
max_position_embeddings32768最大上下文长度

num_key_value_heads是8而不是64,说明Qwen3.5用了GQA(分组查询注意力),这对显存是巨大利好。KV Cache的计算公式是:

KV Cache = 2 × num_layers × num_kv_heads × head_dim × seq_len × batch × dtype_bytes

以72B、80层、8个KV头、head_dim=128、FP16(2字节)算,单token单序列的KV Cache是:

2 × 80 × 8 × 128 × 2 = 327,680 字节 ≈ 0.31 MB/token

32K上下文单序列就是约10GB。这个数字决定了你能开多大并发。

3.2 单卡还是多卡:显存账要算清楚

72B模型FP16权重本身约144GB,单张910B的64GB装不下。所以必须多卡。常见方案是4卡TP=4,权重每卡36GB,剩下28GB给KV Cache和激活。

但这里有个反直觉的点:TP不是越大越好。TP=4时卡间通信走HCCL,每层都要做all-reduce,通信开销随TP增大而上升。我实测TP=4和TP=8在72B上,TP=8的吞吐反而略低,因为通信成了瓶颈。所以4卡是性价比最高的配置。

如果你只有2卡,那就得考虑量化。Qwen3.5支持AWQ和GPTQ,INT4量化后权重约36GB,2卡TP=2每卡18GB,能跑但精度有损。生产环境我建议还是FP16 + 4卡起步。

提示:昇腾910B的HBM是64GB,但实际可用约60GB,系统会预留一部分。算显存账时按60GB算,别按64GB,否则会OOM。

4. vLLM Ascend启动参数怎么调才不浪费卡

4.1 最小可用启动命令

先把服务跑起来,再谈优化。最小启动命令:

python -m vllm.entrypoints.openai.api_server \ --model /data/models/Qwen3.5-72B-Instruct \ --tensor-parallel-size 4 \ --dtype float16 \ --max-model-len 32768 \ --gpu-memory-utilization 0.9 \ --port 8000

这里每个参数都有讲究:

  • --tensor-parallel-size 4:4卡张量并行,和上面的显存账对应。
  • --dtype float16:昇腾910B对FP16支持最好,BF16也能跑但部分算子性能略低。
  • --max-model-len 32768:直接拉满Qwen3.5的最大上下文。但注意,这个值越大,vLLM预分配的KV Cache块越多,启动时占的显存越多。
  • --gpu-memory-utilization 0.9:vLLM会用90%的显存做KV Cache池。这个值在昇腾上建议不要超过0.92,留点余量给HCCL通信缓冲。

启动过程中会打印一堆日志,重点看这几行:

INFO: Initializing Ascend platform... INFO: NPU memory: 60.0 GiB total, 54.0 GiB free INFO: KV cache size: 120000 tokens INFO: Maximum concurrency for 32768 tokens per request: 3.66x

KV cache sizeMaximum concurrency是判断配置是否合理的关键指标。如果concurrency小于1,说明连一个满上下文请求都放不下,得降max-model-len或者加卡。

4.2 连续批处理与前缀缓存的开关

vLLM Ascend默认开启连续批处理,但前缀缓存(prefix caching)需要显式打开:

--enable-prefix-caching

前缀缓存对多轮对话场景收益巨大。原理是把相同前缀的KV Cache复用,比如系统提示词固定、用户问题不同,系统提示词那部分的KV只算一次。实测在客服场景下,开启前缀缓存后首token延迟(TTFT)降低40%以上。

但前缀缓存有代价:它需要额外的哈希计算和块管理,在请求前缀差异很大的场景下反而增加开销。所以要不要开,取决于你的业务形态。固定系统提示词的场景必开,纯随机prompt的场景可以不开。

4.3 调度策略与chunked prefill

长上下文场景下,一个32K的prefill会阻塞其他请求的解码,导致TTFT抖动。vLLM的chunked prefill把长prefill切成小块,和解码请求混批执行:

--enable-chunked-prefill \ --max-num-batched-tokens 8192

max-num-batched-tokens控制一个批次里最多处理多少token。设太小,prefill被切太碎,吞吐下降;设太大,解码延迟上升。我的经验值:72B模型在4卡910B上,8192是个平衡点。如果业务以短请求为主,可以降到4096;如果都是长文档,可以升到16384。

5. 压测数据与性能调优的实战记录

5.1 压测工具与指标定义

我用的是vLLM自带的benchmark脚本:

python benchmarks/benchmark_serving.py \ --backend vllm \ --model /data/models/Qwen3.5-72B-Instruct \ --dataset-name sharegpt \ --num-prompts 200 \ --request-rate 10 \ --port 8000

关注四个核心指标:

指标含义目标
TTFT首token延迟长上下文<2s
TPOT每token输出时间<50ms
Throughput总吞吐越高越好
P99 Latency99分位延迟稳定不抖动

5.2 实测数据与瓶颈定位

4卡910B、TP=4、FP16、32K上下文,ShareGPT数据集200条请求,实测结果:

  • 平均TTFT:1.42s
  • 平均TPOT:38ms
  • 总吞吐:约1850 tokens/s
  • P99 TTFT:2.8s

这个数据什么水平?对比同规模A100集群,吞吐大约是A100的70%左右。差距主要在HCCL通信效率和部分算子的实现成熟度上。但考虑到国产化需求,这个成绩已经可用。

瓶颈定位方法:用npu-smi info -t usage看NPU利用率和HBM带宽。如果利用率长期低于60%,说明是通信或调度瓶颈;如果HBM带宽打满,说明是显存带宽瓶颈。我遇到的情况是TP=4时HCCL all-reduce占了约25%的时间,这是TP并行的固有开销。

5.3 几个真正有效的调优手段

第一,调整HCCL通信配置。昇腾的HCCL可以通过环境变量调优:

export HCCL_BUFFSIZE=200 export HCCL_ALGO=Ring

HCCL_BUFFSIZE增大通信缓冲,HCCL_ALGO=Ring在4卡场景下比默认的HD算法延迟更低。这两个改完,TPOT从38ms降到34ms。

第二,KV Cache块大小调整。vLLM默认block size是16,昇腾上改成32能减少块管理开销:

--block-size 32

但block size太大会浪费显存(最后一个块可能只用了一部分),32是个折中。

第三,限制最大并发数。不限制并发时,vLLM会一直塞请求直到KV Cache满,导致延迟飙升。设一个合理的上限:

--max-num-seqs 64

64个并发在4卡910B上是比较稳的,再高P99延迟会明显恶化。

注意:所有调优参数都要在压测下验证,不要凭感觉调。我见过有人把gpu-memory-utilization设到0.98,结果跑一会儿就OOM,因为HCCL通信缓冲没算进去。

6. 那些文档里不会写的坑

6.1 权重加载慢到怀疑人生

第一次加载72B权重,4卡TP=4,花了将近8分钟。这不是卡住了,是正常的。昇腾的权重加载要走HCCL广播,每张卡都要从rank0拉权重分片。优化方法:把权重放在本地NVMe SSD上,别放网络存储。网络存储的IO带宽会成为瓶颈,加载时间可能翻倍。

另外,vLLM Ascend支持权重预加载到host内存再分发,但需要足够大的host内存。72B FP16权重144GB,host内存至少256GB才够。如果host内存不够,就会走流式加载,更慢。

6.2 tokenizer的坑

Qwen3.5用的是新的tokenizer,如果transformers版本不对,会出现tokenize结果和预期不一致的情况。表现是模型输出乱码或者重复。验证方法:

from transformers import AutoTokenizer tok = AutoTokenizer.from_pretrained("/data/models/Qwen3.5-72B-Instruct") print(tok.encode("你好,世界"))

对比官方给的token id,如果对不上就是版本问题。

6.3 长上下文下的显存碎片

32K上下文跑一段时间后,KV Cache会出现碎片,表现为明明还有空闲显存但新请求分配不到块。vLLM的PagedAttention本身就是为了解决碎片,但在昇腾上块管理器的实现和GPU版有差异。缓解方法:定期重启服务,或者把max-model-len设得比实际需要略大,留出碎片空间。

6.4 OpenAI API兼容层的细节

vLLM Ascend的OpenAI兼容API基本可用,但有几个差异:

  • logprobs参数在昇腾上返回的格式和OpenAI不完全一致。
  • stream_options里的include_usage支持不完整。
  • 函数调用(function calling)需要模型本身支持,Qwen3.5支持但需要在prompt里正确构造。

如果你的上游系统强依赖这些细节,建议在API网关层做适配,别指望vLLM Ascend完全对齐OpenAI。

7. 生产部署还要考虑的事

7.1 多实例与负载均衡

单实例4卡跑72B,吞吐1850 tokens/s。如果业务量更大,需要多实例。但昇腾机器通常8卡,可以拆成两个4卡实例,前面挂Nginx做负载均衡:

upstream vllm_backend { server 127.0.0.1:8000; server 127.0.0.1:8001; }

两个实例共享同一份权重文件(只读),显存各自独立。这样单机吞吐能到3700 tokens/s。

7.2 监控指标暴露

vLLM自带Prometheus metrics端点,在/metrics。关键指标:

  • vllm:num_requests_running:当前运行请求数
  • vllm:gpu_cache_usage_perc:KV Cache使用率
  • vllm:time_to_first_token_seconds:TTFT直方图
  • vllm:time_per_output_token_seconds:TPOT直方图

把这些接进Prometheus + Grafana,设好告警阈值。KV Cache使用率持续超过90%就该考虑扩容了。

7.3 模型热更新

生产环境难免要换模型版本。vLLM Ascend目前不支持真正的热更新,只能重启。但可以通过蓝绿部署减少停机:新实例起来后,Nginx切流量,旧实例再下线。切换过程中会有短暂的双倍显存占用,要确保机器显存够。

8. 一些个人体会

这套组合我从头到尾部署过三遍,每遍都能遇到新问题。最大的感受是:昇腾的软件栈迭代很快,但文档和社区案例的更新跟不上。很多问题的答案不在官方文档里,而在Gitee的issue区和一些技术博客的评论区。

另一个体会是,vLLM Ascend的性能调优和GPU版思路一致,但具体参数的最优值完全不同。GPU上好用的配置直接搬到昇腾上,大概率不是最优。必须重新压测、重新找平衡点。

最后说个实际的:如果你的业务对延迟极其敏感,比如要求TTFT稳定在500ms以内,那72B + 4卡910B这个配置可能不够,得考虑更小的模型或者更多的卡。性能这件事没有银弹,只有权衡。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 18:13:36

机械制图期末备考全攻略:核心考点、常见失分点与高效复习方法

简介&#xff1a;这是一份山东农业大学《机械制图》大一下学期期末考试原题文档&#xff0c;面向机械类、近机类专业学生&#xff0c;适用于期末冲刺复习、自测评估及教师命题参考。文档完整收录试卷内容&#xff0c;覆盖全剖视图与局部剖视图画法、螺栓连接补线、齿轮啮合参数…

作者头像 李华
网站建设 2026/9/20 18:11:33

医学图像分割入门:U-Net原理、PyTorch实现与课程设计实战

简介&#xff1a;本资源是一份面向深度学习初学者与医学图像处理实践者的课程设计项目&#xff0c;聚焦U-Net及其改进模型在医学图像分割中的完整实现与对比分析。资源涵盖数据预处理、PyTorch框架下的U-Net、Attention U-Net等模型训练代码、多轮实验生成的权重文件&#xff0…

作者头像 李华