Nginx + Tomcat 整合实战(三):负载均衡与集群部署

系列导读:本篇将深入讲解 Nginx 负载均衡配置与 Tomcat 集群部署,实现高可用、高性能的 Java Web 应用架构。


文章目录

    • 前言:为什么需要负载均衡?
    • 一、负载均衡核心概念
      • [1.1 负载均衡架构](#1.1 负载均衡架构)
      • [1.2 负载均衡算法](#1.2 负载均衡算法)
      • [1.3 集群架构模式](#1.3 集群架构模式)
    • [二、Nginx 负载均衡配置](#二、Nginx 负载均衡配置)
      • [2.1 基础轮询配置](#2.1 基础轮询配置)
      • [2.2 加权轮询配置](#2.2 加权轮询配置)
      • [2.3 IP 哈希配置(会话保持)](#2.3 IP 哈希配置(会话保持))
      • [2.4 最少连接配置](#2.4 最少连接配置)
      • [2.5 一致性哈希配置](#2.5 一致性哈希配置)
      • [2.6 服务器状态配置](#2.6 服务器状态配置)
    • [三、Tomcat 集群部署](#三、Tomcat 集群部署)
      • [3.1 单机多实例部署](#3.1 单机多实例部署)
      • [3.2 多机集群部署](#3.2 多机集群部署)
      • [3.3 Tomcat 集群配置](#3.3 Tomcat 集群配置)
    • 四、会话管理策略
      • [4.1 会话问题分析](#4.1 会话问题分析)
      • [4.2 解决方案对比](#4.2 解决方案对比)
      • [4.3 方案一:IP Hash(Nginx 配置)](#4.3 方案一:IP Hash(Nginx 配置))
      • [4.4 方案二:Session 复制(Tomcat 配置)](#4.4 方案二:Session 复制(Tomcat 配置))
      • [4.5 方案三:Redis Session 共享(推荐)](#4.5 方案三:Redis Session 共享(推荐))
    • 五、健康检查与故障转移
      • [5.1 被动健康检查](#5.1 被动健康检查)
      • [5.2 主动健康检查(需要第三方模块)](#5.2 主动健康检查(需要第三方模块))
      • [5.3 故障转移配置](#5.3 故障转移配置)
      • [5.4 优雅下线](#5.4 优雅下线)
    • 六、实战案例:生产级集群架构
      • [6.1 架构设计](#6.1 架构设计)
      • [6.2 完整 Nginx 配置](#6.2 完整 Nginx 配置)
    • 总结

前言:为什么需要负载均衡?

单台 Tomcat 服务器的局限性:

复制代码
🚫 并发瓶颈:单机最大并发约 500-1000
🚫 单点故障:服务器宕机,服务不可用
🚫 资源限制:CPU、内存、网络带宽受限
🚫 扩展困难:无法应对流量突增

负载均衡解决方案

复制代码
┌─────────────────────────────────────────────────────────────┐
│                   负载均衡架构优势                           │
├─────────────────────────────────────────────────────────────┤
│  ⚖️ 流量分发       → 请求均匀分配到多台服务器                │
│  🔄 高可用         → 单机故障不影响整体服务                  │
│  📈 弹性扩展       → 动态增减服务器应对流量变化              │
│  🛡️ 故障隔离       → 问题服务器自动隔离                      │
└─────────────────────────────────────────────────────────────┘

一、负载均衡核心概念

1.1 负载均衡架构

复制代码
                    ┌→ Tomcat1 (8080)
客户端 → Nginx ─────┼→ Tomcat2 (8081)
   LB                └→ Tomcat3 (8082)

Nginx 作为负载均衡器(LB)

1.2 负载均衡算法

算法 说明 适用场景
轮询 依次分配(默认) 服务器配置相同
加权轮询 按权重分配 服务器配置不同
IP 哈希 同一 IP 分配到同一服务器 需要会话保持
最少连接 分配给连接最少的服务器 请求处理时间差异大
一致性哈希 基于请求特征哈希 缓存场景

1.3 集群架构模式

模式一:单机多实例

复制代码
一台服务器运行多个 Tomcat 实例
┌─────────────────────────────────────┐
│           物理服务器                 │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐│
│  │Tomcat1  │ │Tomcat2  │ │Tomcat3  ││
│  │ :8080   │ │ :8081   │ │ :8082   ││
│  └─────────┘ └─────────┘ └─────────┘│
└─────────────────────────────────────┘

模式二:多机集群

复制代码
多台服务器,每台运行一个 Tomcat
┌───────────┐  ┌───────────┐  ┌───────────┐
│ Server1   │  │ Server2   │  │ Server3   │
│ Tomcat    │  │ Tomcat    │  │ Tomcat    │
│ :8080     │  │ :8080     │  │ :8080     │
└───────────┘  └───────────┘  └───────────┘

二、Nginx 负载均衡配置

2.1 基础轮询配置

nginx 复制代码
upstream tomcat_cluster {
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://tomcat_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

2.2 加权轮询配置

nginx 复制代码
upstream tomcat_cluster {
    # 高配置服务器分配更多流量
    server 192.168.1.10:8080 weight=5;  # 50% 流量
    server 192.168.1.11:8080 weight=3;  # 30% 流量
    server 192.168.1.12:8080 weight=2;  # 20% 流量
}

# 流量分配:10 → 11 → 12 → 10 → 11 → 10 → 10 → 11 → 12 → 10

2.3 IP 哈希配置(会话保持)

nginx 复制代码
upstream tomcat_cluster {
    ip_hash;  # 同一 IP 始终访问同一服务器
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

# 注意:ip_hash 不支持 weight 和 backup

2.4 最少连接配置

nginx 复制代码
upstream tomcat_cluster {
    least_conn;  # 分配给连接数最少的服务器
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

2.5 一致性哈希配置

nginx 复制代码
upstream tomcat_cluster {
    hash $request_uri consistent;  # 基于 URI 的一致性哈希
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

# 适用场景:缓存服务器集群

2.6 服务器状态配置

nginx 复制代码
upstream tomcat_cluster {
    # 正常服务器
    server 192.168.1.10:8080 weight=5;
    
    # 带故障检测的服务器
    server 192.168.1.11:8080 
        max_fails=3           # 最大失败次数
        fail_timeout=30s;     # 失败后暂停时间
    
    # 备份服务器(仅在其他服务器不可用时启用)
    server 192.168.1.12:8080 backup;
    
    # 下线服务器
    server 192.168.1.13:8080 down;
}

三、Tomcat 集群部署

3.1 单机多实例部署

步骤一:创建实例目录

bash 复制代码
# 创建多实例目录
mkdir -p /opt/tomcat/{instance1,instance2,instance3}

# 复制 Tomcat 文件
TOMCAT_HOME=/opt/tomcat/current

for i in 1 2 3; do
    cp -r $TOMCAT_HOME/* /opt/tomcat/instance$i/
done

步骤二:修改端口配置

bash 复制代码
# 实例1: server.xml
sed -i 's/port="8005"/port="8105"/' /opt/tomcat/instance1/conf/server.xml
sed -i 's/port="8080"/port="8180"/' /opt/tomcat/instance1/conf/server.xml
sed -i 's/port="8009"/port="8109"/' /opt/tomcat/instance1/conf/server.xml

# 实例2: server.xml
sed -i 's/port="8005"/port="8205"/' /opt/tomcat/instance2/conf/server.xml
sed -i 's/port="8080"/port="8280"/' /opt/tomcat/instance2/conf/server.xml
sed -i 's/port="8009"/port="8209"/' /opt/tomcat/instance2/conf/server.xml

# 实例3: server.xml
sed -i 's/port="8005"/port="8305"/' /opt/tomcat/instance3/conf/server.xml
sed -i 's/port="8080"/port="8380"/' /opt/tomcat/instance3/conf/server.xml
sed -i 's/port="8009"/port="8309"/' /opt/tomcat/instance3/conf/server.xml

步骤三:创建启动脚本

bash 复制代码
#!/bin/bash
# /opt/tomcat/instances.sh

INSTANCE_DIR="/opt/tomcat"
INSTANCES=("instance1" "instance2" "instance3")

start_all() {
    for instance in "${INSTANCES[@]}"; do
        echo "Starting $instance..."
        $INSTANCE_DIR/$instance/bin/startup.sh
    done
}

stop_all() {
    for instance in "${INSTANCES[@]}"; do
        echo "Stopping $instance..."
        $INSTANCE_DIR/$instance/bin/shutdown.sh
    done
}

status() {
    for instance in "${INSTANCES[@]}"; do
        pid_file="$INSTANCE_DIR/$instance/temp/tomcat.pid"
        if [ -f "$pid_file" ]; then
            echo "$instance: Running (PID: $(cat $pid_file))"
        else
            echo "$instance: Stopped"
        fi
    done
}

case "$1" in
    start)   start_all ;;
    stop)    stop_all ;;
    restart) stop_all; sleep 3; start_all ;;
    status)  status ;;
    *)       echo "Usage: $0 {start|stop|restart|status}" ;;
esac

3.2 多机集群部署

服务器规划

服务器 IP 角色 端口
Server1 192.168.1.10 Nginx + Tomcat 80/8080
Server2 192.168.1.11 Tomcat 8080
Server3 192.168.1.12 Tomcat 8080

Nginx 配置(Server1)

nginx 复制代码
upstream tomcat_cluster {
    server 192.168.1.10:8080 weight=3;
    server 192.168.1.11:8080 weight=3;
    server 192.168.1.12:8080 weight=3;
    keepalive 32;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://tomcat_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

3.3 Tomcat 集群配置

每个 Tomcat 实例需要配置 jvmRoute

xml 复制代码
<!-- server.xml -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
  <!-- jvmRoute 用于会话粘性,值必须唯一 -->
</Engine>

不同实例的 jvmRoute

bash 复制代码
# 实例1
<Engine ... jvmRoute="tomcat1">

# 实例2
<Engine ... jvmRoute="tomcat2">

# 实例3
<Engine ... jvmRoute="tomcat3">

四、会话管理策略

4.1 会话问题分析

复制代码
用户请求 → Nginx → Tomcat1(创建 Session A)
用户请求 → Nginx → Tomcat2(找不到 Session A,创建 Session B)

问题:用户登录后,下次请求可能被分发到其他 Tomcat,导致登录状态丢失。

4.2 解决方案对比

方案 优点 缺点 适用场景
IP Hash 配置简单 负载不均衡 小规模集群
Session 复制 配置简单 性能开销大 小规模集群
Session 共享(Redis) 性能好、可扩展 需要 Redis 大规模集群
JWT 无状态 无会话问题 无法主动失效 RESTful API

4.3 方案一:IP Hash(Nginx 配置)

nginx 复制代码
upstream tomcat_cluster {
    ip_hash;
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
}

# 缺点:某 IP 流量大时,对应服务器压力大

4.4 方案二:Session 复制(Tomcat 配置)

xml 复制代码
<!-- server.xml -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
         channelSendOptions="8">
  
  <Manager className="org.apache.catalina.ha.session.DeltaManager"
           expireSessionsOnShutdown="false"
           notifyListenersOnReplication="true"/>
  
  <Channel className="org.apache.catalina.tribes.group.GroupChannel">
    <Membership className="org.apache.catalina.tribes.membership.McastService"
                address="228.0.0.4"
                port="45564"
                frequency="500"
                dropTime="3000"/>
    <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
              address="auto"
              port="4000"
              autoBind="100"
              selectorTimeout="5000"
              maxThreads="6"/>
    <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
      <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
    </Sender>
    <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
    <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
  </Channel>
  
  <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
  <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
  <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

web.xml 添加配置

xml 复制代码
<!-- web.xml -->
<distributable/>

4.5 方案三:Redis Session 共享(推荐)

添加依赖

xml 复制代码
<!-- pom.xml -->
<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>

Spring Boot 配置

yaml 复制代码
# application.yml
spring:
  session:
    store-type: redis
  redis:
    host: 192.168.1.100
    port: 6379
    password: yourpassword
    database: 0

启用 Session

java 复制代码
@EnableRedisHttpSession
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Nginx 配置

nginx 复制代码
upstream tomcat_cluster {
    least_conn;  # 使用最少连接算法
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

五、健康检查与故障转移

5.1 被动健康检查

nginx 复制代码
upstream tomcat_cluster {
    server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:8080 max_fails=3 fail_timeout=30s;
}

# max_fails: 最大失败次数
# fail_timeout: 失败后暂停时间

5.2 主动健康检查(需要第三方模块)

nginx 复制代码
# 使用 nginx_upstream_check_module
upstream tomcat_cluster {
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
    
    check interval=3000 rise=2 fall=3 timeout=1000 type=http;
    check_http_send "GET /health HTTP/1.0\r\n\r\n";
    check_http_expect_alive http_2xx http_3xx;
}

server {
    location /nginx_status {
        check_status;
        access_log off;
    }
}

5.3 故障转移配置

nginx 复制代码
upstream tomcat_cluster {
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080 backup;  # 备份服务器
}

server {
    location / {
        proxy_pass http://tomcat_cluster;
        
        # 故障重试
        proxy_next_upstream 
            error 
            timeout 
            http_500 
            http_502 
            http_503 
            http_504;
        proxy_next_upstream_tries 3;
        proxy_next_upstream_timeout 30s;
    }
}

5.4 优雅下线

nginx 复制代码
# 服务器下线流程
# 1. 标记为 down
# 2. 等待现有请求处理完成
# 3. 停止 Tomcat

upstream tomcat_cluster {
    server 192.168.1.10:8080;
    server 192.168.1.11:8080 down;  # 下线
    server 192.168.1.12:8080;
}

六、实战案例:生产级集群架构

6.1 架构设计

复制代码
┌─────────────────────────────────────────────────────────────┐
│                        用户请求                              │
└─────────────────────────┬───────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│                    Nginx 负载均衡                            │
│                    (主备 Keepalived)                         │
└─────────────────────────┬───────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│                      Tomcat 集群                             │
│  ┌───────────┐  ┌───────────┐  ┌───────────┐               │
│  │ Tomcat 1  │  │ Tomcat 2  │  │ Tomcat 3  │               │
│  └───────────┘  └───────────┘  └───────────┘               │
└─────────────────────────┬───────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│                    Redis Session                            │
│                    (主从 Sentinel)                           │
└─────────────────────────────────────────────────────────────┘

6.2 完整 Nginx 配置

nginx 复制代码
# /etc/nginx/nginx.conf

user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 65535;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    # 日志格式
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'upstream=$upstream_addr response_time=$upstream_response_time';
    
    access_log /var/log/nginx/access.log main;
    
    # 性能优化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    
    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 5;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript 
               application/javascript application/json application/xml;
    
    # 限流配置
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
    
    # Upstream 定义
    upstream tomcat_cluster {
        least_conn;
        server 192.168.1.10:8080 weight=3 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=3 max_fails=3 fail_timeout=30s;
        keepalive 32;
    }
    
    # WebSocket 映射
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }
    
    # 引入站点配置
    include /etc/nginx/conf.d/*.conf;
}
nginx 复制代码
# /etc/nginx/conf.d/app.conf

server {
    listen 80;
    server_name app.example.com;
    
    # 强制 HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name app.example.com;
    
    # SSL 配置
    ssl_certificate /etc/nginx/ssl/app.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/app.example.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # 日志
    access_log /var/log/nginx/app.access.log main;
    error_log /var/log/nginx/app.error.log;
    
    # 静态资源
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ {
        root /opt/tomcat/current/webapps/ROOT;
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
    
    # WebSocket
    location /ws/ {
        proxy_pass http://tomcat_cluster;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 3600s;
        proxy_buffering off;
    }
    
    # API 限流
    location /api/ {
        limit_req zone=api_limit burst=200 nodelay;
        
        proxy_pass http://tomcat_cluster;
        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_next_upstream error timeout http_500 http_502 http_503 http_504;
        proxy_next_upstream_tries 3;
    }
    
    # 默认转发
    location / {
        proxy_pass http://tomcat_cluster;
        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;
    }
    
    # 健康检查
    location /health {
        access_log off;
        return 200 "OK\n";
        add_header Content-Type text/plain;
    }
    
    # Nginx 状态
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        allow 192.168.1.0/24;
        deny all;
    }
}

总结

本文深入讲解了 Nginx 负载均衡与 Tomcat 集群部署:

负载均衡算法 :轮询、加权、IP Hash、最少连接、一致性哈希

集群部署 :单机多实例、多机集群、端口配置

会话管理 :IP Hash、Session 复制、Redis 共享

健康检查 :被动检查、主动检查、故障转移

生产架构:完整配置模板、高可用设计

集群部署检查清单

复制代码
□ Tomcat 实例端口配置正确
□ jvmRoute 值唯一
□ Session 共享方案已实施
□ Nginx upstream 配置正确
□ 健康检查已配置
□ 故障转移已测试
□ 静态资源路径一致
□ 日志收集已配置

下一篇预告 :(Nginx + Tomcat 整合实战(四):会话管理与共享详解),将深入讲解 Session 管理的各种方案、Redis 集成、分布式会话最佳实践。


作者 :刘~浪地球
系列 :Nginx + Tomcat 整合实战(三)
更新时间:2026-03-31

相关推荐
人间打气筒(Ada)2 小时前
「码动四季·开源同行」golang:负载均衡如何提高系统可用性?
算法·golang·开源·go·负载均衡·负载均衡算法
灰阳阳12 小时前
Dockerfile实践-构建Nginx镜像
运维·nginx·docker·dockerfile
星晨雪海21 小时前
MyBatis-Plus 常用 CRUD 方法大全
linux·tomcat·mybatis
huabiangaozhi1 天前
Docker:基于自制openjdk8镜像 or 官方openjdk8镜像,制作tomcat镜像
docker·容器·tomcat
大数据新鸟1 天前
设计模式详解——模板方法模式
java·tomcat·模板方法模式
ywlovecjy1 天前
macOs安装docker且在docker上部署nginx+php
nginx·macos·docker
tumeng07111 天前
Linux(CentOS)安装 Nginx
linux·nginx·centos
lclcooky1 天前
JavaWeb项目打包、部署至Tomcat并启动的全程指南(图文详解)
java·tomcat
无名-CODING1 天前
SpringCloud 服务调用与负载均衡:OpenFeign 极简使用教程
spring·spring cloud·负载均衡