原文:F5 / NGINX 文档团队,HTTP Load Balancing。本文依据 2026 年 10 月 5 日的完整页面翻译整理。© 2026 F5, Inc.,原站保留所有权利,NGINX 为 F5 注册商标;源页没有为这篇文档单独列出开放许可,不能把软件许可自动套到文章上。
把 HTTP 请求分配给多个应用实例,可以改善资源使用、吞吐量、延迟与故障容忍能力。NGINX 与 NGINX Plus 都能执行 HTTP/HTTPS 的七层负载均衡;TCP、UDP 等四层场景则应另看 TCP and UDP Load Balancing。负载均衡不会自动使应用变成无状态系统,认证会话、共享数据和失败重试仍要与应用一起设计。

版本核查说明:原教程部分段落继续按旧产品边界描述 Plus 功能。本文保留所有技术主题及原配置,并依据同日 upstream 指令参考校订:max_conns 从 1.11.5 起不再仅限商业订阅;random 在 1.15.1 出现,基本随机及 two/least_conn 不应一概标成 Plus;动态 DNS 的 resolve 从 1.27.3 起开放;sticky 从 1.29.6 起不再整体限于商业订阅(sync 仍有商业限制);独立的 least_time 从 1.31.0 起开放。发行版可能仍打包旧版本,必须按实际二进制及模块核对。slow_start、queue、ntlm、主动健康检查及 Plus API 等仍有相应商业/模块边界。
把请求代理到一组服务器
在 http 上下文中用 upstream 定义服务器组。组内的 server 指令表示一个上游地址,不要与定义虚拟主机的 server {} 块混淆。域名可能解析到多个地址,因此三条配置不一定只产生三个实际后端。
http {
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com;
server 192.0.0.1 backup;
}
}
这里定义了名为 backend 的上游组。weight=5 是权重,backup 标记备用服务器。把组名交给 proxy_pass,即可让虚拟主机将请求转给该组:
server {
location / {
proxy_pass http://backend;
}
}
原文把两段组合后的基础配置如下,普通节点各使用默认权重,第三个节点备用:
http {
upstream backend {
server backend1.example.com;
server backend2.example.com;
server 192.0.0.1 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
}
其他应用协议应使用自己的 pass 指令,例如 fastcgi_pass、memcached_pass、scgi_pass 或 uwsgi_pass。这些示例是 http 配置片段,不包含完整主配置所需的其他上下文。域名、地址和路径都必须改为自己的实验环境;原文的 192.0.0.1 不能被当成已经可用的后端。
选择负载均衡算法
除默认轮询外,应把算法指令放在 upstream 的 server 列表前面。选择依据是连接时长、请求成本、缓存键和会话要求,不能只看一个“更高级”的名字。
轮询:默认按权重轮流分发
不写算法指令就是加权轮询。权重相同的节点按轮询方式分配请求。
upstream backend {
# no load balancing method is specified for Round Robin
server backend1.example.com;
server backend2.example.com;
}
最少连接:比较活跃连接数
least_conn 将请求发给活跃连接较少的服务器,同时考虑服务器权重。当请求的处理时间差异较大时,连接数可能比单纯请求计数更有参考价值;相同最少连接数的节点还会按加权轮询选择。
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
}
IP Hash:依据客户端地址选择后端
ip_hash 使用 IPv4 地址的前三个字节,或完整 IPv6 地址计算哈希。相同地址通常落到同一服务器,除非该服务器不可用。这不等同于用户身份:多个用户可能共享出口 IP,用户 IP 也可能变化。
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
想临时移除一个节点而保留哈希分布结构,可以标记 down。原文展示以下节点清单:
upstream backend {
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
}
编者注:这段本身没有写 ip_hash;,不能仅靠 down 就获得 IP Hash 行为。若目的是前一段的固定映射,应保留前一段算法指令,再给目标节点加 down。在该节点恢复前,原本分配到它的请求会改投可用节点。
通用哈希:按自定义键选择后端
hash 可以采用字符串、变量或两者的组合,例如来源地址和端口,也可以像下面这样使用请求 URI:
upstream backend {
hash $request_uri consistent;
server backend1.example.com;
server backend2.example.com;
}
consistent 启用 ketama 一致性哈希。增删节点时只需重映射部分键,能减少缓存未命中,适合缓存服务或会积累状态的应用。它减少的是重映射范围,不意味着会自动复制状态或保证任意故障下不丢失会话。
最短时间:结合响应延迟和连接数
least_time 同时参考平均响应时间与活跃连接数,并考虑权重。header 表示接收响应头的时间,last_byte 表示完整响应时间,inflight 还把尚未完成的请求纳入计算。原页把 header 简写成“首字节”,此处按指令参考使用更准确的“响应头”。
upstream backend {
least_time header;
server backend1.example.com;
server backend2.example.com;
}
该算法在 NGINX Plus Release 6 起支持,开源 NGINX 从 1.31.0 起支持;更老的开源发行版不能直接照抄。
随机选择与随机抽取两个节点
random 按权重随机选一个节点。加 two 则先随机挑两个,再用指定方法决定其中一个:least_conn 比较活跃连接数,least_time=header 比较响应头时间,least_time=last_byte 比较完整响应时间。
upstream backend {
random two least_time=last_byte;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
server backend4.example.com;
}
上例使用随机二选一及完整响应时间。版本区别:基本 random 与 two/least_conn 不应被误写为全都只限 Plus;但核对日指令参考仍将 random 中的 least_time 选择方法列为商业能力,不能因为独立 least_time 已开放就推断这个组合也开放。随机二选一适合多台负载均衡器共享同一批后端、各自无法掌握所有请求的环境;单个负载均衡器具有完整观测时可考虑其他策略。
按容量设置权重与备用节点
weight 未指定时为 1。轮询、最少连接和随机等算法都能使用权重。
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com;
server 192.0.0.1 backup;
}
两个主节点权重为 5:1,因此在健康节点、均匀调度等前提下,可以用“每 6 个请求中约 5 个到第一个、1 个到第二个”理解分配比例。backup 不参与正常分配,两个主节点都不可用时才接收请求。不要把这个教学比例当成各种并发、失败、重试和不同算法下逐个请求都严格成立的保证。backup 不能与 hash、ip_hash 或 random 随意组合,指令参考明确列有这种限制。
让恢复的服务器缓慢加入
刚恢复的节点如果马上承受满负荷,可能超时并再次被判失败。Plus 的 slow_start 将有效权重从 0 逐渐恢复到配置权重:
upstream backend {
server backend1.example.com slow_start=30s;
server backend2.example.com;
server 192.0.0.1 backup;
}
30s 表示恢复过程持续 30 秒;默认值 0 禁用慢启动。组中只有一个服务器时,max_fails、fail_timeout 和 slow_start 被忽略,该服务器不会因这些参数被视为不可用。慢启动也有与哈希、随机算法的组合限制,部署前要查对应指令版本。
会话保持:让一段会话回到同一后端
会话保持通过标识会话,把后续请求交给先前选择的服务器。原教程按 Plus 介绍 sticky 的三种方法;在当前参考中 sticky 已从 1.29.6 起开放,但旧版开源 NGINX 仍不能直接使用。旧环境可使用 hash 或 ip_hash 获得相应的分配稳定性,但其语义并不完全等同于完整的会话保持。
Sticky cookie
NGINX 在首次响应中加入用于表示所选服务器的 cookie,后续请求带回 cookie,就可回到对应服务器。
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
srv_id 是 cookie 名;expires=1h 表示浏览器保存一小时;domain 和 path 限定作用范围。这个路由 cookie 不是用户认证凭据,不能用“命中了同一个后端”代替登录校验。原例使用宽泛的父域,且未指定 Secure、HttpOnly、SameSite;实际 HTTPS 部署应根据兼容性和业务范围设置这些属性,尽量缩小域作用范围。
Sticky route
每个后端用 route 标记路线。应用在 cookie 或 URI 中携带对应标识;配置依次查看列出的变量,使用第一个非空值进行路由匹配。
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky route $route_cookie $route_uri;
}
原文先查 $route_cookie,再查 $route_uri。配置完整性:这两个变量不是自动定义的;还要用应用实际的 cookie/URI 规则通过 map 等方式提取,才能构成可加载的配置。不能直接把这一个块视为完整配置,也不应将敏感会话令牌随意放进容易被日志记录的 URL。
Sticky learn
NGINX 从请求和响应中学习“会话标识 → 后端”的对应关系。示例中应用返回 EXAMPLECOOKIE,代理从响应头变量建立映射,再从请求 cookie 查找:
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky learn
create=$upstream_cookie_examplecookie
lookup=$cookie_examplecookie
zone=client_sessions:1m
timeout=1h;
}
create 指定新会话标识从哪里取;lookup 指定后续请求的标识来源;zone=client_sessions:1m 声明一块 1 MiB 共享区保存映射;timeout=1h 表示会话映射的空闲超时。
编者校订:原文说这种方法“不需要在客户端保存任何 cookie”,容易产生误解。更准确的是不必再为负载均衡新增一个专用 cookie;这段示例仍依赖应用的会话 cookie。保存在服务器端的是路由映射,不是说客户端无需发送会话标识。
多台 NGINX 需要同步映射时,相关共享区必须同名,每台都配置 zone_sync,并增加 sync 参数。原文给出以下局部片段,其中末尾右花括号属于外围 upstream:
sticky learn
create=$upstream_cookie_examplecookie
lookup=$cookie_examplecookie
zone=client_sessions:1m
timeout=1h
sync;
}
这不是独立完整配置。sync 仍有商业订阅边界,集群同步还必须限制网络访问。详情见原文引用的 Runtime State Sharing in a Cluster。
限制连接,并决定超额请求如何处理
max_conns 控制到某个上游的同时活跃连接数,默认 0 表示不限制。queue 用于在暂时选不到节点时排队,设置最大排队请求数和等待超时:
upstream backend {
server backend1.example.com max_conns=3;
server backend2.example.com;
queue 100 timeout=70;
}
当无法立即选择服务器时请求进入队列;队列满或等待超时将得到错误,指令参考明确为 502。没有 queue 时,也不能假定请求会自动无限等待。max_conns 本身在现代开源版可用,而这个 queue 示例属于商业能力。
编者校订:原文把 keepalive 情况简写为“忽略限制”。准确说法是 max_conns 限制活跃连接;多 worker 和空闲 keepalive 并存时,活跃加空闲的总连接数仍可能大于此值。若没有共享 zone,限制按每个 worker 分别计算,不能把它当成全实例严格总上限。
健康检查与多个 worker 的共享状态
NGINX 可以根据请求失败暂时避开节点,Plus 还可主动周期探测并让恢复节点重入。被动失败判断、主动探测和应用自身的“就绪”状态并非同一个概念。具体配置见 HTTP Health Checks;原文这里只引用这一主题,没有给出完整探测配置。
如果 upstream 没有 zone,各 worker 各自保留服务器组状态、连接数以及失败计数。某个 worker 认为节点失败,其他 worker 可能尚未观察到同样的失败,继续发请求过去。加入 zone 后,相关配置和计数放进共享内存,多个 worker 才能依据同一份数据作决定。主动健康检查与动态上游管理需要相应共享状态,但仅添加 zone 并不会自动获得 Plus API 或主动检查模块。
原文用 max_fails × worker 数量 说明未共享情况下可能需要更多失败才能被各 worker 识别。这个乘法是解释直觉,不是所有流量分布下恰好如此的全局阈值;每个 worker 仍独立处理自己的 fail_timeout 时间窗。低负载时 least_conn 也会受独立计数影响:两个 worker 可能都认为同一个节点最空闲。高负载会减轻这种偏差,但共享 zone 更直接地解决状态不一致。
共享区该分配多大
没有适合所有环境的固定数值。所需空间取决于会话保持、健康检查、DNS 重解析以及服务器标识方式。原文给出的例子是使用 sticky route 和一次健康检查时,256 KiB 可容纳约 128 个 IP:port 节点,或 88 个解析到单个 IP 的 hostname:port 节点,或 12 个会解析到多个 IP 的 hostname:port 节点。这是特定条件的容量示例,不是内存精确预算或性能保证。
借助 DNS 在运行中更新后端
在 server 上加 resolve,并配置可信 DNS resolver,就能跟踪域名对应地址的变化,无须为每次地址变化重启代理。服务器组必须使用共享内存。
http {
resolver 10.0.0.1 valid=300s ipv6=off;
resolver_timeout 10s;
server {
location / {
proxy_pass http://backend;
}
}
upstream backend {
zone backend 32k;
least_conn;
# ...
server backend1.example.com resolve;
server backend2.example.com resolve;
}
}
resolver 10.0.0.1 指定 DNS 服务器;默认缓存尊重 DNS TTL,valid=300s 改为五分钟;resolver_timeout 10s 约束解析等待;ipv6=off 只使用 IPv4,默认可解析双栈。域名解析到多个 IP 时,这些地址都进入上游组,随后按 least_conn 分配请求。记录变化被解析到后,上游列表随之更新。
原文将这项能力写为 Plus 专属,本文已补充 1.27.3 的开源版本边界。resolver 应位于受信任和受保护的网络,防止 DNS 欺骗;10.0.0.1 只是原文环境地址,不能假定你的网络也有这一服务。
Microsoft Exchange 与 NTLM 连接保持
NGINX Plus Release 7 及以后可以对 Exchange 流量做代理和负载均衡。原文按以下顺序搭建:先在 location 代理到 https://exchange:
location / {
proxy_pass https://exchange;
# ...
}
然后保持 HTTP/1.1 上游连接,并清空 Connection 头:
location / {
# ...
proxy_http_version 1.1;
proxy_set_header Connection "";
# ...
}
在同名 upstream 中开启 ntlm:
http {
# ...
upstream exchange {
zone exchange 64k;
ntlm;
# ...
}
}
再加入实际 Exchange 节点,并按需要选择负载均衡算法;如果使用非轮询算法,应先声明算法,再声明 ntlm:
http {
# ...
upstream exchange {
zone exchange 64k;
ntlm;
server exchange1.example.com;
server exchange2.example.com;
# ...
}
}
下面是源文的完整 NTLM 示例:
http {
# ...
upstream exchange {
zone exchange 64k;
ntlm;
server exchange1.example.com;
server exchange2.example.com;
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/company.com.crt;
ssl_certificate_key /etc/nginx/ssl/company.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass https://exchange;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
}
部署风险:这仍是教学配置。上游节点没有写端口时默认是 80;后端实际提供 TLS 的端口可能是 443,应明确配置,不能因为 proxy_pass 写了 https 就假定 server 地址自动使用正确服务端口。入口 TLS 证书路径也是示意。更重要的是,proxy_pass https://... 表示加密传输,不等于自动验证上游证书;应核对 proxy_ssl_verify、受信 CA、SNI 与证书名称。
例如,以下是与原文有意不同的安全配置片段:明确上游 TLS 端口并启用证书验证。它假定两台后端都持有对 exchange.example.com 有效的证书,实际名称与 CA 文件必须替换为真实受控配置;这段没有包含入口证书和完整虚拟主机设置,也未测试。
upstream exchange {
zone exchange 64k;
ntlm;
server exchange1.example.com:443;
server exchange2.example.com:443;
}
# 放在对应 server 块内
location / {
proxy_pass https://exchange;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/nginx/trust/upstream-ca.pem;
proxy_ssl_server_name on;
proxy_ssl_name exchange.example.com;
}
NTLM 需要将上游连接与客户端连接关联起来,以保留认证上下文;它仍是商业功能。新版本的连接默认值可能已经变化,保留显式 HTTP/1.1 设置有利于说明原教程意图,但不能省略对目标版本的核查。进一步部署细节见原文的 Exchange 专项指南。
用 Plus API 动态管理上游
NGINX Plus API 可查看所有节点或单个节点、修改参数,以及增删服务器。这里只介绍能力,具体步骤见 Configuring Dynamic Load Balancing with the NGINX Plus API。管理接口必须限制到受控访问范围并设置认证/授权,不能因为它属于负载均衡配置就暴露给公网。
本文未加载配置、未重启 NGINX、未发流量、未压测或连接任何 Exchange 服务。示例中的响应比例、故障切换和恢复过程都是原理及预期行为,实际部署仍需在隔离环境核对语法、版本、TLS、超时、重试及会话语义。












暂无评论内容