2、反向代理与负载均衡:Nginx反向代理配置、负载均衡算法(轮询、加权、IP哈希)、健康检查机制、Session保持方案

反向代理和负载均衡,说白了就是给后端服务器找个靠谱的“前台”。用户请求先打到Nginx上,Nginx再根据规则分发给后面的真实服务器。我这些年调过的Nginx实例少说也有上百个,今天就把核心配置和那些坑一次性说清楚。

2.1 Nginx反向代理基础配置

反向代理的配置其实不复杂,核心就两个指令:proxy_passupstream。前者定义转发目标,后者定义后端服务器组。

先看一个最基础的例子:

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.1proxy_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丢失。

避坑指南: 我曾经在某个高并发项目里用了IP哈希,结果某个办公楼出口IP的请求全打到了一台服务器上,直接把那台机器打爆了。IP哈希适合小规模场景,大规模集群慎用。

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=2fail_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次失败就摘掉。为什么 fallrise 大?因为网络抖动可能导致偶尔失败,我不想因为一次超时就误判。

核心要点: 健康检查的接口一定要轻量。我见过有人用首页做健康检查,结果首页加载了数据库数据,数据库一慢,健康检查全挂了,整个集群被误判为不可用。建议单独写一个 /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依然有效。

我的经验: 如果非要使用Nginx自带的Session保持,可以用 sticky 模块。它会在响应头里种一个Cookie,后续请求根据Cookie值路由到同一台服务器。配置如下:
upstream backend { sticky cookie srv_id expires=1h domain=.example.com path=/; }

2.5 知识体系图

下面这张图展示了本章的核心逻辑,我画了很久,希望能帮你理清思路:

反向代理与负载均衡核心组件 Nginx反向代理 基础配置(proxy_pass、header) 负载均衡算法 健康检查机制 Session保持方案 轮询 加权轮询 IP哈希 被动检查 主动检查 IP哈希 Cookie植入 Redis共享 核心原则:高可用 + 高性能 + 数据一致性 推荐方案:加权轮询 + 主动健康检查 + Redis共享Session

这张图把本章的核心知识点串起来了。你从Nginx反向代理出发,往左走是负载均衡算法,往右走是健康检查,往下走是Session保持。每个分支都有具体的实现方案。我个人建议你先把加权轮询和主动健康检查搞明白,这两个是生产环境最常用的。

好了,反向代理和负载均衡的核心内容就这些。配置不难,难的是根据业务场景选对方案。记住一点:没有银弹,只有最适合你当前场景的方案。

专注资料整理