LLM 负载均衡:在前端均匀分发推理请求
负载均衡 LLM:在前端均匀分发推理请求
LLM(大语言模型)服务通常是计算密集型的,单台服务器很难承载全部用户请求。通过负载均衡将请求均匀分发到多个推理后端,可以提升吞吐量、降低延迟,并避免单点故障。本教程聚焦于如何在前端(反向代理层)实现 LLM 推理请求的均匀分发,即使你是零运维经验的开发者也能轻松上手。
为什么 LLM 需要负载均衡?
- 计算资源有限:每个推理请求可能占用数 GB 显存和大量算力,单 GPU 的并发能力有限。
- 请求时长波动大:短问题可能 200ms 返回,长文本生成可能持续数秒甚至数十秒,极易造成队列堆积。
- 模型部署多元化:你可能同时运行 7B 量化版和 70B 全量版,需要把不同难度的请求路由到不同实例。
什么是负载均衡?
负载均衡器是一个“流量调度器”,它对外暴露一个统一入口,对内将请求按策略转发到多个后端服务。对调用方而言,它只需要知道一个地址,而不需要关心后端有几台机器、哪台空闲。
用户请求 → [ 负载均衡器 ] → 推理实例 A
→ 推理实例 B
→ 推理实例 C
LLM 推理请求的负载特征
与普通 Web 服务不同,LLM 推理具有以下特点:
- 长连接与流式响应:很多推理采用 SSE (Server‑Sent Events) 流式输出 token,连接会持续很长时间。
- 资源消耗差异大:prompt 长度、生成 token 数、是否启用 kv‑cache 复用,都会导致内存和计算开销悬殊。
- 有状态/无状态共存:无状态对话可以把每次请求视为独立;但带有上下文的多轮对话(依赖缓存)则希望请求能“粘滞”在同一实例上。
了解这些特征后,我们才能选择合适的负载分配策略。
前端负载均衡架构概览
最简单的方案是在反向代理层做分发,推理实例直接运行在 GPU 服务器上,对外暴露内网 IP 和端口(如 http://10.0.1.10:8000)。负载均衡器可以选用:
- Nginx:高性能、配置简单,社区版本支持 HTTP/1.1、WebSocket、长连接。
- HAProxy:更专业的负载均衡器,对 TCP/HTTP 长连接处理更细腻,支持更复杂的健康检查。
- 自研网关:适合需要定制路由逻辑(如按 prompt 长度路由)的场景。
本教程以 Nginx 为例讲解核心配置,并附带 HAProxy 关键片段。
使用 Nginx 实现 LLM 请求均匀分发
安装与基础配置
在 Ubuntu 上安装 Nginx:
sudo apt update
sudo apt install nginx
定义上游服务器组,假设你部署了三台 vLLM 实例,监听 8000 端口:
http {
upstream llm_backend {
server 10.0.1.10:8000;
server 10.0.1.11:8000;
server 10.0.1.12:8000;
}
server {
listen 80;
server_name llm.example.com;
location / {
proxy_pass http://llm_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_read_timeout 300s; # 适应长生成请求
proxy_buffering off; # 流式输出关闭缓冲
}
}
}
上述配置默认使用**轮询(Round Robin)**策略,请求依次分发到三台实例。
适应长连接与流式响应
LLM 推理大量使用 SSE,必须关闭代理缓冲并延长超时:
proxy_buffering off;:收到上游数据立即转发,避免延迟。proxy_read_timeout 300s;:等待上游响应的最大时间,根据你预期的最大生成时长调整。- 支持 HTTP/1.1 长连接:设置
proxy_http_version 1.1;并清除Connection头。
最少连接策略
轮询不考虑实例当前负载,可能把新请求发给正在拼命处理长请求的机器,导致“旱的旱死,涝的涝死”。改用 least_conn 可以让请求优先发给活动连接数最少的实例:
upstream llm_backend {
least_conn;
server 10.0.1.10:8000;
server 10.0.1.11:8000;
server 10.0.1.12:8000;
}
这个策略对请求时长差异大的场景很有效,是 LLM 负载均衡的首选。
权重分发
如果后端 GPU 算力不同(如 A100 和 T4 混合部署),可以给高性能实例设置更高权重:
upstream llm_backend {
server 10.0.1.10:8000 weight=5; # 强 GPU
server 10.0.1.11:8000 weight=2; # 中等
server 10.0.1.12:8000 weight=1; # 弱 GPU
}
权重越高,分到的请求越多。这种加权轮询(weighted round‑robin)在异构集群中很有用。
健康检查
Nginx 社区版自带被动健康检查:当某个后端连接失败或超时,会暂时将其标记为不可用。可以配合 max_fails 和 fail_timeout 调整敏感度:
upstream llm_backend {
server 10.0.1.10:8000 max_fails=3 fail_timeout=30s;
server 10.0.1.11:8000 max_fails=3 fail_timeout=30s;
}
若需主动探测(例如定期调用 /health 端点),需要 Nginx Plus 或使用 nginx‑healthcheck‑module,但通常被动检查已经足够。
使用 HAProxy 实现更精细长连接控制
HAProxy 在处理持久连接和流量整形方面比 Nginx 更灵活。以下是一段 haproxy.cfg 示例:
global
daemon
maxconn 4096
defaults
mode http
timeout connect 5s
timeout client 300s # 客户端超时
timeout server 300s # 上游超时
option http-server-close
option forwardfor
frontend llm_front
bind *:80
default_backend llm_servers
backend llm_servers
balance leastconn
option httpchk GET /health
server llm1 10.0.1.10:8000 check inter 5000
server llm2 10.0.1.11:8000 check inter 5000
server llm3 10.0.1.12:8000 check inter 5000
这里也使用了 leastconn 算法,并启用了主动健康检查(option httpchk),每 5 秒探测一次 /health 端点。
会话保持与有状态推理
多轮对话如果使用 KV‑Cache 保存在实例内存中,后续请求必须发往同一台实例,否则会缓存丢失导致重复计算。实现会话保持(Session Persistence)的常用方式:
- 基于客户端 IP:
ip_hash(Nginx)或source(HAProxy),但 NAT 环境下同一 IP 可能对应多个用户,且 IP 变化会断开。 - Cookie 插入:由负载均衡器下发 Cookie,用户后续请求携带该 Cookie 路由到固定后端,更可靠。
Nginx 中使用 ip_hash 示例:
upstream llm_backend {
ip_hash;
server 10.0.1.10:8000;
server 10.0.1.11:8000;
}
HAProxy 的 Cookie 持久化:
backend llm_servers
balance leastconn
cookie SRV insert indirect nocache
server llm1 10.0.1.10:8000 cookie llm1 check
server llm2 10.0.1.11:8000 cookie llm2 check
对于无状态推理或使用了外部缓存(如 Redis)的部署,可以不用会话保持,保持均匀分布即可。
自研网关的考量
当需要按 prompt 长度或模型类型动态路由时,可以写一个轻量级网关(Go/Python/Node.js)。核心逻辑:解析请求内容(可能需要少量解码),决定发往哪个实例池。例如,短 prompt 发给小模型,长 prompt 发给大模型。
虽然灵活,但要注意:
- 自行处理连接池、重试、超时,避免增加额外延迟。
- 流式响应需要透传 SSE 数据,确保网关自身不缓冲。
- 与成熟的 Nginx/HAProxy 相比,开发与维护成本要高得多,建议只在有明确定制需求时才使用。
监控与可观测性
均匀分发不代表均匀负载。必须监控每个实例的:
- 活跃连接数:由负载均衡器暴露的统计端点获取。
- GPU 利用率 / 显存占用:通过 Prometheus + DCGM 采集。
- 请求延迟百分位数(P99):识别是否有个别实例慢。
结合这些指标可以动态调整权重,或引入更智能的负载感知路由(如 Nginx Plus 的 least_time 算法,或使用 Envoy 的自定义负载策略)。
最佳实践总结
- 首选最少连接策略:比简单轮询更能应对 LLM 请求时长波动。
- 确保流式响应通透:关闭代理缓冲,设置足够长的超时。
- 异构集群使用权重分发:让高性能 GPU 承担更多请求。
- 按需开启会话保持:仅当多轮对话缓存必须落在本地时使用,否则保持无状态以获得最佳均匀性。
- 实施健康检查:自动踢掉不健康的后端,保证服务可用性。
- 监控后端真实负载:不要让负载均衡器“瞎指挥”,结合 GPU 指标进行动态调整。
结语
LLM 负载均衡的核心不在于复杂算法,而在于理解推理流量的长连接、不均匀耗时特性,并采取相应的分发策略、超时配置和流式支持。从 Nginx 的最少连接开始,你就能让多个推理实例协同工作,获得接近线性的性能扩展。当业务规模扩大后,再逐步引入更精细的健康检查、权重调整和智能路由,即可平稳撑起爆发的 AI 请求。