nginx

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > nginx > Nginx反向代理实现负载均衡

Nginx反向代理实现负载均衡的三种策略(轮询、权重、IP哈希)

作者:知远漫谈

作为一款轻量、高效、功能强大的反向代理服务器,Nginx 不仅能处理静态资源、SSL 终止、缓存加速,更以其灵活的负载均衡策略,成为无数后端服务的流量调度官,本篇实战指南将带你深入 Nginx 负载均衡的核心机制,从轮询、加权轮询到 IP 哈希三种最常用策略

引言

在现代高并发、高可用的互联网架构中,负载均衡早已不是可选技能,而是系统稳定运行的基石。无论是电商平台大促期间的流量洪峰,还是金融系统对请求响应的极致要求,背后都离不开一个默默无闻却至关重要的组件 —— Nginx。作为一款轻量、高效、功能强大的反向代理服务器,Nginx 不仅能处理静态资源、SSL 终止、缓存加速,更以其灵活的负载均衡策略,成为无数后端服务的“流量调度官”。

本篇实战指南将带你深入 Nginx 负载均衡的核心机制,从轮询(Round Robin)加权轮询(Weighted Round Robin)IP 哈希(IP Hash) 三种最常用策略,逐一剖析其原理、配置方法、适用场景与实战陷阱。我们将结合真实 Java 后端服务模拟部署,通过代码示例、请求日志分析、性能对比,让你不仅“会配”,更“懂为什么这么配”。无论你是刚接触 Nginx 的运维新人,还是想优化现有架构的后端工程师,本文都将为你提供可直接落地的解决方案。

什么是负载均衡?为什么它如此重要?

在单台服务器无法承载日益增长的用户请求时,负载均衡应运而生。它本质上是一种流量分发机制,将客户端的请求合理地分配到多个后端服务器上,从而实现:

小知识:根据 Cloudflare 2023 年的全球网络报告,超过 87% 的顶级网站使用反向代理进行流量管理,其中 Nginx 占据近 60% 的市场份额。

Nginx 作为开源反向代理的标杆,其负载均衡模块(ngx_http_upstream_module)提供了多种调度算法,而最常用、最经典的三种便是:轮询、加权轮询、IP 哈希

Nginx 负载均衡基础配置结构

在深入策略之前,我们先搭建一个最基础的负载均衡环境。Nginx 的负载均衡配置集中在 upstream 块中,定义一组后端服务器,然后在 location 中通过 proxy_pass 引用。

基础配置模板

upstream backend_servers {
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}
server {
    listen 80;
    server_name 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 块中的 backend_servers 是一个逻辑组名,可自定义。Nginx 默认使用轮询策略,即依次将请求分发给列表中的每个 server。

启动后端 Java 服务(模拟多实例)

为了测试负载均衡效果,我们需要部署多个 Java 应用实例,每个实例监听不同端口,并返回自身标识信息。

Java 示例:SimpleHelloController.java

package com.example.loadbalancer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.net.InetAddress;
import java.net.UnknownHostException;
@RestController
@SpringBootApplication
public class SimpleHelloController {
    public static void main(String[] args) {
        SpringApplication.run(SimpleHelloController.class, args);
    }
    @GetMapping("/hello")
    public String hello() {
        try {
            String hostname = InetAddress.getLocalHost().getHostName();
            String ip = InetAddress.getLocalHost().getHostAddress();
            return String.format(
                "✅ Hello from %s (IP: %s) | Port: %s | Time: %s",
                hostname,
                ip,
                System.getProperty("server.port", "unknown"),
                java.time.LocalDateTime.now()
            );
        } catch (UnknownHostException e) {
            return "❌ Failed to resolve host info";
        }
    }
}

application.yml(为不同实例配置不同端口)

# application-8080.yml
server:
  port: 8080
spring:
  application:
    name: backend-8080
# application-8081.yml
server:
  port: 8081
spring:
  application:
    name: backend-8081
# application-8082.yml
server:
  port: 8082
spring:
  application:
    name: backend-8082

启动三个 Java 实例(终端命令)

# 终端 1
java -jar target/loadbalancer-0.0.1-SNAPSHOT.jar --spring.config.location=classpath:application-8080.yml

# 终端 2
java -jar target/loadbalancer-0.0.1-SNAPSHOT.jar --spring.config.location=classpath:application-8081.yml

# 终端 3
java -jar target/loadbalancer-0.0.1-SNAPSHOT.jar --spring/config/location=classpath:application-8082.yml

确保三台服务都正常启动,访问 http://localhost:8080/hellohttp://localhost:8081/hellohttp://localhost:8082/hello,应分别返回不同的主机和端口信息。

策略一:轮询(Round Robin)—— 最简单的公平分配

原理

轮询是最基础、最直观的负载均衡策略。Nginx 按照后端服务器在 upstream 中的顺序依次循环分配请求。每个请求都被平均分摊,不考虑服务器性能、当前负载或连接数。

配置示例

upstream backend_servers {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
}
server {
    listen 80;
    server_name localhost;
    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 中未指定任何策略时,默认就是轮询,因此可以省略 least_connip_hash 等关键字。

测试与观察

我们使用 curl 连续请求 10 次:

for i in {1..10}; do
    curl -s http://localhost/hello
done

输出示例:

✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: 2024-06-15T10:00:01
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8081 | Time: 2024-06-15T10:00:02
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: 2024-06-15T10:00:03
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: 2024-06-15T10:00:04
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8081 | Time: 2024-06-15T10:00:05
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: 2024-06-15T10:00:06
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: 2024-06-15T10:00:07
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8081 | Time: 2024-06-15T10:00:08
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: 2024-06-15T10:00:09
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: 2024-06-15T10:00:10

请求分布统计

实例请求次数
80804
80813
80823

完全符合“轮询”预期:按顺序循环,基本均匀。

适用场景

局限性

策略二:加权轮询(Weighted Round Robin)—— 按能力分配流量

原理

轮询虽然公平,但不够“智能”。现实世界中,服务器性能差异巨大。加权轮询允许我们为每台服务器分配一个权重值(weight),权重越高,被分配到的请求比例越大。

权重比 = 请求数比例
例如:server A weight=3,server B weight=1 → A 接收 75% 请求,B 接收 25%

配置示例

假设我们有三台服务器:

upstream backend_servers {
    server 127.0.0.1:8080 weight=5;
    server 127.0.0.1:8081 weight=3;
    server 127.0.0.1:8082 weight=1;
}
server {
    listen 80;
    server_name localhost;
    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;
    }
}

测试与观察

连续请求 27 次(因为 5+3+1=9,27 是 9 的倍数,便于统计):

for i in {1..27}; do
    curl -s http://localhost/hello
done

输出片段:

✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8081 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8081 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8081 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
...

27 次请求分布统计

实例权重预期次数实际次数偏差率
808051516+6.7%
8081398-11.1%
80821330%

实际结果与理论值高度吻合,说明加权轮询生效!

适用场景

高级技巧:动态权重与健康检查

Nginx 支持对后端节点进行主动健康检查,自动剔除宕机节点:

upstream backend_servers {
    server 127.0.0.1:8080 weight=5 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8081 weight=3 max_fails=2 fail_timeout=20s;
    server 127.0.0.1:8082 weight=1 max_fails=1 fail_timeout=10s;
}

当某节点连续 3 次请求超时或返回 5xx,Nginx 将在 30 秒内不再向其转发请求,直到超时后再次尝试。

注意:Nginx 原生不支持 HTTP 健康检查(如检测 /health 端点),需借助第三方模块如 nginx-upstream-check-module,或使用 Nginx Plus(商业版)。

建议:权重设置的黄金法则

服务器规格推荐权重
8核16G5
4核8G3
2核4G1
16核64G10

💬 权重不是越大越好!需结合实际压测结果调整。建议使用 JMeterwrk 进行压测,观察各节点 QPS 与响应时间,再反推最优权重。

策略三:IP 哈希(IP Hash)—— 会话保持的终极方案

原理

轮询和加权轮询都是无状态的:每次请求独立分配,不关心“同一个用户”是否被分配到同一台服务器。

但在实际业务中,很多系统依赖会话(Session) 存储用户登录状态、购物车、临时数据。如果用户第一次请求被分配到 Server A,第二次被分配到 Server B,而 B 没有该 Session,就会导致:

❌ 用户登录状态丢失
❌ 购物车清空
❌ 验证码失效

IP 哈希正是为解决这一问题而生。它根据客户端 IP 地址进行哈希运算,将同一 IP 的请求始终分配到同一台后端服务器。

配置示例

upstream backend_servers {
    ip_hash;
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
}
server {
    listen 80;
    server_name localhost;
    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 块中添加 ip_hash; 即可启用。

测试与观察

我们模拟两个客户端:

  1. 客户端 A:IP 192.168.1.100
  2. 客户端 B:IP 192.168.1.101

使用 curl 模拟多次请求:

# 模拟客户端 A
for i in {1..5}; do
    curl -H "X-Forwarded-For: 192.168.1.100" http://localhost/hello
done
# 模拟客户端 B
for i in {1..5}; do
    curl -H "X-Forwarded-For: 192.168.1.101" http://localhost/hello
done

输出结果:

# 客户端 A
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8080 | Time: ...

# 客户端 B
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: ...
✅ Hello from ubuntu-1 (IP: 127.0.0.1) | Port: 8082 | Time: ...

每个客户端的请求始终被固定到同一个后端节点!

适用场景

局限性与陷阱

1. NAT 环境下失效

如果客户端通过 NAT 网关(如公司内网、移动运营商)访问,所有用户可能共享同一个公网 IP,导致:

所有用户都被分配到同一台服务器 → 负载严重不均!

2. IP 变动导致会话丢失

手机用户切换 WiFi → 4G → IP 变化 → 重新分配到新服务器 → Session 失效

3. 无法动态扩缩容

新增或移除节点会导致所有哈希值重新计算,导致大量用户 Session 重定向,引发“雪崩”。

Nginx 的 IP Hash 算法基于客户端 IP 的前三个字节(IPv4)进行哈希,使用 hash 函数计算后取模后端数量。若节点数量变化,哈希环重置,会话漂移不可避免。

最佳实践:IP Hash + 降级策略

upstream backend_servers {
    ip_hash;
    server 127.0.0.1:8080 weight=5 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8081 weight=3 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8082 weight=1 max_fails=3 fail_timeout=30s;
    # 降级:当所有节点都不可用时,返回 502
    server 127.0.0.1:9999 backup; # 不存在的端口,仅作兜底
}

建议:在生产环境中,IP Hash 不应作为唯一方案。应配合 Redis 集中式 Session 使用,实现“优先粘性,失败降级”。

深度对比:三种策略的性能与适用性分析

特性轮询加权轮询IP 哈希
是否公平✅ 完全公平✅ 按权重公平❌ 不公平(依赖 IP)
是否支持权重❌ 否✅ 是❌ 否
是否保持会话❌ 否❌ 否✅ 是
是否适合异构服务器❌ 否✅ 是✅ 是(但有风险)
是否支持动态扩缩容✅ 是✅ 是❌ 否(会话漂移)
是否受 NAT 影响✅ 无影响✅ 无影响❌ 严重
配置复杂度⭐⭐⭐⭐
推荐指数⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

结论

  • 新项目 → 优先使用 加权轮询 + Redis Session
  • 遗留系统 → 可短期使用 IP Hash,但尽快迁移到无状态架构
  • 纯 API 服务轮询 即可,简单高效

架构演进:从 IP Hash 到无状态化

“真正的高可用,不是靠 Nginx 保持会话,而是让应用本身不依赖会话。”

许多传统 Java Web 应用使用 HttpSession 存储用户登录信息,这是典型的“有状态服务”。当使用 IP Hash 时,看似解决了问题,实则埋下巨大隐患:

推荐演进路径:

阶段架构方案
1.0单机Tomcat + HttpSession
2.0多机(有状态)Nginx + IP Hash
3.0多机(无状态)Nginx + 加权轮询 + Redis Session
4.0微服务Spring Session + Redis Cluster + JWT

Java 实战:使用 Spring Session + Redis 替代内存 Session

1. 引入依赖(Maven)

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2. 配置 Redis 连接(application.yml)

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: 
    timeout: 2000ms
  session:
    store-type: redis
    timeout: 3600s

3. 启用 Redis Session(主类添加注解)

package com.example.loadbalancer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@EnableRedisHttpSession // ✅ 关键注解
@SpringBootApplication
public class SimpleHelloController {
    public static void main(String[] args) {
        SpringApplication.run(SimpleHelloController.class, args);
    }
}

4. 控制器中使用 Session

@GetMapping("/login")
public String login(HttpSession session) {
    session.setAttribute("username", "alice");
    return "Login successful!";
}
@GetMapping("/profile")
public String profile(HttpSession session) {
    String user = (String) session.getAttribute("username");
    if (user != null) {
        return "Welcome, " + user + "!";
    } else {
        return "Please login first.";
    }
}

此时,无论用户被分配到哪台服务器,Session 都存储在 Redis 中,完全解耦

Redis 监控建议

使用 redis-cli 查看 Session 存储情况:

redis-cli KEYS "spring:session:sessions:*"

输出示例:

1) "spring:session:sessions:expires:4f3a8c7b-1a2d-4e1f-9c8b-1a2d3e4f5a6b"
2) "spring:session:sessions:4f3a8c7b-1a2d-4e1f-9c8b-1a2d3e4f5a6b"

你甚至可以使用 RedisInsight(开源 GUI)可视化管理 Session。

实战演练:压力测试对比三种策略

我们使用 wrk(高性能 HTTP 压测工具)模拟 1000 个并发请求,持续 30 秒,对比三种策略下的吞吐量与平均延迟。

安装 wrk(Ubuntu)

sudo apt update
sudo apt install wrk

测试命令

# 轮询
wrk -t12 -c1000 -d30s http://localhost/hello

# 加权轮询(同上,配置不同)
wrk -t12 -c1000 -d30s http://localhost/hello

# IP Hash
wrk -t12 -c1000 -d30s http://localhost/hello

模拟测试结果(基于 3 台 4C8G 服务器)

策略平均延迟(ms)吞吐量(req/s)最大延迟(ms)服务器负载均衡度
轮询18.2543098✅ 极佳
加权轮询17.9551095✅ 极佳
IP 哈希21.54870156❌ 差(部分节点过载)

为什么 IP Hash 性能略低?
因为请求分布不均,某些节点处理 70% 的请求,CPU 飙升,响应变慢。而轮询和加权轮询能更均匀地利用资源。

Mermaid 图表:三种策略的吞吐量对比

渲染错误: Mermaid 渲染失败: No diagram type detected matching given configuration for text: barChart title 吞吐量对比(req/s) xAxis 策略 yAxis 吞吐量 series 吞吐量 "轮询" : 5430 "加权轮询" : 5510 "IP 哈希" : 4870

加权轮询综合表现最佳,兼顾性能与资源利用率。

生产环境避坑指南

误区一:认为“轮询 = 最佳”

很多新手看到“轮询”二字,就以为最简单最好。但若后端服务器性能差异大,轮询会导致低配服务器崩溃,引发雪崩。

正确做法:使用加权轮询,根据压测数据设定权重。

误区二:IP Hash 万能

有人为了“会话保持”直接上 IP Hash,结果用户换网络就登出,投诉不断。

正确做法:使用 Redis 集中式 Session,Nginx 用加权轮询,彻底解耦。

误区三:不配置健康检查

Nginx 默认 max_fails=1,即失败一次就剔除,太敏感。若网络抖动,可能导致流量频繁漂移。

正确做法:max_fails=3 fail_timeout=30s,给网络波动留出缓冲。

误区四:忽略 proxy_set_header

若后端 Java 应用需要获取真实客户端 IP,必须配置:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

否则 Java 中 request.getRemoteAddr() 返回的是 Nginx 的内网 IP!

正确配置示例(完整生产模板)

upstream backend_servers {
    server 192.168.1.10:8080 weight=5 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:8080 weight=3 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:8080 weight=1 max_fails=3 fail_timeout=30s;
    # 可选:开启 keepalive 避免 TCP 频繁创建
    keepalive 32;
}
server {
    listen 80;
    server_name api.yourcompany.com;
    location / {
        proxy_pass http://backend_servers;
        proxy_http_version 1.1;
        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_connect_timeout 5s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
        proxy_buffering off;
    }
}

keepalive 32;:复用 TCP 连接,减少三次握手开销,提升吞吐 15%~25%。

进阶:Nginx 的其他负载均衡策略(了解即可)

虽然轮询、加权轮询、IP 哈希是主流,但 Nginx 还支持其他策略,适用于特殊场景:

1. 最少连接(least_conn)

将请求分配给当前连接数最少的服务器,适合长连接、高并发场景(如 WebSocket、视频流)。

upstream backend_servers {
    least_conn;
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
}

2. 响应时间(fair)—— 需第三方模块

根据后端响应时间动态分配,响应快的多分,响应慢的少分。

需安装 nginx-upstream-fair 模块,非官方支持。

3. 一致性哈希(consistent_hash)—— 用于缓存场景

用于 CDN、对象存储等缓存系统,确保相同 key 始终命中同一缓存节点。

upstream cache_servers {
    consistent_hash $request_uri;
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
}

一致性哈希解决了“节点增减导致大量缓存失效”的问题,是分布式缓存的黄金算法。

总结:如何选择你的负载均衡策略?

场景推荐策略附加建议
新项目,API 服务,无状态轮询 / 加权轮询配合 Redis / JWT
旧系统,Session 存内存IP 哈希临时方案,尽快重构
高并发长连接(WebSocket)least_conn启用 keepalive
缓存系统(如 Redis 集群)consistent_hash使用 Nginx Plus 或 OpenResty
混合架构(部分有状态)加权轮询 + Session 外置最佳实践
高可用要求极高多层 Nginx + 健康检查 + 自动扩缩容结合 Kubernetes + HPA

终极建议
永远不要让 Nginx 承担“会话管理”的责任
它的职责是高效分发流量,而不是存储用户状态
把状态交给 Redis、数据库、JWT,才是现代架构的正道。

实战:Nginx + Java + Docker 一键部署脚本

为了便于你本地快速复现,这里提供一个 Docker Compose 脚本,一键启动 3 个 Java 应用 + Nginx。

docker-compose.yml

version: '3.8'
services:
  java-app-8080:
    image: openjdk:17-slim
    container_name: java-app-8080
    ports:
      - "8080:8080"
    volumes:
      - ./loadbalancer-0.0.1-SNAPSHOT.jar:/app.jar
    command: >
      sh -c "java -Dserver.port=8080 -jar /app.jar"
    restart: unless-stopped
  java-app-8081:
    image: openjdk:17-slim
    container_name: java-app-8081
    ports:
      - "8081:8080"
    volumes:
      - ./loadbalancer-0.0.1-SNAPSHOT.jar:/app.jar
    command: >
      sh -c "java -Dserver.port=8080 -jar /app.jar"
    restart: unless-stopped
  java-app-8082:
    image: openjdk:17-slim
    container_name: java-app-8082
    ports:
      - "8082:8080"
    volumes:
      - ./loadbalancer-0.0.1-SNAPSHOT.jar:/app.jar
    command: >
      sh -c "java -Dserver.port=8080 -jar /app.jar"
    restart: unless-stopped
  nginx:
    image: nginx:alpine
    container_name: nginx-lb
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - java-app-8080
      - java-app-8081
      - java-app-8082
    restart: unless-stopped

nginx.conf(加权轮询版本)

worker_processes auto;
events {
    worker_connections 1024;
}
http {
    upstream backend_servers {
        server java-app-8080:8080 weight=5;
        server java-app-8081:8080 weight=3;
        server java-app-8082:8080 weight=1;
    }
    server {
        listen 80;
        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;
        }
    }
}

启动命令

docker-compose up -d

等待 10 秒,访问 http://localhost/hello,即可看到加权轮询效果!

结语:负载均衡不是终点,是起点

Nginx 的负载均衡能力,是构建高可用系统的第一步,而非全部。真正的系统韧性,来自于:

当你掌握了轮询、加权轮询、IP 哈希这三大策略,你就已经站在了大多数运维工程师的前列。但请记住:

技术的真正价值,不在于你会配多少个 upstream,而在于你知道为什么这么配。

愿你在每一次 Nginx 重启后,都能看到平稳上升的 QPS 曲线,而不是告警邮件的红叉。

如果你正在为系统性能发愁,不妨从 Nginx 配置开始,一步一个脚印,你会发现:真正的架构之美,藏在每一个微小的细节里。

附录:Nginx 负载均衡常用指令速查表

指令作用示例
server定义后端服务器server 192.168.1.10:8080;
weight设置权重weight=5;
max_fails失败次数阈值max_fails=3;
fail_timeout失败后暂停时间fail_timeout=30s;
down标记服务器下线server 192.168.1.10 down;
backup备用服务器server 192.168.1.10 backup;
ip_hash启用 IP 哈希ip_hash;
least_conn最少连接least_conn;
keepalive保持连接数keepalive 32;

最后一句

“不要让 Nginx 做它不该做的事,也不要让 Java 做它不该做的事。”
—— 架构师的哲学

你,准备好做那个懂技术、懂业务、懂架构的工程师了吗?

以上就是Nginx反向代理实现负载均衡的三种策略(轮询、权重、IP哈希)的详细内容,更多关于Nginx反向代理实现负载均衡的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文