多GPU服务器部署vLLM集群,中转网关负载均衡调度
多GPU服务器部署vLLM集群的核心思路,是把多张GPU卡拆成多个vLLM推理实例,再通过一个中转网关统一入口做负载均衡调度。
这样做的好处是:单卡故障不影响整体服务、吞吐量可按需扩容、客户端只需要连接一个固定地址。
下面按零基础可执行的方式,从环境准备到验证逐步说明。
一、部署前先确认三件事
第一,GPU卡和驱动要统一。 建议所有节点使用同型号GPU,驱动版本和CUDA版本保持一致。
如果混用A100和4090,调度器会按最弱卡的性能分配请求,导致资源浪费。
第二,vLLM版本要一致。 不同版本之间可能对模型格式、量化方式和API参数有差异。
执行 pip show vllm 查看版本,建议所有服务器安装同一个版本。
第三,中转网关至少需要一台独立服务器或单独的Nginx。 如果只有两台GPU服务器,也可以在其中一台部署网关,但生产环境不推荐,因为网关本身也会消耗CPU和内存。
下面是本教程使用的环境示例:
| 节点 | 角色 | 配置 |
| --- | --- | --- |
| 192.168.1.10 | GPU节点1 | 4×A100 80G |
| 192.168.1.11 | GPU节点2 | 4×A100 80G |
| 192.168.1.20 | 中转网关 | 4核8G,安装Nginx |
二、在GPU服务器上启动vLLM实例
先按单卡或单实例的方式启动多个vLLM进程。
假设每张卡启动一个实例,并指定不同的端口,便于网关统一转发。
第一步:安装vLLM(如果还没装)
pip install vllm
第二步:编写启动脚本
以GPU节点1为例,将4张卡拆成4个实例,分别监听 8001-8004 端口:
# 实例1
CUDA_VISIBLE_DEVICES=0 python -m vllm.entrypoints.openai.api_server \
--model /data/models/Qwen2.5-72B-Instruct \
--tensor-parallel-size 1 \
--port 8001
# 实例2
CUDA_VISIBLE_DEVICES=1 python -m vllm.entrypoints.openai.api_server \
--model /data/models/Qwen2.5-72B-Instruct \
--tensor-parallel-size 1 \
--port 8002
CUDA_VISIBLE_DEVICES 指定当前进程可见的GPU编号,tensor-parallel-size 1 表示单卡运行,这样每个实例独立处理请求,互不干扰。
其它实例依此类推。
第三步:验证实例正常启动
curl http://192.168.1.10:8001/v1/models
返回模型信息则启动成功。
所有GPU节点的所有实例都要能通过类似请求访问。
三、在中转网关配置Nginx负载均衡
在网关服务器上安装Nginx,然后把所有vLLM实例加入upstream组。
这里的关键是:每个GPU节点的实例都要被当作一台独立后端服务器,而不是按节点粒度转发。
第一步:安装Nginx(Debian/Ubuntu)
apt update && apt install nginx -y
第二步:新建Nginx配置
编辑 /etc/nginx/conf.d/vllm_cluster.conf:
upstream vllm_backends {
# 加权轮询,可根据GPU性能调整权重
server 192.168.1.10:8001 weight=1;
server 192.168.1.10:8002 weight=1;
server 192.168.1.10:8003 weight=1;
server 192.168.1.10:8004 weight=1;
server 192.168.1.11:8001 weight=1;
server 192.168.1.11:8002 weight=1;
server 192.168.1.11:8003 weight=1;
server 192.168.1.11:8004 weight=1;
# 开启健康检查(Nginx Plus支持,开源版可用nginx_upstream_check_module或定期探测)
# 这里用最简单的被动健康检查:后端连续失败2次则摘除30秒
server 192.168.1.10:8001 max_fails=2 fail_timeout=30s;
# ……其余server同样加参数
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://vllm_backends;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# vLLM支持流式输出,必须关闭缓冲
proxy_buffering off;
proxy_cache off;
# 长连接超时设置,避免等待生成时断开
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
第三步:检查配置并重载
nginx -t
nginx -s reload
如果 nginx -t 返回 syntax is ok,说明配置无误。
四、常见报错与避坑指南
1. 网关转发后返回502 Bad Gateway
先检查后端vLLM实例是否还在运行:curl http://192.168.1.10:8001/v1/models。
如果实例正常,再确认防火墙是否放行了网关到后端端口的访问。
Nginx重载后也要看错误日志 /var/log/nginx/error.log。
2. 流式输出(SSE)卡住或中断
必须关闭代理缓冲:
proxy_buffering off;
同时把 proxy_read_timeout 调大,否则vLLM生成大量token时Nginx会过早断开。
3. 多实例共享相同模型但显存不足
如果一张卡不够放下整个模型,请不要强制使用单卡。
正确做法是减少实例数,改用张量并行:
CUDA_VISIBLE_DEVICES=0,1 python -m vllm.entrypoints.openai.api_server \
--model /data/models/Qwen2.5-72B-Instruct \
--tensor-parallel-size 2 \
--port 8001
此时该实例占用2张卡,后端upstream里的地址也要对应修改。
4. 网关本身成为瓶颈
当并发很高时,Nginx的 worker_processes 默认值可能不够。
可调整为CPU核心数,并开启keepalive到后端:
upstream vllm_backends {
keepalive 64;
server 192.168.1.10:8001;
# ...
}
然后在 location 中增加 proxy_http_version 1.1; 和 proxy_set_header Connection "";。
五、如何验证调度是否生效
第一步:查看后端连接分布
持续发送请求,然后分别登录GPU服务器查看各端口连接数:
ss -tn | grep :8001 | wc -l
正常情况下所有端口都应该有连接,而不是集中在某一台机器上。
第二步:用压测工具验证吞吐
推荐使用 hey 或 wrk 发起简单请求测试:
hey -n 1000 -c 50 -m POST -H "Content-Type: application/json" \
-d '{"model":"Qwen2.5-72B-Instruct","messages":[{"role":"user","content":"hello"}]}' \
http://192.168.1.20/v1/chat/completions
观察返回结果中是否有超时或错误。
如果全部成功,说明中转网关负载均衡调度已经正常工作。
第三步:停掉一个后端实例测试自动摘除
找一台GPU服务器,杀掉其中一个vLLM进程,然后继续发请求。
在Nginx开源版中,max_fails 机制会让失败次数达到阈值后自动把该实例移出转发列表,期间请求会被转发到其它健康实例,这就是集群调度带来的稳定性。
如果你正在处理多GPU服务器部署vLLM集群、中转网关负载均衡调度相关的问题,建议先按本文步骤完整执行,再根据自己环境调整权重和超时参数;
遇到异常时优先回看避坑和高频问题部分。
后续还可以结合Kubernetes和容器化方案做更细粒度的自动扩缩容,但先把当前这套基础架构跑稳,再逐步演进更安全。