Nginx负载均衡需结合Java生产实践:策略选型(如ip_hash保会话、least_conn适配长连接)、session共享方案(redis或JWT)、proxy_next_upstream精准重试、主动健康检查防假死。

Java后端面试中问到 Nginx 负载均衡策略,不是让你背诵定义,而是考察你是否真在生产环境调过、改过、踩过坑。Nginx 本身不属 Java 技术栈,但 Java 服务部署在它后面时,它的调度逻辑直接影响服务的可用性、会话一致性、扩容弹性——这些才是面试官想听的实战判断。
upstream 块里写错策略名,Nginx 直接启动失败
Nginx 不会静默降级,upstream 中指定不存在的负载均衡算法(比如手误写成 least_connction 或 ip_hashh),nginx -t 就会报错:
nginx: [emerg] invalid parameter "least_connction" in /etc/nginx/conf.d/app.conf:12
常见合法策略只有 5 种(Nginx 1.23+): round_robin(默认,不需显式写)、least_conn、ip_hash、hash $request_uri consistent、random(需 random two 或 random two least_conn 等组合)。注意:
-
ip_hash只支持 IPv4 的前 3 段哈希,IPv6 默认不兼容,要加hash $binary_remote_addr consistent;才能真正按客户端 IP 稳定路由 -
hash $request_uri对带 Query 参数的请求敏感,/api/user?id=1和/api/user?id=2会被散列到不同后端——如果业务依赖 URI 局部一致性(如文件分片上传),得改用hash $uri(去掉 query) -
least_conn不是“最少请求数”,而是“当前活跃连接数最少”,对长连接(WebSocket、gRPC 流)更真实,但对短连接压测时可能不如预期均衡
Java 应用启用了 Session,却配了 round_robin,结果登录态频繁丢失
这是高频翻车点。Spring Boot 默认用内存存储 HttpSession,没做共享;Nginx 若用轮询,用户第二次请求落到另一台机器,session.getId() 已失效,request.getSession(false) 返回 null。
立即学习“Java免费学习笔记(深入)”;
解决路径不是“换策略”,而是明确取舍:
- 若必须保留内存 Session → 必须配
ip_hash或hash $cookie_JSESSIONID(前提是前端带 Cookie) - 若要水平扩展 → 改用
spring-session-data-redis,此时round_robin反而是最稳妥选择,无状态才可靠 - 若用 JWT 替代 Session → 同样回归
round_robin,且应关掉 Nginx 的proxy_cookie_path重写,避免干扰 Token 透传
proxy_next_upstream 配少了,超时或 502 不重试,Java 接口毛刺率飙升
默认情况下,Nginx 只在后端返回 error(连接拒绝)、timeout(连接超时)时才尝试下一个 upstream server。但 Java 应用常见问题如 503 Service Unavailable(Tomcat 线程池满)、502 Bad Gateway(响应体过大被截断)、甚至 408 Request Timeout(应用处理慢),默认都不触发重试。
建议显式补全:
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
但要注意副作用:
- 开启
http_500后,所有后端抛出未捕获异常的请求都会重试——如果 Java 侧有非幂等操作(如扣库存),重复提交会导致资损 -
proxy_next_upstream_tries 3控制最大重试次数,别设太大,否则平均延迟翻倍 - 配合
proxy_next_upstream_timeout 10s,防止重试链路过长
健康检查只靠 max_fails=1 fail_timeout=10s,机器卡死却还在转发
这个配置只能发现“连接失败”,但 Java 进程假死(CPU 100%、GC 长停顿、线程池耗尽)时,TCP 握手仍成功,Nginx 会持续把流量打过去,直到超时或下游返回错误。
必须叠加主动健康检查(Nginx Plus 支持,开源版需用 nginx_upstream_check_module 编译模块,或改用 lua-resty-upstream-healthcheck):
- 检查路径设为 Spring Boot Actuator 的
/actuator/health,返回{"status":"UP"}才算健康 -
fall=3表示连续 3 次失败才摘除,rise=2表示连续 2 次成功才恢复,避免抖动 - 检查间隔
interval=5秒足够,太密增加后端压力,太疏发现慢
没有主动健康检查时,至少把 max_fails 设为 3,fail_timeout 设为 30 秒,给 JVM GC 或慢查询一点缓冲时间。










