Nginx 反向代理与负载均衡
Nginx 反向代理与负载均衡
在现代复杂的Web架构中,Nginx不仅仅是一个高性能的Web服务器,更是实现反向代理和负载均衡的关键组件。它能够有效地将客户端请求转发到后端服务器,并根据预设策略将流量分发到多个服务器,从而提高应用的性能、可用性和可伸缩性。本章将深入探讨Nginx的反向代理和负载均衡功能。
核心概念
- 反向代理:代理服务器接收客户端请求,然后将请求转发给内部网络中的一台或多台服务器,并将从服务器得到的结果返回给客户端。客户端并不知道它访问的是代理服务器。
- 负载均衡:将网络流量分发到多个服务器上,以避免单个服务器过载,提高系统的吞吐量和响应速度。
- 上游服务器 (Upstream Server):指Nginx代理的后端服务器,通常是应用服务器(如Tomcat, Node.js, Python等)。
- 健康检查:Nginx定期检查后端服务器的可用性,将不可用的服务器从负载均衡池中移除。
1. Nginx 反向代理
反向代理是Nginx最常用且强大的功能之一。它充当客户端和后端服务器之间的中间人,隐藏了后端服务器的真实IP和端口,增强了安全性,并提供了统一的访问入口。
1.1 基本反向代理配置
使用 proxy_pass
指令可以轻松实现反向代理。它通常配置在 location
块中。
http {
server {
listen 80;
server_name api.example.com;
location / {
# 将所有请求代理到后端服务器
proxy_pass http://backend_server_ip:8080;
# 配置代理请求头,确保后端服务器能获取到客户端真实IP等信息
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 X-Forwarded-Proto $scheme;
}
}
}
常用 proxy_set_header
指令:
Host
:将客户端请求的Host
头转发给后端服务器。如果后端服务器需要根据Host
头来区分不同的虚拟主机,这个非常重要。X-Real-IP
:将客户端的真实IP地址传递给后端服务器。X-Forwarded-For
:记录客户端IP地址和所有代理服务器的IP地址链。如果请求经过多个代理,这个头会包含所有中间代理的IP。X-Forwarded-Proto
:记录客户端请求使用的协议(HTTP或HTTPS)。X-Forwarded-Host
:记录客户端请求的原始Host头。
1.2 路径重写与匹配
proxy_pass
的行为会根据 location
块的匹配方式以及 proxy_pass
URL是否带URI而有所不同。
1.2.1 proxy_pass
URL不带URI
当 proxy_pass
后面的URL不带URI时,Nginx会将 location
匹配到的URI部分直接附加到 proxy_pass
的URL后面。
server {
listen 80;
server_name app.example.com;
location /api/ {
proxy_pass http://backend_api_server:8080; # 注意:这里没有 /api/
}
# 访问 http://app.example.com/api/users
# 代理到 http://backend_api_server:8080/api/users
}
1.2.2 proxy_pass
URL带URI
当 proxy_pass
后面的URL带URI时,Nginx会将 location
匹配到的URI部分替换为 proxy_pass
的URI。
server {
listen 80;
server_name app.example.com;
location /api/ {
proxy_pass http://backend_api_server:8080/v1/; # 注意:这里有 /v1/
}
# 访问 http://app.example.com/api/users
# 代理到 http://backend_api_server:8080/v1/users
location /static/ {
proxy_pass http://static_server:9000/assets/; # 将 /static/ 替换为 /assets/
}
# 访问 http://app.example.com/static/css/style.css
# 代理到 http://static_server:9000/assets/css/style.css
}
1.2.3 使用 rewrite
指令
对于更复杂的URI重写需求,可以使用 rewrite
指令配合 proxy_pass
。
server {
listen 80;
server_name old.example.com;
location /old-path/ {
# 将 /old-path/xxx 重写为 /new-path/xxx,然后代理
rewrite ^/old-path/(.*)$ /new-path/$1 break;
proxy_pass http://backend_server:8080;
}
# 访问 http://old.example.com/old-path/page.html
# 代理到 http://backend_server:8080/new-path/page.html
}
break
标志表示停止处理当前的 rewrite
规则,并继续在当前 location
块中处理请求。
1.3 代理缓存
Nginx可以缓存后端服务器的响应,减少对后端服务器的请求,提高响应速度。
http {
# 定义代理缓存路径和大小
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=my_cache:10m inactive=60m max_size=1g;
server {
listen 80;
server_name cache.example.com;
location / {
proxy_pass http://backend_server:8080;
proxy_cache my_cache; # 启用缓存
proxy_cache_valid 200 302 10m; # 缓存200和302状态码的响应10分钟
proxy_cache_valid 404 1m; # 缓存404状态码的响应1分钟
proxy_cache_key "$scheme$request_method$host$request_uri"; # 定义缓存键
proxy_cache_min_uses 1; # 至少被请求1次后才缓存
proxy_cache_bypass $http_pragma $http_authorization; # 不缓存带有Pragma或Authorization头的请求
add_header X-Proxy-Cache $upstream_cache_status; # 在响应头中显示缓存状态
}
}
}
常用代理缓存指令:
proxy_cache_path
:定义缓存的存储路径、目录层级、内存区域大小、非活动时间、最大缓存空间。proxy_cache
:指定使用的缓存区域。proxy_cache_valid
:定义不同HTTP状态码的缓存有效期。proxy_cache_key
:定义生成缓存键的规则,确保不同请求有不同的缓存。proxy_cache_min_uses
:请求多少次后才缓存。proxy_cache_bypass
:在特定条件下不使用缓存,直接转发请求到后端。proxy_cache_revalidate
:在缓存过期时,使用If-Modified-Since
和If-None-Match
头向后端验证。proxy_cache_use_stale
:当后端服务器不可用时,允许Nginx返回过期的缓存内容。
2. Nginx 负载均衡
负载均衡是Nginx的另一个核心功能,它通过将请求分发到多个后端服务器来提高系统的并发处理能力和可靠性。
2.1 upstream
模块
upstream
块用于定义一组后端服务器,然后在 proxy_pass
中引用这个 upstream
名称。
http {
# 定义一个名为 backend_servers 的上游服务器组
upstream backend_servers {
server 192.168.1.100:8080 weight=5;
server 192.168.1.101:8080;
server 192.168.1.102:8080 backup;
server 192.168.1.103:8080 down;
}
server {
listen 80;
server_name myapp.example.com;
location / {
proxy_pass http://backend_servers; # 引用上游服务器组
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
upstream
服务器参数:
weight=number
:设置服务器的权重,权重越高,被分配到的请求越多,默认为1。max_fails=number
:在fail_timeout
时间内,如果与服务器通信失败达到指定次数,则认为服务器不可用。默认为1。fail_timeout=time
:服务器被标记为不可用后的持续时间,默认为10秒。在此期间,Nginx不会向该服务器发送请求。backup
:将服务器标记为备用服务器。当所有非备用服务器都不可用时,请求才会被发送到备用服务器。down
:将服务器标记为永久不可用。通常用于维护期间。max_conns=number
:限制Nginx与上游服务器的最大并发连接数。当达到此限制时,Nginx将不再向该服务器发送请求,直到连接数下降。
2.2 负载均衡算法
Nginx支持多种负载均衡算法,可以通过 upstream
块中的指令进行配置。
2.2.1 轮询 (Round Robin) - 默认
这是Nginx默认的负载均衡算法。请求按时间顺序逐一分配到不同的后端服务器,如果服务器宕机,会自动从轮询列表中剔除。
upstream backend_servers {
server 192.168.1.100:8080;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
}
2.2.2 加权轮询 (Weighted Round Robin)
在轮询的基础上,根据服务器的权重分配请求。权重越大,被分配到的请求越多。
upstream backend_servers {
server 192.168.1.100:8080 weight=3;
server 192.168.1.101:8080 weight=1;
}
2.2.3 IP Hash (ip_hash)
根据客户端的IP地址进行哈希计算,将同一个客户端的请求始终发送到同一个后端服务器。这有助于保持会话粘性。
upstream backend_servers {
ip_hash;
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
注意:如果后端服务器数量发生变化,或者某个服务器宕机,ip_hash
可能会导致部分客户端的会话中断。
2.2.4 最少连接 (least_conn)
将请求发送到当前连接数最少的后端服务器。适用于请求处理时间差异较大的场景。
upstream backend_servers {
least_conn;
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
2.2.5 最短响应时间 (least_time) - Nginx Plus
将请求发送到平均响应时间最短且活跃连接数最少的服务器。此功能通常在Nginx Plus版本中提供。
upstream backend_servers {
least_time header; # 或 last_byte
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
2.2.6 Hash (hash) - Nginx Plus
根据用户定义的键(如URI、请求头等)进行哈希计算,将请求分发到后端服务器。此功能通常在Nginx Plus版本中提供。
upstream backend_servers {
hash $request_uri consistent; # 根据URI进行哈希,consistent表示一致性哈希
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
2.3 会话保持 (Session Persistence)
对于需要会话保持的应用(如购物车、用户登录状态),除了 ip_hash
,还可以使用其他方式实现。
2.3.1 基于Cookie的会话保持
Nginx可以向客户端设置一个特殊的Cookie,记录其访问的后端服务器,后续请求根据Cookie将请求转发到同一服务器。
upstream backend_servers {
server 192.168.1.100:8080;
server 192.168.1.101:8080;
# Nginx Plus 提供的 sticky 指令
# sticky learn
# create=$cookie_sessionid
# lookup=$cookie_sessionid
# zone=client_sessions:1m;
}
对于开源版Nginx,通常需要在后端应用层面实现会话共享(如使用Redis、Memcached等),或者使用 ip_hash
。
2.4 健康检查
Nginx的 upstream
模块自带简单的健康检查功能,通过 max_fails
和 fail_timeout
参数实现。当后端服务器在指定时间内失败次数达到阈值,Nginx会将其标记为不可用。
对于更高级的健康检查(如HTTP状态码检查、内容检查),通常需要Nginx Plus或第三方模块(如 nginx_upstream_check_module
)。
# 示例:使用第三方模块进行健康检查
# http {
# upstream backend_servers {
# server 192.168.1.100:8080;
# server 192.168.1.101:8080;
# check interval=3000 rise=2 fall=5 timeout=1000 type=http;
# check_http_send "GET /health HTTP/1.0\r\nHost: example.com\r\n\r\n";
# check_http_expect_alive http_2xx http_3xx;
# }
# }
总结
本章详细介绍了Nginx作为反向代理和负载均衡器的核心功能:
- 反向代理:通过
proxy_pass
指令实现请求转发,并学习了proxy_set_header
配置,以及proxy_pass
URL带URI和不带URI的区别,和rewrite
指令的配合使用。 - 代理缓存:配置Nginx代理缓存,有效减轻后端服务器压力,提高响应速度。
- 负载均衡:使用
upstream
模块定义后端服务器组,并深入了解了轮询、加权轮询、IP Hash、最少连接等多种负载均衡算法。 - 会话保持与健康检查:探讨了会话保持的实现方式以及Nginx自带的健康检查机制。
掌握这些功能对于构建高可用、高性能的Web服务架构至关重要。在下一章中,我们将探讨Nginx的安全防护和性能优化策略。