大数跨境
0
0

Nginx | 核心知识150讲,百万并发下性能优化之反向代理流程与负载均衡模块介绍笔记

Nginx | 核心知识150讲,百万并发下性能优化之反向代理流程与负载均衡模块介绍笔记 全栈工程师修炼指南
2025-12-04
0
导读:本文将主要介绍 Nginx 中反向代理与负载均衡相关基础知识,梳理了HTTP反向代理请求处理流程,浅析了负载均衡在 http 与 stream 下相关 upstream 模块以及其 server 指令

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ]


📢 大家好,我是 WeiyiGeek一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 🚀,若此文对你有帮助,一定记得倒点个关注⭐与小红星❤️,以及文中广告,收藏学习不迷路 😋 。


0x00 前言简述

好久没有发 Nginx 相关文章了,不知道各位看友是否已经 abandon ,最近正好整理了一些,后面几天将会逐步发布,还请大家持续关注我哟?上一章《[Nginx | 核心知识150讲之变量介绍与实践应用笔记]》,作者介绍了 Nginx 常用变量及其相关模块,通过实践案例配置使用相关模块,例如 secure_link、split_clients、split_geoip2 模块,想必各位看友都有所收获吧!趁着大家的学习激情,本章节将继续介绍 Nginx 中比较常用且核心的功能,即反向代理与负载均衡相关知识,本文将先介绍反向代理(七层、四层)与负载均衡的基础知识,再讲解了 Nginx 反向代理中引入负载均衡、以及缓存配置的相关配置指令,最后通过实践案例演示其使用。

温馨提示:若文章代码块中存在乱码或不能复制,请联系作者,也可通过文末的阅读原文链接,加入知识星球中阅读,原文链接:https://articles.zsxq.com/id_a2l6pacq0flr.html


基础知识

Nginx 反向代理与负载均衡是 Nginx 两大核心功能,在互联网行业中,无论是大型网站还是小型应用,都离不开这两个功能的支持。通过反向代理和负载均衡,Nginx 能够有效地管理大量并发请求,提高系统的稳定性和性能表现。

在 Nginx 中,反向代理和负载均衡是通过配置 proxy_pass 指令实现的,通过将请求转发到后端服务器组(upstream),Nginx 能够根据不同的策略(如轮询、最少连接等)来分配流量,从而实现负载均衡和高可用性。


什么是反向代理?

反向代理(Reverse Proxy)是一种网络代理服务器,它位于客户端和实际服务之间。当客户端请求到达反向代理时,它会将请求转发到后端的一个或多个真实服务器上,并将从这些服务器返回的响应传递给原始请求者。反向代理隐藏了真实的服务器地址,增强了安全性,并提供了额外的功能,如负载均衡、缓存和加密处理。

知识扩展: 除了反向代理,还有一种正向代理指的是客户端通过一个代理服务器访问目标服务器的过程。正向代理隐藏了真实的请求方身份,主要用于绕过网络限制、缓存数据等目的,网络术语中科学上网(FQ)便采用正向代理居多。


什么是负载均衡?

负载均衡(Load Balancing)是一种将网络流量或工作负载分配到多个服务器或资源上的技术,旨在提高系统的可用性、可靠性和性能。通过分散请求到不同的后端服务上,负载均衡可以避免单一节点过载,从而防止系统崩溃,并确保用户访问正常。

简单来说,负载均衡的作用是构建应用服务集群,支持容灾与动态扩容,提升系统应用服务可用性。


原理介绍

负载均衡(Load Balancing)

当 Nginx 作为反向代理时,它会接收来自客户端的请求,并根据配置的策略将请求转发到后端服务器。负载均衡是实现这一功能的关键部分,它决定了如何分配流量到不同的后端服务器上,以及当后端服务器出现故障时,如何进行故障转移。

例如,下图客户端通过Nginx访问应用服务器。

  • 1.客户端一选择应用服务器一(绿色线)
  • 2.客户端二选择应用服务器三(深绿色线)
  • 3.应用服务器二宕机(灰色)
  • 4.新增应用服务器四用于扩容
weiyigeek.top-Nginx负载均衡示例图
weiyigeek.top-Nginx负载均衡示例图

Nginx 支持多种负载均衡算法,包括轮询(Round Robin)、最少连接数(Least Connections)和IP哈希(简单实现会话粘连)等,负载均衡算法此处又涉及到 Nginx 在 AKF 扩展立方体上的应用。

  • X轴扩展:又称水平扩展,它是成本最低的扩容方式,要求服务无状态,使得所有服务实例完全等同地处理用户请求,Nginx 中轮询(Round Robin)、最少连接数(Least Connections)就是典型的X轴负载均衡算法,其缺点是无法解决单台服务器数据量过大的问题。

  • Y轴扩展:又称垂直扩展,它是成本最高的扩容方式,按功能对服务进行拆分(微服务思想),需要代码修改与大量重构并要求服务有状态,所有服务实例需共享数据,能有效降低单个服务的数据容量压力。

  • Z轴扩展:又称功能扩展,它是介于X、Y轴之间的扩容方式,要求服务有状态,但不完全等同于垂直拆分,而是在原有基础上增加新的功能模块,可根据用户信息(IP地址、用户名)进行分流将请求转发到某个特定服务或集群上,Nginx 中提供多种基于哈希的负载均衡算法。

b932c1b301d49dadac93205274552555.png
weiyigeek.top-Nginx在AKF扩展立方体上的应用图

反向代理(Reverse Proxy )

Nginx 支持多种反向代理协议,包括 HTTP、Websocket 和 TCP 等。当配置为反向代理时,Nginx 能够接收客户端的请求并将其转发到后端服务器上,同时将服务器的响应返回给原始请求者。

例如,由下图可在 Nginx 反向代理分为七层反向代理(应用层)和四层反向代理(传输层)。

  • 四层反向代理:由 Nginx 的 stream 模块支持,能够对TCP和UDP协议进行反向代理,优点转发性能好,缺点协议本身业务特性少,Nginx 干预能力有限,实现相对简单。

  • 七层反向代理:由 Nginx 的 http 模块支持,能够对众多的协议进行反向代理,优点协议本身业务特性丰富,Nginx 干预能力强,实现相对复杂,例如:根据HTTP方法(GET/POST等)/URL路径/请求头等进行分流, 此外可将 HTTP 请求转换为 memcached、gRPC、FastCGI、WebSocket 等协议的请求。

1c52c67f04f0962f330cdb2ed6a7e428.png
weiyigeek.top-Nginx反向代理协议支持图

知识扩展到 Nginx 反向代理,除了负载均衡,还不得不提到缓存机制,通常分为两类缓存 时间缓存 和 空间缓存,前者通过设置 HTTP 响应头中的 Expires 或 Cache-Control 来实现将内容缓存至客户端中,后者则是将静态资源(如图片、CSS文件等)缓存在本地磁盘上,减少对后端服务器的请求次数。

97f6700871632082438afd979fa72dce.png
weiyigeek.top-Nginx里的两种缓存机制图

Nginx 中 HTTP 反向代理流程

下图展示了 Nginx 中 proxy 模块反向代理的处理流程,包括请求接收、缓存检查、上下游请求与响应的缓冲机制、负载均衡选择及连接复用等核心环节。通过这些步骤,Nginx 能够有效地将客户端请求转发给后端服务器,并将服务器的响应返回给客户端,从而实现反向代理的功能,这一流程对于理解 Nginx 的工作原理和优化配置至关重要。

  • 流程01.反向代理在 Nginx 十一阶段之一的 content 阶段生效,此阶段负责生成发往用户的响应内容,当配置使用了 proxy_pass 指令时,反向代理流程在此阶段被触发。

  • 流程02.反向代理流程中,首先会检查是否有缓存可用,如果有则直接返回响应, 无需向上游发起请求。如果没有缓存或缓存过期,则会进入下一步处理。

  • 流程03.未命中缓存时,将进入完整的反向代理流程,首先是首先生成发往上流的HTTP头部和包体(body),而非立即建立TCP连接,因为提前生成请求可避免对上游应用服务器造成不必要的连接压力,延迟建连可优化资源使用。

  • 流程04.判断 proxy_request_buffering 指令控制是否先将用户请求的完整包体缓存后再处理,缺省为 on 表示启用缓冲 Nginx 会先读取完整的请求包体并存储至内存或磁盘。

    • 开启场景(on):上游服务并发处理能力弱于 Nginx  c 时,若边接收边转发,会导致与上游服务器的连接长时间保持,消耗其有限的并发连接资源。
    • 关闭场景(off):上游服务不敏感于并发连接数,可关闭此功能,然后采用流式转发,提升响应实时性,但可能增加内存压力。
  • 流程05.反向代理流程中,Nginx 会根据负载均衡算法(包括哈希(hash)、轮询(round robin)、最少连接(least_conn)等)选择  upstream 块中 server 指令定义的上游服务器。

  • 流程06.根据所选服务器参数建立TCP连接,并可通过多种指令配置连接行为,如超时、重试等。

  • 流程07.发送请求到上游服务器,若启用了 proxy_request_buffering ,则在接收完全部请求体后一次性发送,否则采用边读边发的方式进行流式传输,两种发送方式会对服务器内存产生影响,缓冲模式内存可控,流式模式因上下游速率差异导致更高内存占用。

  • 流程08.接收上游响应头部,在接收到完整的响应头部后,进入到下一步处理。

  • 流程09.处理响应头部,接收完成后根据配置指令处理响应头部信息,与此同时 $upstream_header_time 变量记录接收响应头部所耗时间。

  • 流程10.根据 proxy_buffering 指令控制下游响应方式,默认开启(on)表示接收完整的上游响应包体,暂存于临时文件(目的:节约内存)或内存,再统一向客户端发送响应头部和包体。

    • 开启场景(on):快速接收上游响应,释放上游连接,独立控制向客户端的发送,提高系统吞吐。
    • 关闭场景(off):采用流式传输,边接收上游响应边转发给客户端, 受限于下游网速,若都客户端都在内网则影响不大。
  • 流程11.缓存写入判断,响应发送完毕后,判断是否开启缓存(cache),若开启且当前响应可被缓存,则将其加入缓存系统。

  • 流程12.反向代理流程结束,根据配置决定是否关闭或复用与上游的连接,复用连接通过 keepalive 机制实现,提升性能,至此整个请求处理完毕。

da4ffd56a5afc52465bbedef11b8698e.png
weiyigeek.top-Nginx中HTTP 反向代理流程图

由上述可知 proxy 反向代理完整处理流程,涵盖缓存检查 → 请求构造 → 包体接收控制 → 负载均衡选服 → 连接建立 → 请求发送 → 响应头接收 → 响应体缓冲控制 → 响应转发 → 缓存写入 → 连接管理

好了,作者这里简单的针对反向代理与负载均衡相关知识做个简单介绍,接下来将根据上述基础知识,通过实践案例演示 Nginx 反向代理与负载均衡模块的具体工作机制。


0x01 Nginx 负载均衡模块指令浅析

Nginx 对 keepalive 长连接行为控制指令

描述:keepalive 相关指令是用于提升连接效率的,特指HTTP协议中的长连接,涉及对浏览器/客户端(client)和上游服务器(upstream)的行为控制,本小节将聚焦于两者进行讲解。

在 client 端 Nginx 已经在 ngx_http_core_module 模块中内置,而在 stream 中则是由 ngx_http_upstream_keepalive_module 默认编译到 Nginx 中,可通过 --without-upstream-keepalive-module 移除,当然通常情况下不会这样操作。


什么是 keepalive?

从字面含义中可知就是保持存活,而在此处则表示多个http请求可复用同一个TCP连接,即浏览器或Nginx服务端只需建立一次TCP连接即可发送多个HTTP请求,其功能优势如下:

  • 减少TCP连接的建立与断开次数,降低握手开销。
  • 减少并发连接数,从而降低服务器内存消耗。
  • TCP拥塞窗口可维持在最佳状态,避免重新慢启动,提升吞吐量同时降低延迟。

从 HTTP 协议头部控制 keepalive?

  • Connection 请求头:由客户端发起,决定是否使用长连接机制,若值为 close 则表示请求处理完毕后即刻关闭连接,若值为 keepalive 则表示复用当前TCP连接接着处理下一条请求,其格式为"Connection: keepalive"
  • Keep-Alive 请求头:由服务端返回,决定与客户端至少保留n秒,其格式为"Keep-Alive: timeout=n"

Nginx 对客户端 keepalive 行为控制的模块指令

ngx_http_core_module 模块中提供的 keepalive_* 相关指令,决定了 客户端与Nginx 服务端之间的连接处于活跃连接,还是单次请求后就马上关闭,还是在一定时间内关闭,正确的设置此指令可提升客户端连接效率,参考链接: https://nginx.org/en/docs/http/ngx_http_core_module.html

# 指令通过配置浏览器参数来控制与表现不佳的浏览器之间的保持活动连接(keep-alive connections),它提供了三个值(msie6、safari 和 none),用于指定哪些浏览器将受到影响,通过设置这些参数,可以优化服务器与不同浏览器之间的通信性能,确保更好的用户体验。
syntax: keepalive_disable none | browser ...;
Default: keepalive_disable msie6;
Context: http, server, location
# 参数
  msie6:当接收到 POST 请求后,将禁用与旧版 MSIE 浏览器的保持活动连接。
  safari:将禁用与 macOS 和类似操作系统上的 Safari 及类似浏览器的保持活动连接。
  none:启用与所有浏览器的保持活动连接。

# 设置可通过单个TCP连接最大能处理的HTTP请求数。在发出最大请求数之后,连接将关闭。为了释放每个连接的内存分配,必须定期关闭连接。因此,使用过高的最大请求数可能会导致过多的内存使用,不建议使用。
Syntax: keepalive_requests number;
Default: keepalive_requests 1000;
Context: http, server, location
# 温馨提示:1.19.10 在及之前,其默认值为 100

# 限制了一个持久连接处理请求的最大时间。一旦达到这个时间,在处理了后续的请求之后,连接就会被强制关闭。
Syntax: keepalive_time time;
Default: keepalive_time 1h;
Context: http, server, location

# 设置一个最小超时,在此期间,服务器端不会关闭保持活动的客户端连接以进行连接重用或正常关闭工作进程。
Syntax: keepalive_min_timeout timeout;
Default: keepalive_min_timeout 0;
Context: http, server, location
This directive appeared in version 1.27.4.

# 第一个参数设置在服务器端与客户端连接保持活动状态的超时时间,若在此时间内无新请求进来则会关闭连接,零值将禁用客户端连接保持活动状态。
# 可选的第二个参数在“Keep-Alive: timeout = time”响应头字段中设置一个值,两个参数可以不同。“Keep-Alive: timeout=time”报头字段被Mozilla和Konqueror识别,MSIE在大约60秒内自行关闭keep-alive连接。
Syntax: keepalive_timeout timeout [header_timeout];
Default: keepalive_timeout 75s;
Context: http, server, location

Nginx 对客户端 keepalive 行为控制的模块指令

在内置的 ngx_http_upstream_module 模块中也有 keepalive 相关指令,用于控制 Nginx 服务端与上游服务器之间的连接行为。

# 设置激活与上游服务器长连接,其中 connections 参数指定了在空闲状态下保持打开状态的连接数。
Syntax: keepalive connections;
Default: —
Context: upstream

# 设置通过一个TCP连接可以处理的最大请求数。
Syntax: keepalive_requests number;
Default: keepalive_requests 1000;
Context: upstream

# 设置限制一个TCP连接处理请求的最长时间,达到时间后立即关闭。
Syntax: keepalive_time time;
Default: keepalive_time 1h;
Context: upstream

# 设置nginx与上游服务器的TCP连接空闲时间,若在时间内无新请求进来便在到达此时间后断开连接。
Syntax: keepalive_timeout timeout;
Default: keepalive_timeout 60s;
Context: upstream

温馨提示:由于 http 1.0 协议中不支持 keepalive 机制,防止客户端与服务端之间出现兼容性问题,可通过在反向代理到上游连接时,设置如下请求头:

proxy_http_version 1.1;
proxy_set_header Connection "";

Nginx 负载均衡 upstream 模块

在 Nginx 中负责于上游服务交互的模块是 upstream 模块,它定义了一个或多个上游服务器组(server group),Nginx 会根据配置的负载均衡算法策略将请求转发到这些服务器的其中一个。

其中 upstream 模块有两种类型,分别是 Stream upstream 和 HTTP upstream, 模块内置缺省的负载均衡算法为轮询(Round Robin)。

  • HTTP upstream:用于七层反向代理,支持HTTP、HTTPS协议, 由 ngx_http_upstream_module 模块提供支持。

  • Stream upstream:用于四层反向代理,支持TCP和UDP协议, 由 ngx_stream_upstream_module 模块提供支持。


ngx_http_upstream_module 模块

描述:该模块用于定义可由 proxy_pass、fastcgi_pass、uwsgi_pass、scgi_pass、memcached_pass 和 grpc_pass 指令引用的服务器组,是 Nginx 实现七层反向代理的内置核心模块,参考地址:https://nginx.org/en/docs/http/ngx_http_upstream_module.html

另外,upstream 模块中子模块顺序决定执行逻辑,可通过在编译 Nginx 源码时执行./configure 脚本生成 ngx_modules.c 文件中的 ngx_modules[] 数组,可以确定各模块的加载顺序,模块按数组中从上到下的顺序依次生效。

cd /usr/local/src/nginx-1.29.0/objs
more ngx_modules.c
ngx_module_t *ngx_modules[] = {
....
    &ngx_http_upstream_hash_module,
    &ngx_http_upstream_ip_hash_module,
    &ngx_http_upstream_least_conn_module,
    &ngx_http_upstream_random_module,
    &ngx_http_upstream_keepalive_module,
    &ngx_http_upstream_zone_module,
....
};

由上 ngx_modules[] 数组中模块加载顺序可知,在配置使用 upstream 模块时,启动时优先检查的模块顺序为haship_hashleast_connrandomkeepalive 和 zone


模块指令

# 定义一组服务器,可用于监听TCP和UNIX域套接字的服务器。
Syntax: upstream name { ... }
Default: —
Context: http

# 定义服务器的地址和其它参数,其中地址可用域名、IP地址或UNIX套接字,若未指定端口缺省 80
Syntax: server address [parameters];
Default: —
Context: upstream
# parameters 参数列表
  weight=number     # 权重,默认为1
  max_conns=number  # 允许的最大连接数,默认为0,表示无限制
  max_fails=number  # 允许失败的次数,默认为1
  fail_timeout=time # 失败尝试间隔时间,默认为10s,其功能是在单位时间内最大失败次数为 max_fails,达到后该service不能访问的时间,每隔设定 time 后会尝试重连接,若后端服务恢复正常,则该服务器权重恢复到正常值。(重点理解)
  backup            # 标记为备用服务器,只有在其他所有非备份服务器都失败时才使用
  down              # 标记为永久不可用,直到下一次配置重新加载
  resolve           # 动态解析服务器地址,每次请求都会重新解析
  drain             # 将服务器置于“耗尽”模式,此模式下只有绑定到服务器的请求才会被代理到服务器。
  service=name      # 启用DNS SRV记录的解析并设置服务名称,必须于 resolve 参数一起使用。
  route=string      # 设置服务器路由名称。
  slow_start=time   # 设置服务器将其权重从零恢复到标称值的时间,在 fail_timeout 时间内限制连接数,缺省值为 0,即禁用慢启动。

# 定义共享内存区的名称和大小,该共享内存区保留工作进程之间共享的组配置和运行时状态。
Syntax: zone name [size];
Default: —
Context: upstream

# 指定一个保存动态可配置组状态的文件,不常用了解即可。
Syntax: state file;
Default: —
Context: upstream

# 允许使用NTLM身份验证代理请求。
# 当客户端发送了以“协商”或“NTLM”开头的“授权”标头字段值的请求,上游连接就绑定到客户端连接
Syntax: ntlm;
Default: —
Context: upstream

# 指定如果在处理请求时无法立即选择上游服务器,则该请求将被放入队列。
Syntax: queue number [timeout=time];
Default: —
Context: upstream

# 配置用于将上游服务器名称解析为地址的名称服务器,可局部或全局配置。
Syntax: resolver address ... [valid=time] [ipv4=on|off] [ipv6=on|off] [status_zone=zone];
Default: —
Context: upstream
# 配置DNS解析的超时时间。
Syntax: resolver_timeout time;
Default: 
resolver_timeout 30s;
Context: upstream

负载均衡算法指令:轮询(Round Robin,缺省)、最少连接数(Least Connections)、IP哈希(IP Hash)等。

# 基于请求传递给活动连接数最少的服务器,受到服务器的权重影响
Syntax: least_conn;
Default: —
Context: upstream

# 基于请求最小的平均响应时间和最少的活动连接数传递给服务器,受到服务器的权重影响
Syntax: least_time header | last_byte [inflight];
Default: —
Context: upstream
# 参数:
# header 表示使用响应头字段作为负载均衡的依据
# last_byte 表示使用最后一个字节的时间

# 基于哈希键值的服务器组指定负载均衡算法。
Syntax: hash key [consistent];
Default: —
Context: upstream

# 基于客户端IP地址哈希的负载平衡方法,客户端IPv4地址的前三个八位字节或整个IPv6地址用作哈希密钥。
Syntax: ip_hash;
Default: —
Context: upstream

# 基于请求传递给随机选择的服务器,同时考虑服务器的权重。
Syntax: random [two [method]];
Default: —
Context: upstream

会话关联(粘连)指令:有三种方法可供选择 cookie、route 和 learn。

# 启用会话关联,这会导致来自同一客户端的请求被传递到一组服务器中的同一服务器。
Syntax: sticky cookie name [expires=time] [domain=domain] [httponly] [samesite=strict|lax|none|$variable] [secure] [path=path];
sticky route $variable ...;
sticky learn create=$variable lookup=$variable zone=name:size [timeout=time] [header] [sync];
Default: —
Context: upstream
# 参数:
  cookie name  # 表示使用cookie进行会话关联,name为cookie的名称
  expires=time # 设置浏览器应保留cookie的时间
  domain=domain # 设置cookie的域
  httponly      # 将 HttpOnly 属性添加到 cookie 中
  samesite=strict | lax | none | $variable# 设置 SameSite 属性
  secure        # 将 Secure 属性添加到 cookie 中
  path=path     # 设置cookie的路径
  route $variable ...  # 表示使用route进行会话关联,$variable为变量名称
  learn create=$variable lookup=$variable zone=name:size [timeout=time] [header] [sync]; # 表示使用learn进行会话关联,create和lookup为变量名称

另外,此模块还内置一些变量(Embedded Variables),例如:

  • $upstream_addr: 上游服务器的地址,可以是IP或域名或unix。
  • $upstream_bytes_received: 从上游服务器接收的字节数。
  • $upstream_bytes_sent: 发送到上游服务器的字节数。
  • $upstream_connect_time: 与上游服务器建立连接的时间,单位为秒。
  • $upstream_header_time: 从上游服务器接收响应头的时间,单位为秒。
  • $upstream_response_time: 从上游服务器接收整个响应的时间,单位为秒。
  • $upstream_response_length: 上游服务器响应的长度。
  • $upstream_queue_time: 请求在上游服务器队列中等待的时间,单位为秒。
  • $upstream_last_server_name: 上游服务器组中最后一个服务器的名称。
  • $upstream_status: 上游服务器响应的HTTP状态码。
  • $upstream_cookie_name 与 $upstream_http_name: 分别用于访问上游服务器返回响应的cookie和HTTP头,例如:$upstream_http_server 表示上游服务器返回的响应头中的 Server 字段的值。
  • $upstream_trailer_name: 用于访问上游服务器响应的尾部头。
  • $upstream_cache_status: 上游缓存状态,例如:MISS、BYPASS、EXPIRED、STALE、UPDATING、REVALIDATED、HIT等。

模块示例

例子1:定义一个名为 backend 的服务器组,包含多种个上游服务器,演示了 upstream 模块的大部分指令,以及以及一个常规的七层反向代理配置。

# 全局 DNS 解析
resolver 10.0.0.1;
upstream dynamic {
# 定义共享内存区,用于存储服务器组的状态信息。
  zone upstream_dynamic 64k;

# 使用 unix socket 方式连接上游服务器
  server unix:/tmp/backend3;
# 指定上游服务器权重为 5
  server backend1.example.com      weight=5;
# 指定上游服务器,在30s时间内限制连接数,fail_timeout
  server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
# 指定上游服务器,最大失败次数为3次,缺省 10s
  server 192.168.10.50             max_fails=3;
  server backend3.example.com      resolve;
# 例如,查找 _http._tcp.backend4.example.com SRV 记录
  server backend4.example.com      service=http resolve;

# 指定备用服务器,只有在其他所有非备份服务器都失败时才使用
  server backup1.example.com:8080  backup;
  server backup2.example.com:8080  backup;

# 指定不可用服务器,直到下一次配置重新加载
  server 192.168.10.51              down;

# 局部 DNS 解析
  resolver 127.0.0.1 [::1]:5353 valid=30s;

# 设置与上游服务器的长连接,最多保持32个空闲的保活连接。(此处了解即可,后续会详细介绍)
  keepalive 32;
}

server {
    location / {
      # 当反向代理使用 HTTP 时,长连接还需设置如下:
      proxy_pass http://dynamic;
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      # 当反向代理使用 FastCGI 时
      # fastcgi_pass fastcgi_backend;
      # fastcgi_keep_conn on;
      health_check;
    }
}

例子2:演示了如何使用 upstream 模块的会话关联指令。

# 方式1.轮询算法,使用 cookie 方式进行会话关联
upstream backend {
  server backend1.example.com;
  server backend2.example.com;
  sticky cookie srv_id expires=1h domain=.example.com path=/;
}

# 方式2.轮询算法,使用 route 方式进行会话关联
# 代理服务器在收到第一个请求时为客户端分配路由。来自此客户端的所有后续请求都将在cookie或URI中携带路由信息。
map $cookie_jsessionid$route_cookie {
  ~.+\.(?P<route>\w+)$ $route;
}
map $request_uri$route_uri {
  ~jsessionid=.+\.(?P<route>\w+)$ $route;
}
upstream backend {
  server backend1.example.com route=a;
  server backend2.example.com route=b;

  sticky route $route_cookie$route_uri;
}

# 方式3.轮询算法,使用 learn 方式进行会话关联
upstream backend {
   server backend1.example.com:8080;
   server backend2.example.com:8081;
   sticky learn
          create=$upstream_cookie_examplecookie
          lookup=$cookie_examplecookie
          zone=client_sessions:1m;
}

温馨提示:如果 upstream 中只有一台服务器,则忽略 max_fails、fail_timeout 和 slow_start参数,这样的服务器永远不会被视为不可用。


例子3.演示 http upstream 模块中相关变量输出到日志文件。

tee proxy_server_rr_vars.conf <<'EOF'
# 定义日志格式,将 upstream 相关变量以json格式输出
log_format json_upvars escape=json '{'
'"@timestamp":"$time_iso8601",'
'"remote_addr": "$remote_addr", '
'"host": "$host", '
'"request_uri": "$request_uri", '
'"upstream_addr": "$upstream_addr", '
'"upstream_connect_time": "$upstream_connect_time", '
'"upstream_header_time": "$upstream_header_time", '
'"upstream_status": "$upstream_status", '
'"upstream_response_time": "$upstream_response_time", '
'"upstream_response_length": "$upstream_response_length", '
'"upstream_bytes_received": "$upstream_bytes_received", '
'"upstream_bytes_sent": "$upstream_bytes_sent", '
'"upstream_http_server": "$upstream_http_server", '
'"upstream_cache_status": "$upstream_cache_status" '
'}';

# 创建上游服务器
upstream backend {
  server 127.0.0.1:8011 weight=2;
  server 127.0.0.1:8012 weight=1;
  keepalive 10;
}

# 创建监听于于反向代理
server {
  listen 80;
  server_name test.weiyigeek.top;
# 指定访问日志路径,并指定日志格式为 json_upvars
  access_log /var/log/nginx/test.log json_upvars;
  error_log test.error.log info;

  location / {
    proxy_pass http://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 Connection "";
    proxy_http_version 1.1;
    proxy_read_timeout 10s;
    proxy_connect_timeout 10s;
  }
}
EOF

# 测速反向代理
for i in $(seq 1 10);doecho -n "user_WeiyiGeek${i}:";curl -H 'X-Forwarded-For: 100.10.2.215' http://test.weiyigeek.top?user=WeiyiGeek${i};sleep 1;done
user_WeiyiGeek1:From 8011 server response!
user_WeiyiGeek2:From 8012 server response!
user_WeiyiGeek3:From 8011 server response!
user_WeiyiGeek4:From 8011 server response!
user_WeiyiGeek5:From 8012 server response!
user_WeiyiGeek6:From 8011 server response!
user_WeiyiGeek7:From 8011 server response!
user_WeiyiGeek8:From 8012 server response!
user_WeiyiGeek9:From 8011 server response!
user_WeiyiGeek10:From 8011 server response!

# 查看日志输出结果
tail -f /var/log/nginx/test.log
{"@timestamp":"2025-12-04T07:45:18+00:00","remote_addr""10.20.172.213""host""test.weiyigeek.top""request_uri""/?user=WeiyiGeek1""upstream_addr""127.0.0.1:8011""upstream_connect_time""0.000""upstream_header_time""0.000""upstream_status""200""upstream_response_time""0.000""upstream_response_length""27""upstream_bytes_received""175""upstream_bytes_sent""169""upstream_http_server""nginx/1.29.0""upstream_cache_status""" }

7a804a8961090ec3102267097848092b.pngweiyigeek.top-访问日志中输出upstream模块变量图

ngx_stream_upstream_module 模块

此模块用于定义可由 proxy_pass 指令引用的服务器组,主要用于 TCP/UDP 反向代理,例如:反向代理到 MySQL 高可用数据库、或者主从场景,当然不限于此。

模块指令

温馨提示:该模块指令与 http upstream 模块基本一致,但是略有精简不同,在学习时注意区分。

# 定义一组服务器。服务器可以监听不同的端口
Syntax: upstream name { ... }
Default: —
Context: stream

# 定义上游服务器。可以指定服务器的地址、端口或unix,其参数http upstream 一致。
Syntax: server address [parameters];
Default: —
Context: upstream

# 定义共享内存区的名称和大小
Syntax: zone name [size];
Default: —
Context: upstream

# 指定一个保存动态可配置组状态的文件,即动态配置 server 指令。
Syntax: state file;
Default: —
Context: upstream

# 基于哈希键值负载均衡算法
Syntax: hash key [consistent];
Default: —
Context: upstream

# 基于最少连接数负载均衡算法
Syntax: least_conn;
Default: —
Context: upstream

# 基于最少时间负载均衡算法
Syntax: least_time connect | first_byte | last_byte [inflight];
Default: —
Context: upstream

# 基于随机负载均衡算法
Syntax: random [two [method]];
Default: —
Context: upstream

# 用于将上游服务器名称解析为地址的名称服务器,参数与 http upstream 一致。
Syntax: resolver address ... [valid=time] [ipv4=on|off] [ipv6=on|off] [status_zone=zone];
Default: —
Context: upstream
# 解析超时时间。默认值为 30s
Syntax: resolver_timeout time;
Default: resolver_timeout 30s;
Context: upstream

ngx_stream_upstream_module 模块支持以下嵌入式变量:

  • $upstream_addr:上游服务器的地址。
  • $upstream_bytes_received:从上游服务器接收的字节数。
  • $upstream_bytes_sent:发送到上游服务器的字节数。
  • $upstream_connect_time:与上游服务器建立连接的持续时间。
  • $upstream_first_byte_time:从上游服务器接收到第一个字节的持续时间。
  • $upstream_last_addr:上游服务器最后一次连接的地址。
  • $upstream_session_time:与上游服务器会话的总持续时间。

参考文档: https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html


模块示例

特别注意:在反向代理 TCP/UDP 协议时,将相关负载均衡以及反向代理配置放在 stream 代码块中,而非 http 代码块里。

# stream 模块
stream {
# 解析DNS记录的服务器地址
  resolver 10.0.0.1;

  upstream dynamic {
    # 定义共享内存区名称和大小
    zone upstream_dynamic 64k;
    
    # 定义上游服务器TCP/UDP协议,并设置权重和故障超时时间等参数
    server backend1.example.com:12345 weight=5;
    server backend2.example.com:12345 fail_timeout=5s slow_start=30s;
    server 192.0.2.1:12345            max_fails=3;
    server backend3.example.com:12345 resolve;
    server backend4.example.com       service=http resolve;
    
    # 定义备份服务器,当主服务器不可用时使用。
    server backup1.example.com:12345  backup;
    server backup2.example.com:12345  backup;
  }

  server {
    listen 12346;
    proxy_pass dynamic;
  }
}


由于文章篇幅原因到此为止,下一章将讲解和实践 Nginx 中常用的几种负载均衡算法。

END

加入:作者【全栈工程师修炼指南】知识星球

『 全栈工程师修炼指南』星球,主要涉及全栈工程师(Full Stack Development)实践文章,包括但不限于企业SecDevOps和网络安全等保合规、安全渗透测试、编程开发、云原生(Cloud Native)、物联网工业控制(IOT)、人工智能Ai,从业书籍笔记,人生职场认识等方面资料或文章。


Q: 加入作者【全栈工程师修炼指南】星球后有啥好处?

✅ 将获得作者最新工作学习实践文章以及网盘资源。

✅ 将获得作者珍藏多年的全栈学习笔记(需连续两年及以上老星球友,也可单次购买) 

✅ 将获得作者专门答疑学习交流群,解决在工作学习中的问题。 

✅ 将获得作者远程支持(在作者能力范围内且合规)。


获取:作者工作学习全栈笔记

作者整理了10年的工作学习笔记(涉及网络、安全、运维、开发),需要学习实践笔记的看友,可添加作者微信或者回复【工作学习实践笔记】,当前价格¥299(会随着笔记持续更新后续会涨价,所以早买早优惠哟),除了获得从业笔记的同时还可进行问题答疑以及每月远程技术支持,希望大家多多支持,收获定大于付出!


 知识推荐 往期文章


若文章对你有帮助,请将它转发给更多的看友,若有疑问的小伙伴,可在评论区留言你想法哟 💬

【声明】内容源于网络
0
0
全栈工程师修炼指南
记录全栈工程师学习之路修炼心得,分享工作实践、网络安全、运维、编程、大数据、云原生、物联网、人工智能以及书籍笔记、人生职场感悟等相关高质量文章。 花开堪折直须折,莫待无花空折枝。 Blog:【https://weiyigeek.top】
内容 589
粉丝 0
全栈工程师修炼指南 记录全栈工程师学习之路修炼心得,分享工作实践、网络安全、运维、编程、大数据、云原生、物联网、人工智能以及书籍笔记、人生职场感悟等相关高质量文章。 花开堪折直须折,莫待无花空折枝。 Blog:【https://weiyigeek.top】
总阅读36
粉丝0
内容589