LLM 负载均衡:在前端均匀分发推理请求

FreeGuideOnline 最新 2026-06-29

负载均衡 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_failsfail_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)的常用方式:

  • 基于客户端 IPip_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 的自定义负载策略)。

最佳实践总结

  1. 首选最少连接策略:比简单轮询更能应对 LLM 请求时长波动。
  2. 确保流式响应通透:关闭代理缓冲,设置足够长的超时。
  3. 异构集群使用权重分发:让高性能 GPU 承担更多请求。
  4. 按需开启会话保持:仅当多轮对话缓存必须落在本地时使用,否则保持无状态以获得最佳均匀性。
  5. 实施健康检查:自动踢掉不健康的后端,保证服务可用性。
  6. 监控后端真实负载:不要让负载均衡器“瞎指挥”,结合 GPU 指标进行动态调整。

结语

LLM 负载均衡的核心不在于复杂算法,而在于理解推理流量的长连接、不均匀耗时特性,并采取相应的分发策略、超时配置和流式支持。从 Nginx 的最少连接开始,你就能让多个推理实例协同工作,获得接近线性的性能扩展。当业务规模扩大后,再逐步引入更精细的健康检查、权重调整和智能路由,即可平稳撑起爆发的 AI 请求。