从个人公众号分享过来,看好多教程都无法正确的运行起来,所以当笔记记录与分享。
一、环境配置
- 硬件拓扑
本次部署采用分布式架构,共涉及 3 台机器,。
-
Head 节点:xxx.xxx.xxx.14 ,配备 8 个 L20 显卡,每个显卡显存达 46GB 。
-
Worker 节点:xxx.xxx.xxx.18 和 xxx.xxx.xxx.19 ,同样各配备 8 个 L20 显卡,单个显卡显存 46GB 。这些 Worker 节点作为计算主力,分担推理任务。
总显存容量达到 24×46GB = 1,104GB 。
- 软件栈
| 组件 | 版本 |
|---|---|
| CUDA | 12.4 |
| vllm/vllm-openai | v0.8.0 |
| docker 和 nvidia-contaier-toolkit | / |
二、部署vllm
- 前置条件
安装cuda 与nvidia-contaier-toolkit
查看vllm 官方文档并且下载run_cluster.sh 脚本
每一台机器执行 export VLLM_HOST_IP=${local_ip}
第三个必须执行!!!
2. 节点启动
bash run_cluster.sh vllm/vllm-openai:v0.8.0 {head_ip} --{role} /wx/models-e VLLM_HOST_IP={local_ip} -e GLOO_SOCKET_IFNAME=bond0 -e NCCL_SOCKET_IFNAME=bond0
3. 参数说明
| head_ip | head 节点的ip 地址 |
|---|---|
| role | 只有 head 和worker |
| local_ip | 本地机器ip,需要和IFNAME 对应起来,不能IFNAME 选择eth0 ip 是eth1 |
| bond0 | 网络eth |
| /wx/models | 模型目录地址,该目录下存在deepseek-r1 目录,最佳方案是 找一台机器做nfs server |
| GLOO_SOCKET_IFNAME | 指定 GLOO 进行通信时所使用的网络接口 |
| NCCL_SOCKET_IFNAME | 用于指定 NCCL 进行通信时所使用的网络接口| |
- 查看状态
首先进行docker ps 查看容器是否启动成功?然后执行ray status 和查看模型是否挂载进来,如图所示就是OK,
注意事项:/root/hugginface 目录并不是默认存放模型地址,我修改了run_cluster.sh 脚本
三、运行deepseek 671B模型
- 进入head 容器中,执行命令
VLLM_USE_V1=1 VLLM_TEST_ENABLE_EP=1 vllm serve /root/huggingface/deepseek-r1 --trust-remote-code --port 8000 --tensor-parallel-size 8 --pipeline-parallel-size 3 --quantization fp8 --gpu-memory-utilization 0.95 --max-model-len 32768 --max-num-seqs 16 --served-model-name deepseek-r1
- 参数说明
参数说明
| /root/huggingface/deepseek-r1 | 模型目录 |
|---|---|
| --port 8000 | open api 端口 |
| --tensor-parallel-size 8 | 每个层的计算分布在8个GPU上 |
| --pipeline-parallel-size 3 | 将模型的多个层纵向切分到3个GPU节点上 |
VLLM其他部分参数
--model说明: 使用的Hugging Face模型名称或路径。
--tokenizer说明: 使用的Hugging Face分词器名称或路径。如果未指定,将使用模型名称或路径。
--tokenizer-revision说明: 使用的Hugging Face分词器的修订版本。
--tokenizer-mode说明: 分词器模式,支持选项:auto, slow, mistral, custom。默认: “auto”
--trust-remote-code说明: 信任来自Hugging Face的远程代码。
--load-format说明: 加载模型权重的格式,支持选项:auto, pt, safetensors, npcache, dummy, tensorizer, sharded_state, gguf, bitsandbytes, mistral, runai_streamer。默认: “auto”
--config-format说明: 加载模型配置的格式,支持选项:auto, hf, mistral。默认: “auto”
--dtype说明: 模型权重和激活的数值类型,支持选项:auto, half, float16, bfloat16, float, float32。默认: “auto”
--kv-cache-dtype说明: kv缓存存储的数据类型,支持选项:auto, fp8, fp8_e5m2, fp8_e4m3。默认: “auto”
--max-model-len说明: 模型上下文长度。如果未指定,将自动从模型配置中推导。
--distributed-executor-backend说明: 用于分布式模型工作者的后端,支持选项:ray, mp, uni, external_launcher。
--pipeline-parallel-size,说明: 管道阶段的数量。
--tensor-parallel-size, -tp说明: 张量并行副本的数量。
--block-size说明: 连续token块的大小,支持选项:8, 16, 32, 64, 128。--enable-prefix-caching,
--no-enable-prefix-caching说明: 启用或禁用自动前缀缓存。
--swap-space说明: 每个GPU的CPU交换空间大小(GiB)。默认: 4
--gpu-memory-utilization说明: 用于模型执行的GPU内存占用比例,范围从0到1。默认: 0.9
--max-num-seqs说明: 每次迭代的最大序列数量。
--quantization, -q说明: 用于量化权重的方法,支持多种选项。
--device说明: vLLM执行的设备类型,支持选项:auto, cuda, neuron, cpu, openvino, tpu, xpu, hpu。默认: “auto”
3. 进行api 测试
curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-r1", "messages": [ {"role": "user", "content": "用Python写一个快速排序算法"} ], "stream": true, "max_tokens": 2048 }'
四、性能测试
测试脚本来源是github vllm 项目benchmarks
- 测试脚本
python3 vllm/benchmarks/benchmark_serving.py --backend openai-chat --dataset-name random --model {modelPath} --served-model-name {modelName} --num-prompts 100 --max-concurrency {concurrency} --random-input {inLen} --random-output {outLen} --endpoint /v1/chat/completions --trust-remote-code
2. 下载数据集或者使用random 数据集进行测试
- 测试部分结果
- 测试结论
直接将数据交给部署的deepseek 告诉我测试结论。
a. 首字延迟与批次大小的关系
- 首字延迟随批次增大显著上升在输入/输出长度为256时,batch_size从8增至512,首字延迟从837ms激增至24秒。4096长度下,batch_size 512的首字延迟高达214秒。
- 原因推测大batch_size需要更多计算资源初始化生成过程,显存带宽或并行计算能力可能成为瓶颈。
b. 吞吐量(TPS)与批次规模的平衡
- Input/Output TPS先升后降
-
- 对于256长度,TPS在batch_size=64时达到峰值238(Input)和237(Output);4096长度下,TPS峰值在batch_size=128时(304.53 Input)。
- 优化区间:不同输入长度存在最佳batch_size(如256长度选64,4096选128),超过后TPS下降或增长停滞。
- 硬件资源限制极大batch_size可能导致显存耗尽或计算单元过载,限制性能提升。
3. 输入长度对性能的影响
- 长文本处理成本剧增
-
- 输入长度从256增至4096时,首字延迟增长超25倍(837ms→214秒),总时延增长超9倍(150s→1453s)。
- TPS衰减明显4096长度的Input TPS仅为256长度的35%(峰值304 vs 238)。
- 实际建议需权衡上下文长度需求与性能,超长文本(如4096)适合非实时场景。
4. 用户级TPS与并发能力
- 用户级TPS随批次增大而下降
-
- 256长度下,batch_size=8时用户级Input TPS为10.64,batch_size=512时降至0.53。
- 并发与效率的权衡:小batch_size适合高并发低延迟场景,大batch_size适合批量处理但牺牲单请求响应速度。
5. 总时延的批次效应
- 总时延呈U型曲线
-
- 在256长度下,batch_size=64时总时延最低(53.78s),过大(如128)或过小(如8)均导致时延增加。
- 资源竞争加剧极大batch_size可能导致显存碎片化或调度开销上升。
6. 硬件瓶颈推测
- 显存带宽限制首字延迟的陡增可能源于大batch_size的显存加载压力。
- 计算单元利用率小batch_size可能无法充分利用GPU并行计算能力,大batch_size则受限于显存容量。
五、调参优化
调解vllm 参数进行测试,其他的调试也不会!!
- 找到问题
- 查看测试数据和测试结论,第一个是首token 生成延迟。第一个想到是增大block size
- 查看vllm 日志,kvcache 最高居然达到80%,必须增大!!
INFO 04-28 15:03:11 [metrics.py:481] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 193.6 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 41 reqs, GPU KV cache usage: 79.5%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:16 [metrics.py:481] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 193.7 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 41 reqs, GPU KV cache usage: 79.7%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:21 [metrics.py:481] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 193.0 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 41 reqs, GPU KV cache usage: 79.8%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:26 [metrics.py:481] Avg prompt throughput: 723.0 tokens/s, Avg generation throughput: 140.8 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 40 reqs, GPU KV cache usage: 79.6%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:32 [metrics.py:481] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 181.0 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 40 reqs, GPU KV cache usage: 79.8%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:37 [metrics.py:481] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 187.7 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 40 reqs, GPU KV cache usage: 80.4%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:42 [metrics.py:481] Avg prompt throughput: 1667.8 tokens/s, Avg generation throughput: 76.6 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 38 reqs, GPU KV cache usage: 79.8%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:47 [metrics.py:481] Avg prompt throughput: 843.3 tokens/s, Avg generation throughput: 134.5 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 37 reqs, GPU KV cache usage: 80.0%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:52 [metrics.py:481] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 148.9 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 36 reqs, GPU KV cache usage: 80.1%, CPU KV cache usage: 0.1%.
INFO 04-28 15:03:57 [metrics.py:481] Avg prompt throughput: 1581.6 tokens/s, Avg generation throughput: 123.4 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 35 reqs, GPU KV cache usage: 79.9%, CPU KV cache usage: 0.1%.
INFO 04-28 15:04:02 [metrics.py:481] Avg prompt throughput: 837.3 tokens/s, Avg generation throughput: 130.9 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 34 reqs, GPU KV cache usage: 79.7%, CPU KV cache usage: 0.1%.
INFO 04-28 15:04:07 [metrics.py:481] Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 187.8 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 34 reqs, GPU KV cache usage: 79.8%, CPU KV cache usage: 0.1%.
INFO 04-28 15:04:12 [metrics.py:481] Avg prompt throughput: 1674.5 tokens/s, Avg generation throughput: 73.6 tokens/s, Running: 48 reqs, Swapped: 0 reqs, Pending: 32 reqs, GPU KV cache usage: 79.2%, CPU KV cache usage: 0.1%.
-
并发上不去,想到优先处理短链接,增大批处理数量
-
使用nvtop 监控gpu ,判断是否存在pcie 问题或者nvlink nvp2p 等没启用或者存在问题。
-
是不是NCCL 通信存在问题
- 设置优化参数
| 参数 | 当前配置值 | 开启后测试结果 | 优化建议 |
|---|---|---|---|
--enable-chunked-prefill | True | ✔️ 分块处理降低内存峰值,4096长度时吞吐量提升23% | 长文本场景必选参数 |
--block-size=64 | 64 | ✔️ 4096长度处理效率提升18%已验证 | 超过8k上下文推荐128 |
--quantization=awq | AWQ | ✔️ 显存降低45%实测有效,但速度提升需搭配Marlin内核 | 需使用LLM-Compressor量化工具 |
--max-num-batched-tokens=8192 | 8192 | ✔️ 与动态批处理配合吞吐量提升32% | 短文本场景可降为4096 |
--gpu-memory-utilization=0.93 | 0.93 | ⚠️ :L20的安全阈值为0.92,超过0.92可能触发OOM | 建议调整为0.9,并配合swap-space=16GiB |
--enable-cuda-graph=True | True | ⚠️:没效果 | 需禁用动态shape请求 |
--swap-space=16 | 16GiB | ✔️ 支持32k上下文处理,但会增加延迟 | 显存不足时必选参数 |
3.通信优化参数(好像没啥效果!!)
- NCCL_NSOCKS_PERTHREAD=8:每个线程使用 8 个套接字,增加数据传输通道,提升通信带宽。
- NCCL_SOCKET_NTHREADS=4:设置每个套接字的线程数为 4 ,优化线程资源分配,提高通信性能。
- 量化没有什么是量化解决不了的,下面是我的硬件配置ai 给出的估算。那就直接选择AWQ ,开搞!!
| 量化方式 | 吞吐提升 | 精度损失 |
| FP8 | 38% | <0.5% |
| AWQ | 52% | 0.8% |
| GPTQ | 45% | 1.2% |
六、优化后的部分测试结果
测试4096 输长度
| 指标 | 非量化配置 | AWQ量化配置 | 提升幅度 |
|---|---|---|---|
| 首字延迟 | 204,416ms | 78,200ms | 61.7%↓ |
| Input TPS | 304.53 | 892.7 | 193%↑ |
| Output TPS | 105.33 | 342.1 | 225%↑ |
| 总时延 | 1,345s | 402s | 70.1%↓ |
| 显存占用 | 38.2GB | 21.7GB | 43.2%↓ |