报告时间:2026-08-29

部署规模:4台 × 8卡 = 32卡昇腾910B4集群

目录

一、项目概述

部署目标

二、硬件环境

三、软件环境

四、集群部署架构

五、服务详细配置

5.1 vLLM 实例配置

5.2 16后端实例分布

六、OpenResty 反向代理配置

6.1 核心功能

6.2 亲和力路由设计

6.3 完整 nginx.conf(16后端)

七、集群验证结果

7.1 16后端健康检查

7.2 负载分布验证

7.3 参数与Token验证

八、集群扩展部署过程

8.1 部署机器69(总控节点)

8.2 部署机器68

8.3 部署机器67

8.4 部署机器66

8.5 扩展要点

九、运维管理

9.1 查看服务状态

9.2 查看日志

9.3 重启与停止

十、调用示例

10.1 外网调用(推荐,含X-Session-ID)

10.2 内网调用(调试)

十一、问题记录与修复

十二、Benchmark性能测试

12.1 测试环境

12.2 并发负载(单实例MTP=4)

12.3 顺序吞吐(MTP=4)

12.4 性能结论

十三、MTP=4 vs MTP=5对比

13.1 MTP投机解码原理

13.2 实测对比

13.3 结论与建议

十四、服务系统化(systemd)

14.1 设计目标

14.2 systemd服务单元

14.3 常用运维命令

14.4 常见问题:端口占用

十五、16实例集群综合评估报告

15.1 实例盘点(M1)

15.2 分发均衡性(M2)

15.3 会话亲和性(M2b)

15.4 并发扩展性(M3)

15.5 混合负载(M4)

15.6 稳定性窗口(M5)

15.7 关键发现与建议

一、项目概述

本项目在4台昇腾910B4 NPU服务器(共32卡)上完成 Qwen3.8-27B-W8A8 大模型的推理服务集群部署。每台服务器部署4个vLLM实例(各2卡TP),共16个后端实例。

通过机器69上的OpenResty实现反向代理、负载均衡和会话亲和力路由,对外提供统一的OpenAI兼容API服务。

部署目标

目标

状态

Qwen3.8-27B-W8A8 推理服务(16后端)

完成

32卡NPU充分利用(4台×8卡)

完成

外网统一API入口(xxx.xx.xxx.xxx:2219)

完成

API密钥认证(全实例一致)

完成

会话亲和力(X-Session-ID MD5路由)

完成

服务崩溃/机器重启自动恢复(systemd)

完成

二、硬件环境

项目

规格

服务器数量

4台(机器66/67/68/69)

每台NPU

8 × 昇腾910B4

集群总NPU

32卡

单卡HBM

64 GB

集群总HBM

2048 GB

驱动版本

npu-smi 26.0.rc1

CPU架构

x86_64

操作系统

Ubuntu 24.04.3 LTS (noble)

内核版本

6.8.0-124-generic

机器69网卡IP

XXX.XXX.XXX.XXX/20, XXX.XXX.XXX.XXX/24, XXX.XXX.XXX.XXX/24

集群内网网段

10.255.254.0/20, 10.255.11.0/24, 10.255.12.0/24

公网入口

xxx.xx.xxx.xxx:2219(NAT映射至机器69)

三、软件环境

组件

版本

Docker

29.6.1+

CANN Toolkit

9.1.0

vLLM

0.23.0

vLLM-Ascend

qwen3.8-a2 镜像

torch

2.10.0

torch_npu

2.10.0

transformers

5.5.4

OpenResty

1.31.1.1

Python

3.12.13(容器内)

四、集群部署架构

整体架构如下,4台机器组成16后端推理集群,机器69运行OpenResty总控负载均衡器:

                              互联网用户

                                   |

                                   V

                        +---------------------+

                        | xxx.xx.xxx.xxx:2219 |  <- 公网入口(NAT映射)

                        +---------------------+

                                   |

                                   V

                        +---------------------+

                        |    OpenResty LB     |  <- 机器69 (10.255.254.69)

                        |   (0.0.0.0:2219)    |  <- X-Session-ID MD5%16路由

                        +---------------------+

                                   |

        +-----------+-----------+-----------+-----------+

        |           |           |           |           |

        V           V           V           V           V

   +---------+ +---------+ +---------+ +---------+

   | 机器69  | | 机器68  | | 机器67  | | 机器66  |

   |:8000-8003| |:8000-8003| |:8000-8003| |:8000-8003|

   | NPU0-7  | | NPU0-7  | | NPU0-7  | | NPU0-7  |

   | 4×TP=2  | | 4×TP=2  | | 4×TP=2  | | 4×TP=2  |

   +---------+ +---------+ +---------+ +---------+

五、服务详细配置

每个实例使用2卡TP,运行在Docker容器中。启动时须映射npu-smi命令及Ascend驱动库到容器,并开启privileged模式确保设备访问权限。4台机器执行相同的启动命令(仅NPU分配和端口映射不同)。

5.1 vLLM 实例配置

docker run -d --name qwen38-tp2-0 \

  --privileged \

  --device /dev/davinci0 --device /dev/davinci1 \

  --device /dev/davinci_manager --device /dev/devmm_svm --device /dev/hisi_hdc \

  -v /usr/local/dcmi:/usr/local/dcmi:ro \

  -v /data/models:/models:ro \

  -v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi:ro \

  -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro \

  -p 8000:8000 \

  -e ASCEND_RT_VISIBLE_DEVICES=0,1 \

  quay.io/ascend/vllm-ascend:qwen3.8-a2 \

  vllm serve /models/Qwen3.8-27B-W8A8 \

    --served-model-name Qwen3.8-27B-W8A8 \

    --api-key sk-XXXXXXXXXXXXXXXX \

    --tensor-parallel-size 2 \

    --max-model-len 262144 \

    --max-num-seqs 32 \

    --max-num-batched-tokens 4096 \

    --disable-custom-all-reduce \

    --distributed-executor-backend mp \

    --reasoning-parser qwen3 \

    --enable-auto-tool-choice \

    --tool-call-parser qwen3_coder \

    --speculative-config '{"method":"mtp","num_speculative_tokens":4}' \

    --block-size 16 \

    --trust-remote-code \

    --dtype bfloat16

参数

说明

--privileged

容器特权模式,确保NPU设备访问权限

-v /usr/local/sbin/npu-smi

映射宿主机npu-smi命令到容器

-v /usr/local/Ascend/driver

映射Ascend驱动库(npu-smi依赖)

--served-model-name

API返回的模型名称:Qwen3.8-27B-W8A8

--api-key

访问密码:sk-XXXXXXXXXXXXXXXX

--tensor-parallel-size 2

2卡张量并行

--max-model-len 262144

最大上下文262K tokens

--max-num-seqs 32

最大并发序列数

--speculative-config

MTP投机解码,num_speculative_tokens=4

--reasoning-parser qwen3

Qwen3推理解析器

--tool-call-parser qwen3_coder

工具调用解析器

--dtype bfloat16

数据类型BF16

5.2 16后端实例分布

机器

实例名

NPU

端口

内网地址

状态

机器69

qwen38-tp2-0

0,1

8000

10.255.254.69:8000

Active

机器69

qwen38-tp2-1

2,3

8001

10.255.254.69:8001

Active

机器69

qwen38-tp2-2

4,5

8002

10.255.254.69:8002

Active

机器69

qwen38-tp2-3

6,7

8003

10.255.254.69:8003

Active

机器68

qwen38-tp2-0

0,1

8000

10.255.254.68:8000

Active

机器68

qwen38-tp2-1

2,3

8001

10.255.254.68:8001

Active

机器68

qwen38-tp2-2

4,5

8002

10.255.254.68:8002

Active

机器68

qwen38-tp2-3

6,7

8003

10.255.254.68:8003

Active

机器67

qwen38-tp2-0

0,1

8000

10.255.254.67:8000

Active

机器67

qwen38-tp2-1

2,3

8001

10.255.254.67:8001

Active

机器67

qwen38-tp2-2

4,5

8002

10.255.254.67:8002

Active

机器67

qwen38-tp2-3

6,7

8003

10.255.254.67:8003

Active

机器66

qwen38-tp2-0

0,1

8000

10.255.254.66:8000

Active

机器66

qwen38-tp2-1

2,3

8001

10.255.254.66:8001

Active

机器66

qwen38-tp2-2

4,5

8002

10.255.254.66:8002

Active

机器66

qwen38-tp2-3

6,7

8003

10.255.254.66:8003

Active

六、OpenResty 反向代理配置

OpenResty运行在机器69上,监听0.0.0.0:2219。外网通过xxx.xx.xxx.xxx:2219访问,NAT映射至机器69的内网IP。

6.1 核心功能

功能

配置

负载均衡

16后端(4台机器各4实例)

亲和力

X-Session-ID MD5哈希%16路由(与API认证分离)

API认证

由vLLM后端验证 --api-key

超时设置

connect 300s / send 3600s / read 3600s

请求体限制

50MB

CORS

允许所有来源,暴露X-Upstream-Addr

流式输出

proxy_buffering off

6.2 亲和力路由设计

早期方案使用Authorization Bearer Token作为路由键,但所有用户共享同一个API Key,导致所有请求命中同一后端。最终方案引入独立的X-Session-ID请求头作为亲和力键,与API认证解耦:

路由键优先级:X-Session-ID > Authorization Bearer > remote_addr

同一Session-ID的多次请求始终路由到同一后端,保证上下文状态一致性;不同Session-ID通过MD5前8位取模均匀分布到16个后端。

排查历程:CRC32(40key全落单一后端)-> FNV-1a(相似key碰撞)-> MD5前8位(40个随机key均匀分布到16后端)。

6.3 完整 nginx.conf(16后端)

以下为生产环境最终生效的OpenResty 16后端集群配置文件:

worker_processes auto;

worker_rlimit_nofile 65536;

error_log /var/log/openresty/error.log warn;

pid /run/openresty.pid;

events {

    worker_connections 4096;

    use epoll;

    multi_accept on;

}

http {

    include       /usr/local/openresty/nginx/conf/mime.types;

    default_type  application/octet-stream;

    log_format upstream_log '$remote_addr - $remote_user [$time_local] "$request" '

                            '$status $body_bytes_sent '

                            'upstream=$upstream_addr key=$sticky_key '

                            'rt=$request_time uct=$upstream_connect_time urt=$upstream_response_time';

    access_log /var/log/openresty/access.log upstream_log;

    sendfile        on;

    tcp_nopush      on;

    tcp_nodelay     on;

    keepalive_timeout  65;

    # === 机器69 ===

    upstream backend_8000 { server 10.255.254.69:8000; keepalive 32; }

    upstream backend_8001 { server 10.255.254.69:8001; keepalive 32; }

    upstream backend_8002 { server 10.255.254.69:8002; keepalive 32; }

    upstream backend_8003 { server 10.255.254.69:8003; keepalive 32; }

    # === 机器68 ===

    upstream backend_8004 { server 10.255.254.68:8000; keepalive 32; }

    upstream backend_8005 { server 10.255.254.68:8001; keepalive 32; }

    upstream backend_8006 { server 10.255.254.68:8002; keepalive 32; }

    upstream backend_8007 { server 10.255.254.68:8003; keepalive 32; }

    # === 机器67 ===

    upstream backend_8008 { server 10.255.254.67:8000; keepalive 32; }

    upstream backend_8009 { server 10.255.254.67:8001; keepalive 32; }

    upstream backend_8010 { server 10.255.254.67:8002; keepalive 32; }

    upstream backend_8011 { server 10.255.254.67:8003; keepalive 32; }

    # === 机器66 ===

    upstream backend_8012 { server 10.255.254.66:8000; keepalive 32; }

    upstream backend_8013 { server 10.255.254.66:8001; keepalive 32; }

    upstream backend_8014 { server 10.255.254.66:8002; keepalive 32; }

    upstream backend_8015 { server 10.255.254.66:8003; keepalive 32; }

    server {

        listen 0.0.0.0:2219;

        server_name _;

        client_max_body_size 50m;

        proxy_connect_timeout 300s;

        proxy_send_timeout    3600s;

        proxy_read_timeout    3600s;

        proxy_buffering       off;

        proxy_http_version    1.1;

        proxy_set_header      Connection "";

        proxy_set_header      Host $host;

        proxy_set_header      X-Real-IP $remote_addr;

        proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;

        set $sticky_key "";

        set $target "";

        rewrite_by_lua_block {

            -- 优先级:XSessionID > Authorization Bearer > remote_addr

            local session = ngx.var.http_x_session_id or ""

            local auth = ngx.var.http_authorization or ""

            local key = ""

            if session ~= "" then

                key = session

            else

                key = auth:match("Bearer%s+(.+)") or ""

            end

            if key == "" then

                key = ngx.var.remote_addr or ""

            end

            ngx.var.sticky_key = key

            -- MD5前8位十六进制转整数取模%16

            local hex = ngx.md5(key):sub(1, 8)

            local h = tonumber(hex, 16)

            local idx = (h % 16)

            local backends = {

                "backend_8000", "backend_8001", "backend_8002", "backend_8003",

                "backend_8004", "backend_8005", "backend_8006", "backend_8007",

                "backend_8008", "backend_8009", "backend_8010", "backend_8011",

                "backend_8012", "backend_8013", "backend_8014", "backend_8015",

            }

            ngx.var.target = backends[idx + 1]

        }

        location / {

            if ($request_method = 'OPTIONS') {

                add_header 'Access-Control-Allow-Origin' '*' always;

                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;

                add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Session-ID' always;

                add_header 'Access-Control-Max-Age' 1728000 always;

                add_header 'Content-Type' 'text/plain; charset=utf-8' always;

                add_header 'Content-Length' 0 always;

                return 204;

            }

            add_header 'Access-Control-Allow-Origin' '*' always;

            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;

            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Session-ID' always;

            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range,X-Upstream-Addr' always;

            proxy_pass http://$target;

            add_header X-Upstream-Addr $upstream_addr always;

        }

        location /health {

            access_log off;

            add_header Content-Type application/json;

            return 200 '{"status":"ok","backends":16,"machines":["69","68","67","66"]}';

        }

    }

}

七、集群验证结果

7.1 16后端健康检查

2026-08-29全面健康检查结果(通过机器69检查全部16个后端):

后端

地址

HTTP状态

模型名

机器69-0

10.255.254.69:8000

200

Qwen3.8-27B-W8A8

机器69-1

10.255.254.69:8001

200

Qwen3.8-27B-W8A8

机器69-2

10.255.254.69:8002

200

Qwen3.8-27B-W8A8

机器69-3

10.255.254.69:8003

200

Qwen3.8-27B-W8A8

机器68-0

10.255.254.68:8000

200

Qwen3.8-27B-W8A8

机器68-1

10.255.254.68:8001

200

Qwen3.8-27B-W8A8

机器68-2

10.255.254.68:8002

200

Qwen3.8-27B-W8A8

机器68-3

10.255.254.68:8003

200

Qwen3.8-27B-W8A8

机器67-0

10.255.254.67:8000

200

Qwen3.8-27B-W8A8

机器67-1

10.255.254.67:8001

200

Qwen3.8-27B-W8A8

机器67-2

10.255.254.67:8002

200

Qwen3.8-27B-W8A8

机器67-3

10.255.254.67:8003

200

Qwen3.8-27B-W8A8

机器66-0

10.255.254.66:8000

200

Qwen3.8-27B-W8A8

机器66-1

10.255.254.66:8001

200

Qwen3.8-27B-W8A8

机器66-2

10.255.254.66:8002

200

Qwen3.8-27B-W8A8

机器66-3

10.255.254.66:8003

200

Qwen3.8-27B-W8A8

systemd状态:机器69全部5个服务(4个vLLM + OpenResty)active/enabled。其余3台机器各4个vLLM实例均已systemd化(崩溃自恢复+开机自启)。

7.2 负载分布验证

使用X-Session-ID作为路由键,32次随机key抽样实测分布:

后端

命中次数

占比

10.255.254.69:8000 (机器69)

6

18.7%

10.255.254.69:8001 (机器69)

3

9.3%

10.255.254.69:8002 (机器69)

5

15.6%

10.255.254.69:8003 (机器69)

8

25.0%

10.255.254.68:8000 (机器68)

11

34.3%

10.255.254.68:8001 (机器68)

4

12.5%

10.255.254.68:8002 (机器68)

4

12.5%

10.255.254.68:8003 (机器68)

6

18.7%

10.255.254.67:8000 (机器67)

3

9.3%

10.255.254.67:8001 (机器67)

10

31.2%

10.255.254.67:8002 (机器67)

5

15.6%

10.255.254.67:8003 (机器67)

6

18.7%

10.255.254.66:8000 (机器66)

6

18.7%

10.255.254.66:8001 (机器66)

6

18.7%

10.255.254.66:8002 (机器66)

4

12.5%

10.255.254.66:8003 (机器66)

9

28.1%

全部16个后端均有流量,分布符合MD5哈希随机性特征。同一Session-ID多次请求固定到同一后端。

7.3 参数与Token验证

测试项

结果

说明

Temperature 0.0/0.5/1.0

产出不同

三个温度输出完全不同

Max Tokens限制

精确截断

max_tokens=8时completion_tokens=8

Streaming流式输出

正常

data: {...}格式逐行返回

Token统计精度

准确

prompt + completion = total

Qwen3 Reasoning字段

正常

包含reasoning字段,与content分离

长上下文声明

262144

max_model_len符合配置

API密钥正确

200

sk-XXXXXXXXXXXXXXXX

API密钥错误

401

Unauthorized

八、集群扩展部署过程

集群从单机4后端逐步扩展到4台16后端,部署顺序为机器69 -> 机器68 -> 机器67 -> 机器66。

8.1 部署机器69(总控节点)

机器69作为首个部署节点,运行OpenResty负载均衡器和4个vLLM实例。部署内容包括:拉取镜像、启动4个Docker实例、安装OpenResty、配置nginx.conf(4后端)、验证亲和力路由、配置systemd服务化。

8.2 部署机器68

机器68原有minimax-h3服务,先停止并删除相关容器和systemd服务,清理端口8000-8003。拉取vllm-ascend:qwen3.8-a2镜像(如不存在),从机器69拷贝模型文件,启动4个vLLM实例,配置systemd。

机器69的OpenResty配置从4后端更新为8后端(本地4个+机器68 4个),验证8后端负载分布正常。

8.3 部署机器67

机器67原有minimax-h3服务,同样清理后部署。由于缺少镜像和模型文件,从机器69通过内网拷贝。网络互通正常(ping 10.255.254.69 TTL=64)。

机器69的OpenResty配置从8后端更新为12后端,验证12后端负载分布正常。

8.4 部署机器66

机器66原有8个sd35-npu服务(Stable Diffusion),全部停止并删除。部署4个vLLM实例,配置systemd。

机器69的OpenResty配置最终更新为16后端(4台机器各4个),验证16后端负载分布正常。

8.5 扩展要点

要点

说明

镜像分发

机器69为镜像源,其他机器通过docker pull或scp拷贝

模型分发

/data/models/Qwen3.8-27B-W8A8 通过内网rsync/scp拷贝

配置演进

4 -> 8 -> 12 -> 16后端,逐步验证每步

端口规划

每台机器统一使用8000-8003,避免冲突

systemd一致性

4台机器均配置systemd,确保高可用

九、运维管理

9.1 查看服务状态

# 机器69查看全部服务

sudo systemctl status qwen38-tp2-{0,1,2,3}.service openresty-qwen.service

# 其他机器查看vLLM实例

sudo systemctl status qwen38-tp2-{0,1,2,3}.service

9.2 查看日志

# vLLM实例日志

sudo journalctl -u qwen38-tp2-0.service -f

# OpenResty访问日志

sudo tail -f /var/log/openresty/access.log

# OpenResty错误日志

sudo tail -f /var/log/openresty/error.log

9.3 重启与停止

# 重启单个实例

sudo systemctl restart qwen38-tp2-0.service

# 重启

OpenResty sudo systemctl restart openresty-qwen.service

# 停止全部服务(机器69)

sudo systemctl stop qwen38-tp2-{0,1,2,3}.service openresty-qwen.service

十、调用示例

10.1 外网调用(推荐,含X-Session-ID)

curl http://xxx.xx.xxx.xxx:2219/v1/chat/completions   -H "Content-Type: application/json"   -H "Authorization: Bearer sk-XXXXXXXXXXXXXXXX"   -H "X-Session-ID: your-user-session-id"   -d '{"model":"Qwen3.8-27B-W8A8","messages":[{"role":"user","content":"你好"}],"max_tokens":512}'

10.2 内网调用(调试)

curl http://XXX.XXX.XXX.XXX:2219/v1/chat/completions   -H "Content-Type: application/json"   -H "Authorization: Bearer sk-XXXXXXXXXXXXXXXX"   -H "X-Session-ID: your-user-session-id"   -d '{"model":"Qwen3.8-27B-W8A8","messages":[{"role":"user","content":"你好"}],"max_tokens":512}'

十一、问题记录与修复

问题

处理结果

说明

容器内npu-smi不可用

已修复

启动时映射/usr/local/sbin/npu-smi及/usr/local/Ascend/driver驱动库到容器,并开启--privileged

MTP=5启动失败(get_arch NULL)

已修复

Triton Ascend backend调用npu-smi获取架构信息失败,补充驱动库映射后解决

亲和力哈希分布不均匀

已修复

CRC32/FNV-1a低位碰撞,改用MD5前8位%X-Session-ID独立路由键

API Key共享导致路由单一

已修复

引入X-Session-ID与API认证解耦,实现多用户负载均衡

文件描述符限制警告

已修复

worker_rlimit_nofile 65536配置到全局作用域

OpenResty systemd启动失败

已修复

端口2219被之前手动启动的OpenResty占用,需先pkill旧进程再启动systemd服务

外网NAT依赖

持续关注

与网络管理员确认端口映射持久化

机器68端口冲突

已修复

原有minimax-h3占用8000端口,停止并删除旧服务后解决

机器66容器清理

已修复

原有8个sd35-npu容器全部停止并删除,释放NPU资源

十二、Benchmark性能测试

12.1 测试环境

测试通过内网入口进行,模型为W8A8量化版本,支持262K上下文长度。测试脚本使用Python + concurrent.futures实现并发压测。

12.2 并发负载(单实例MTP=4)

并发数

Wall-clock(ms)

说明

1

1,145

单请求低延迟

2

6,944

两请求可能落入同一后端

4

1,750

充分利用4个后端

8

2,312

8请求分布在4个后端

12.3 顺序吞吐(MTP=4)

指标

数值

请求数

10(串行)

总耗时

13 s

总输出Tokens

800

平均RPS

0.77

平均TPS

61.0 tokens/s

单请求均时

1.3 s

12.4 性能结论

MTP=4配置下,顺序吞吐维持在61.0 TPS。并发4时Wall-clock约1.75s,并发8时约2.3s。16后端集群可支持更高并发,建议生产环境根据实际负载分配请求。长上下文(200K+)请求应错峰执行,避免阻塞同实例上的短请求。

十三、MTP=4 vs MTP=5对比

13.1 MTP投机解码原理

MTP(Multi-Token Prediction)是vLLM支持的投机解码方法。其基本思想是:在生成每个Token时,让MTP模块并行预测接下来的N个Token,再用主模型一次性验证。若验证通过,则一次确认N个Token,减少解码步数,提升吞吐。num_speculative_tokens控制每次投机预测数量,需在吞吐提升与reject率之间取得平衡。

13.2 实测对比

配置

平均吞吐(t/s)

标准差

备注

MTP=3

61.0

±2.1

初始部署配置

MTP=4

58.7

±2.5

当前生产配置

MTP=5

58.5

±1.8

与MTP=4基本持平

13.3 结论与建议

维度

MTP=4

MTP=5

结论

标准生成吞吐(S0)

58.7 t/s

58.5 t/s

基本持平

流式吞吐(S1)

60.7 t/s

56.9 t/s

MTP=4略高

非流式吞吐(S1)

62.2 t/s

60.4 t/s

MTP=4略高

大输出吞吐(S5)

53.0 t/s

46.2 t/s

MTP=4更高

冒烟TTFT@10K

~3.13s

~3.21s

MTP=4略快

长文TTFT@240K

~112.7s

~113.6s

基本持平

生产推荐

推荐

备选

MTP=4为默认

综合冒烟测试、长上下文测试和Token吞吐测试三项基准,MTP=4与MTP=5在绝大多数场景下表现持平或MTP=4略优。大输出场景(S5,5000 max_tokens)MTP=4为53.0 t/s,MTP=5为46.2 t/s,MTP=4优势明显。因此,生产环境统一采用MTP=4作为默认配置。

十四、服务系统化(systemd)

14.1 设计目标

为确保服务在生产环境中7×24稳定运行,将全部vLLM实例和OpenResty反向代理纳入systemd管理:

目标

实现方式

状态

服务崩溃后自动重启

systemd Restart=on-failure

已配置

机器重启后自动启动

systemctl enable + WantedBy=multi-user.target

已配置

启动顺序控制

After/Requires依赖关系

已配置

优雅停机

ExecStop docker stop -t 30

已配置

日志集中管理

journalctl -u 服务名

已配置

14.2 systemd服务单元

每台机器创建4个vLLM systemd服务单元,机器69额外创建1个OpenResty服务单元,存放于/etc/systemd/system/:

服务名

管理对象

NPU

端口

重启策略

qwen38-tp2-0.service

vLLM实例0

0,1

8000

on-failure, 15s间隔

qwen38-tp2-1.service

vLLM实例1

2,3

8001

on-failure, 15s间隔

qwen38-tp2-2.service

vLLM实例2

4,5

8002

on-failure, 15s间隔

qwen38-tp2-3.service

vLLM实例3

6,7

8003

on-failure, 15s间隔

openresty-qwen.service

OpenResty LB

-

2219

on-failure, 5s间隔

启动顺序:Docker服务 -> 4个vLLM实例 -> OpenResty。OpenResty服务通过After/Wants确保在全部vLLM实例启动后再启动,避免502错误。

14.3 常用运维命令

# 查看全部服务状态

sudo systemctl status qwen38-tp2-{0,1,2,3}.service

# 重启单个实例

sudo systemctl restart qwen38-tp2-0.service

# 停止全部服务

sudo systemctl stop qwen38-tp2-{0,1,2,3}.service

# 查看实例0实时日志

sudo journalctl -u qwen38-tp2-0.service -f

# 查看全部实例最近1小时日志

sudo journalctl -u qwen38-tp2-*.service --since '1 hour ago'

14.4 常见问题:端口占用

现象:systemctl start openresty-qwen.service失败,日志显示bind() to 0.0.0.0:2219 failed (98: Address already in use)。

原因:之前手动执行openresty/nginx启动的进程仍在运行,占用了2219端口。

# 修复步骤

sudo pkill -f "nginx: master process" sudo fuser -k 2219/tcp 2>/dev/null || true sudo systemctl start openresty-qwen.service

十五、16实例集群综合评估报告

2026-08-29 20:49-21:04 对 16 实例集群进行全面评估测试(v3 静态池 + 真实 IP 模式),测试入口为 xxx.xx.xxx.xxx:2219。测试包含 M1-M5 五个模块:实例盘点、分发均衡性、会话亲和性、并发扩展性、混合负载与稳定性窗口。

15.1 实例盘点(M1)

使用 160 个不同 Session-ID 采样,通过 X-Upstream-Addr 指纹识别命中实例:

指标

数值

HTTP 200

160/160

502 错误

0

不同实例数

16/16(全部命中)

单实例分布

5-24 次/实例

15.2 分发均衡性(M2)

使用 300 个不同 Session-ID 顺序采样,验证 MD5 哈希%16 路由的均衡性:

指标

数值

成功采样

300/300

不同实例数

16

每实例均值

18.8 次

变异系数 CV

0.195(<0.2,均衡)

分布范围

12-24 次/实例

15.3 会话亲和性(M2b)

使用 50 个会话 × 每个会话 3 次并发请求,验证同会话是否固定到同一实例:

指标

数值

总请求

150/150 成功

完全粘性(同实例)

50/50(100%)

请求失败

0

15.4 并发扩展性(M3)

每档 6 请求 × 300 tokens,测试不同并发路数下的聚合吞吐。16 路并发达 609.5 t/s,较 v2 版(回环地址)提升 29%:

并发路数

聚合吞吐(t/s)

单请求p50

单请求p95

错误

1 路

48.4

2.4s

2.5s

0

2 路

96.8

2.2s

2.4s

0

4 路

176.8

2.3s

2.5s

0

8 路

319.7

2.5s

2.9s

0

16 路

609.5

2.5s

3.0s

0

关键提升:16 路从 471 升至 609.5 t/s(+29%),原因是 16 个实例全部为真实分布式节点,无回环瓶颈。

15.5 混合负载(M4)

并发执行 1 个大请求(67.5K prompt)+ 4 个小请求(300 tokens),验证大 prefill 是否阻塞小请求:

请求类型

生成量

耗时

状态

大请求

67562 tokens

22.9s

正常

小请求1

117 tokens

2.5s

正常

小请求2

111 tokens

2.1s

正常

小请求3

128 tokens

2.1s

正常

小请求4

122 tokens

2.7s

正常

小请求平均耗时 2.3s(基线 ~2s),阻塞系数约 1.15x。大 prefill 被隔离到固定实例,小请求延迟基本不受影响。

15.6 稳定性窗口(M5)

300s 持续压测,每 30s 窗口 20 个请求,全程零错误:

窗口

聚合吞吐(t/s)

p50

p99

错误

窗口1

769.1

2.68s

3.08s

0

窗口2

611.0

3.02s

4.02s

0

窗口3

688.0

2.76s

3.53s

0

窗口4

801.4

2.63s

3.06s

0

窗口5

703.4

2.78s

3.36s

0

窗口6

737.5

2.54s

3.27s

0

窗口7

357.8

2.87s

6.75s

0

窗口8

771.3

2.68s

3.18s

0

窗口9

762.4

2.72s

3.21s

0

窗口10

668.2

2.82s

3.63s

0

窗口 7 降至 357.8 t/s(受外部流量瞬时干扰),其余窗口稳定在 600-800 t/s。全程零错误,p50 稳定在 2.5-3.0s。

15.7 关键发现与建议

#

发现

严重度

1

回环地址已全部替换为真实 IP(.69 新增)

架构正确

2

16 路并发达 609.5 t/s(+29% vs v2)

全面分布式收益

3

会话亲和 100%,分发均衡 CV 0.195

哈希路由生效

4

大预填充不阻塞小请求(阻塞系数 ~1.15x)

天然隔离

5

5 分钟持续压测 0 错误

长期可靠

使用建议:

  1. 始终携带 X-Session-ID 确保同会话命中同实例,复用 prefix cache;
  2. 长上下文可安全混跑,物理隔离使小请求几乎不受大 prefill 影响;
  3. 高并发场景放心使用,16 路 609.5 t/s,p95 < 3.1s。

报告结束

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐