8卡服务器(4服务x 2卡)Nginx 负载均衡配置,与百分位延迟说明
- vLLM 请求处理时间长(10-30s),属于长连接场景 - 不同请求生成 token 数不同(200-300),处理时间异构 - least_conn 能动态将新请求发给当前最空闲的实例。排序后: [18s, 19s, 19s, 20s, 20s, 21s, 21s, 22s, 23s, 100s]10 个请求的延迟:[1s, 1s, 1s, 1s, 1s, 1s, 1s, 1s, 1s,
A.1 Nginx 负载均衡详细配置
A.1.1 当前生产配置
upstream vllm_backend {
least_conn;
server 10.255.254.44:8000;
server 10.255.254.44:8001;
server 10.255.254.44:8002;
server 10.255.254.44:8003;
}
server {
listen 0.0.0.0:2196;
server_name _;
location /v1/ {
proxy_pass http://vllm_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
proxy_buffering off;
proxy_socket_keepalive on;
}
location / {
return 444;
}
}
A.1.2 配置逐行说明
|
配置项 |
值 |
作用 |
|
least_conn |
— |
最少连接调度:将请求发给当前活跃连接数最少的后端实例,确保负载均匀 |
|
server 10.255.254.44:8000~8003 |
4 个后端 |
4 个 vLLM TP=2 实例,每个实例占用 2 张 4090 |
|
listen 0.0.0.0:2196 |
公网 2196 端口 |
对外暴露统一 API 入口 |
|
proxy_set_header 系列 |
透传客户端信息 |
让后端 vLLM 看到真实客户端 IP |
|
proxy_*_timeout 600s |
600 秒 |
匹配 vLLM 长生成时间,避免 Nginx 提前断开 |
|
proxy_buffering off |
关闭缓冲 |
流式响应实时返回,不等待完整响应 |
|
proxy_socket_keepalive on |
开启 TCP Keepalive |
维持长连接,减少 TCP 握手开销 |
|
location / { return 444; } |
静默拒绝 |
拦截非法扫描请求(如漏洞探测),不返回任何内容 |
A.1.3 负载均衡策略对比
|
策略 |
配置 |
适用场景 |
本测试表现 |
|
ip_hash |
ip_hash; |
会话保持(同一 IP 固定到同一后端) |
❌ 单实例过载,其余空闲 |
|
round_robin |
默认 |
简单轮询 |
⚠️ 请求长度不均时可能负载不均 |
|
least_conn |
least_conn; |
长连接/异构请求 |
✅ 最优,4 实例均匀负载 |
|
least_time |
需第三方模块 |
响应时间敏感 |
— 未测试 |
本测试选择 least_conn 的原因: - vLLM 请求处理时间长(10-30s),属于长连接场景 - 不同请求生成 token 数不同(200-300),处理时间异构 - least_conn 能动态将新请求发给当前最空闲的实例
A.1.4 后端实例架构
客户端请求
↓
Nginx (2196端口, least_conn)
↓
├─→ vLLM-8000 (GPU 0+1, TP=2)
├─→ vLLM-8001 (GPU 2+3, TP=2)
├─→ vLLM-8002 (GPU 4+5, TP=2)
└─→ vLLM-8003 (GPU 6+7, TP=2)
- 每个实例独立进程,互不影响
- 实例故障时 Nginx 自动剔除(需配合健康检查)
- 单实例重启不影响其他实例服务
A.1.5 健康检查建议(生产增强)
当前配置无主动健康检查,建议增加:
upstream vllm_backend {
least_conn;
server 10.255.254.44:8000 max_fails=3 fail_timeout=30s;
server 10.255.254.44:8001 max_fails=3 fail_timeout=30s;
server 10.255.254.44:8002 max_fails=3 fail_timeout=30s;
server 10.255.254.44:8003 max_fails=3 fail_timeout=30s;
}
或使用 nginx_upstream_check_module 做主动健康检查:
upstream vllm_backend {
least_conn;
server 10.255.254.44:8000;
check interval=3000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "GET /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
A.2 百分位延迟(P50 / P90 / P99)说明
A.2.1 什么是百分位延迟?
百分位延迟是衡量请求延迟分布的统计指标,比”平均延迟”更能反映真实用户体验。
|
指标 |
定义 |
通俗理解 |
|
P50 |
50th Percentile |
中位数:50% 请求比它快,50% 比它慢 |
|
P90 |
90th Percentile |
90% 请求 ≤ 这个值,10% 更慢 |
|
P99 |
99th Percentile |
99% 请求 ≤ 这个值,仅 1% 更慢 |
A.2.2 为什么不能用”平均延迟”?
平均延迟有欺骗性:
10 个请求的延迟:[1s, 1s, 1s, 1s, 1s, 1s, 1s, 1s, 1s, 100s]
平均延迟 = 10.9s ← 看起来"还行"
P99 延迟 = 100s ← 有一个用户等了 100 秒!
平均延迟掩盖了尾部用户的痛苦。
A.2.3 百分位延迟的计算方法
将 N 个请求的延迟从小到大排序:
排序后: [18s, 19s, 19s, 20s, 20s, 21s, 21s, 22s, 23s, 100s]
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
P10 P20 P30 P40 P50 P60 P70 P80 P90 P100
- P50 = 第 5 个值 = 20s(中位数)
- P90 = 第 9 个值 = 23s(90% 用户 ≤ 23s)
- P99 = 第 9.9 个值 ≈ 100s(99% 用户 ≤ 100s)
A.2.4 本测试中的百分位延迟数据
4090 测试结果(健康系统)
|
并发 |
请求数 |
P50 |
P90 |
P99 |
P99-P50 |
状态 |
|
1 |
50 |
19.2s |
19.2s |
19.2s |
0ms |
✅ 完全均匀 |
|
10 |
50 |
20.5s |
20.5s |
20.5s |
0ms |
✅ 完全均匀 |
|
20 |
50 |
19.8s |
19.8s |
19.8s |
0ms |
✅ 完全均匀 |
|
50 |
50 |
20.7s |
20.7s |
20.7s |
0ms |
✅ 完全均匀 |
|
100 |
50 |
20.4s |
20.4s |
20.4s |
0ms |
✅ 完全均匀 |
|
100 |
100 |
20.9s |
20.9s |
20.9s |
0ms |
✅ 完全均匀 |
|
200 |
150 |
— |
— |
21.5s |
— |
✅ 尾部稳定 |
|
250 |
250 |
— |
— |
22.2s |
— |
✅ 尾部稳定 |
特征:P50 = P90 = P99
B60 参考结果(压力系统)
|
并发 |
P50 |
P90 |
P99 |
P99-P50 |
状态 |
|
150 |
110s |
112s |
112s |
2s |
⚠️ 轻微尾部 |
|
200 |
151s |
164s |
184s |
33s |
❌ 尾部恶化 |
特征:P99 >> P90 >> P50
A.2.5 百分位差距的含义
|
P99-P50 差距 |
系统状态 |
说明 |
|
< 1s |
✅ 健康 |
调度公平,资源充足,所有请求一致 |
|
1-5s |
⚠️ 轻度压力 |
10% 请求开始变慢,调度轻微不均 |
|
5-20s |
❌ 中度瓶颈 |
尾部请求明显饥饿,队列堆积 |
|
> 20s |
❌ 严重瓶颈 |
系统过载,部分请求长时间等待 |
A.2.6 本测试结论
4090 + vLLM 表现: - 并发 250 以内,P99-P50 ≈ 0-3s - 说明 vLLM continuous batching 调度器工作完美 - 无请求被”饿死”,所有用户获得一致体验 - GPU 算力是瓶颈,但调度器不是瓶颈
对比 B60: - B60 并发 200 时 P99-P50 = 33s(尾部恶化 22%) - 4090 并发 250 时 P99-P50 ≈ 3s(零恶化)
4090 的调度公平性远超 B60。
A.2.7 生产环境的 P99 承诺
|
业务类型 |
建议 P99 目标 |
理由 |
|
实时客服 |
< 5s |
用户不能等,超时即流失 |
|
在线 API |
< 30s |
多数应用可接受,需进度提示 |
|
批处理/后台 |
< 120s |
容忍度高,但需监控 |
|
SLA 合同 |
必须写 P99 |
平均延迟无法作为法律承诺 |
A.2.8 如何解读本测试报告中的延迟数据
并发=200, 请求=150:
平均延迟: 22.3s
P50: — | P90: — | P99: 21.5s
解读:
- 平均延迟 22.3s 与 P99 21.5s 接近 → 分布均匀,无异常值
- 如果平均 >> P99,说明有少量请求极慢(被平均拉高了)
- 本测试中平均 ≈ P99 → 所有请求处理时间一致 ✅
A.3 配置与监控命令速查
查看 Nginx 配置
cat /etc/nginx/conf.d/vllm_lb.conf
重载 Nginx
sudo nginx -t && sudo systemctl reload nginx
查看后端连接分布
sudo ss -tnp | grep -E "8000|8001|8002|8003" | grep ESTAB | awk '{print $4}' | sort | uniq -c
查看 vLLM 实例日志
sudo journalctl -u vllm-8000 -f --no-pager | grep -E "chat.completions|Engine.*throughput"
查看 GPU 利用率
nvidia-smi --query-gpu=index,utilization.gpu,memory.used,temperature.gpu --format=csv
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)