2、反向代理与负载均衡:Nginx反向代理配置、负载均衡算法(轮询、加权、IP哈希)、健康检查机制、Session保持方案
反向代理和负载均衡,说白了就是给后端服务器找个靠谱的“前台”。用户请求先打到Nginx上,Nginx再根据规则分发给后面的真实服务器。我这些年调过的Nginx实例少说也有上百个,今天就把核心配置和那些坑一次性说清楚。
2.1 Nginx反向代理基础配置
反向代理的配置其实不复杂,核心就两个指令:proxy_pass 和 upstream。前者定义转发目标,后者定义后端服务器组。
先看一个最基础的例子:
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
server {
listen 80;
server_name example.com;
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 这几行一定要带上。我在项目中遇到过好几次,后端拿不到真实客户端IP,排查半天才发现是没传 X-Real-IP。你想想看,后端日志里全是Nginx的内网IP,这谁受得了?
proxy_http_version 1.1 和 proxy_set_header Connection ""。这样能启用HTTP长连接,减少握手开销。尤其在高并发场景下,效果立竿见影。
2.2 负载均衡算法详解
Nginx默认支持三种负载均衡算法,我按使用频率排个序:
| 算法 | 配置方式 | 适用场景 | 我的评价 |
|---|---|---|---|
| 轮询(Round Robin) | 默认,无需配置 | 服务器配置相同 | 最省心,但别指望它智能 |
| 加权轮询(Weighted) | server 192.168.1.10 weight=3; |
服务器性能不均 | 实际项目中最常用 |
| IP哈希(IP Hash) | ip_hash; |
需要Session保持 | 简单粗暴,但小心雪崩 |
轮询算法:Nginx按顺序把请求分给后端。每个服务器机会均等。嗯,这里要注意,如果某台服务器挂了,Nginx会自动把它摘掉,不会继续转发。
加权轮询:我个人习惯用这个。比如我有两台服务器,一台8核16G,一台4核8G,我会给前者设 weight=3,后者 weight=1。这样流量分配更合理。
upstream backend {
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080 weight=1;
server 192.168.1.12:8080 weight=2;
}
IP哈希:这个算法根据客户端IP计算哈希值,同一个IP永远打到同一台服务器。我曾经在一个电商项目中用过它来解决Session问题,效果不错。但有个坑——如果某台服务器挂了,这个IP的请求会重新哈希到其他服务器,导致Session丢失。
2.3 健康检查机制
Nginx自带被动健康检查,也就是转发请求时发现后端挂了,就标记为不可用。但主动健康检查需要借助第三方模块,比如 nginx_upstream_check_module。
先看被动检查的配置:
upstream backend {
server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
}
这里的意思是:连续3次失败,就把服务器标记为不可用,30秒后再尝试。我个人觉得这个配置比较保守,生产环境我一般设 max_fails=2,fail_timeout=10s,这样故障恢复更快。
主动健康检查需要编译时加模块,配置如下:
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_http_send "GET /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
这里 interval=3000 表示每3秒检查一次,rise=2 表示连续2次成功就认为服务器恢复,fall=5 表示连续5次失败就摘掉。为什么 fall 比 rise 大?因为网络抖动可能导致偶尔失败,我不想因为一次超时就误判。
/health 接口,只返回状态码,不做任何业务逻辑。
2.4 Session保持方案
Session保持是个老生常谈的问题。说白了,就是让同一个用户的请求始终打到同一台服务器。这里有几种常见方案:
- IP哈希:前面说过了,简单但不够灵活
- Cookie植入:Nginx在响应里种一个Cookie,后续请求根据Cookie路由
- Redis共享Session:所有服务器共享一个Redis,Session存在Redis里
我个人强烈推荐第三种方案——Redis共享Session。为什么?因为前两种都有单点故障风险。IP哈希如果服务器挂了,Session就丢了。Cookie植入虽然能解决,但实现起来麻烦。
Redis共享Session的配置思路:
# 在应用层配置,比如Spring Boot
spring.session.store-type=redis
spring.redis.host=192.168.1.100
spring.redis.port=6379
这样配置后,所有后端服务器都从同一个Redis读取Session。即使某台服务器挂了,用户的请求打到其他服务器上,Session依然有效。
sticky 模块。它会在响应头里种一个Cookie,后续请求根据Cookie值路由到同一台服务器。配置如下:upstream backend { sticky cookie srv_id expires=1h domain=.example.com path=/; }
2.5 知识体系图
下面这张图展示了本章的核心逻辑,我画了很久,希望能帮你理清思路:
这张图把本章的核心知识点串起来了。你从Nginx反向代理出发,往左走是负载均衡算法,往右走是健康检查,往下走是Session保持。每个分支都有具体的实现方案。我个人建议你先把加权轮询和主动健康检查搞明白,这两个是生产环境最常用的。
好了,反向代理和负载均衡的核心内容就这些。配置不难,难的是根据业务场景选对方案。记住一点:没有银弹,只有最适合你当前场景的方案。