使用 Nginx 实现 Tomcat 集群的负载均衡

整个过程可以分为以下几个核心步骤:

  1. 环境准备:准备好 Nginx 和多个 Tomcat 实例。
  2. 配置 Tomcat 集群 :确保所有 Tomcat 实例配置一致,并能通过 session 共享来维持用户登录状态。
  3. 配置 Nginx 负载均衡:设置 Nginx 反向代理,将请求分发到不同的 Tomcat 实例。
  4. 验证与测试:验证集群是否正常工作。

1. 环境准备

  • 一台 Nginx 服务器:用于接收外部请求并分发。
  • 两台或多台 Tomcat 服务器 :构成应用服务器集群。为了简单演示,我们可以在同一台服务器上启动多个 Tomcat 实例,通过修改端口来区分它们。

示例场景

  • Nginx 服务器192.168.1.100,监听 80 端口。
  • Tomcat 集群
    • Tomcat 1: 监听 8080 端口
    • Tomcat 2: 监听 8081 端口

2. 配置 Tomcat 集群 (Session 共享)

这是集群部署的关键。如果不配置 Session 共享,用户的一次请求可能分发到 Tomcat 1,登录成功后,下一次请求可能分发到 Tomcat 2,而 Tomcat 2 上没有该用户的 Session,导致用户需要重新登录。

解决方案:使用 Redis 集中存储 Session。

步骤 A:修改 Tomcat 配置 (conf/context.xml)

在所有 Tomcat 实例的 conf/context.xml 文件中,添加以下 <Manager> 配置。

xml

复制代码
<!-- Tomcat 1 和 Tomcat 2 的 context.xml 都需要添加此配置 -->
<Context>
    ... 其他配置 ...

    <!-- 
        使用 Redis 存储 Session
        确保你的项目中已经引入了 tomcat-redis-session-manager 的相关 JAR 包
        下载地址: https://github.com/ran-jit/tomcat-redis-session-manager/releases
        需要将 tomcat-redis-session-manager-VERSION.jar, jedis-VERSION.jar, commons-pool2-VERSION.jar 放入 Tomcat 的 lib 目录
    -->
    <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
             host="127.0.0.1"          <!-- Redis 服务器地址 -->
             port="6379"               <!-- Redis 端口 -->
             password=""               <!-- Redis 密码 (如果没有则为空) -->
             database="0"              <!-- 使用的 Redis 数据库 -->
             maxInactiveInterval="60"  <!-- Session 过期时间(秒) -->
             sessionPersistPolicies="PERSIST_POLICY_1,PERSIST_POLICY_2" />

</Context>

重要

  • 我的测试版本:apache-tomcat-9.0.113,下载JAR 包 jackson-databind-2.13.4.jar,redisson-all-3.17.0.jar,redisson-tomcat-9-3.17.0.jar,slf4j-simple-1.7.36.jar,放入每个 Tomcat 实例的 lib 目录下。
  • mven仓库地址:https://mvnrepository.com/artifact/com.dotcms
  • 所有 Tomcat 实例都必须连接到同一个 Redis 实例
步骤 B:修改 Tomcat 端口 (如果在同一台服务器)

如果你的多个 Tomcat 实例在同一台服务器上,需要修改 conf/server.xml 文件来避免端口冲突。

对于 Tomcat 2 (tomcat2),修改以下三个端口

xml

复制代码
<!-- 修改前 -->
<Server port="8005" shutdown="SHUTDOWN">
<Connector port="8080" protocol="HTTP/1.1" ... />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

<!-- 修改后 (例如) -->
<Server port="8006" shutdown="SHUTDOWN">
<Connector port="8081" protocol="HTTP/1.1" ... />
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />
步骤 C:部署测试应用

为了验证负载均衡和 Session 共享是否生效,我们可以创建一个简单的 JSP 页面。

在两个 Tomcat 的 webapps/ROOT 目录下创建一个 index.jsp 文件:

jsp

复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Tomcat Cluster Test</title>
</head>
<body>
    <h1>Tomcat Cluster Test</h1>
    <p>服务器信息: <%= request.getLocalAddr() + ":" + request.getLocalPort() %></p>
    <p>Session ID: <%= session.getId() %></p>
    <p>Session 创建时间: <%= new java.util.Date(session.getCreationTime()) %></p>
    <%
        // 在 Session 中设置一个属性
        String dataName = "testData";
        if (session.getAttribute(dataName) == null) {
            session.setAttribute(dataName, "This is a test data from Tomcat.");
            out.println("<p>Session 数据已创建!</p>");
        } else {
            out.println("<p>Session 数据: " + session.getAttribute(dataName) + "</p>");
        }
    %>
</body>
</html>

启动 Tomcat:分别启动两个 Tomcat 实例。


3. 配置 Nginx 负载均衡

配置 Nginx,让它作为前端反向代理。

编辑 Nginx 的主配置文件 nginx.conf 或者在 conf.d 目录下创建一个新的配置文件(例如 tomcat-cluster.conf)。

nginx

复制代码
# 定义一个上游服务器组,即你的 Tomcat 集群
upstream tomcat_cluster {
    # 策略1: 默认轮询 (Round Robin)
    # 每个请求按时间顺序逐一分配到不同的后端服务器。
    server 127.0.0.1:8080 weight=1; # Tomcat 1
    server 127.0.0.1:8081 weight=1; # Tomcat 2

    # 策略2: 最少连接 (Least Connections)
    # 请求被转发到当前活动连接数最少的后端服务器。
    # least_conn;

    # 策略3: IP 哈希 (IP Hash)
    # 根据访问 IP 的哈希结果分配,确保来自同一 IP 的请求始终定向到同一台后端服务器。
    # ip_hash; 
}

# 配置一个 server 块来接收外部请求
server {
    listen 80;
    server_name 192.168.1.100; # 你的 Nginx 服务器地址或域名

    location / {
        # 将请求代理到上游服务器组
        proxy_pass http://tomcat_cluster;

        # 以下是一些推荐的 proxy 设置
        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;
        
        # 为了 WebSocket 支持 (如果需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # 配置静态资源直接由 Nginx 处理,提高性能
    location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
        # 假设你的静态资源在 Nginx 的 html 目录下
        root /usr/share/nginx/html; 
        expires 30d; # 缓存30天
    }
}

配置说明

  • upstream tomcat_cluster: 定义了一个名为 tomcat_cluster 的服务器池。
  • server 127.0.0.1:8080;: 指定了后端服务器的地址和端口。weight 参数表示权重,权重越高的服务器被分配到请求的概率越大。
  • proxy_pass http://tomcat_cluster;: 这是核心指令,它将当前 location 匹配的所有请求转发到 tomcat_cluster 这个服务器池中。
  • proxy_set_header: 设置一些重要的 HTTP Header,以便后端 Tomcat 能够获取到真实的客户端信息。

检查并重新加载 Nginx 配置

运行

复制代码
# 检查配置语法是否正确
sudo nginx -t

# 如果语法正确,重新加载配置
sudo nginx -s reload

4. 验证与测试

现在,所有配置都已完成。打开你的浏览器,访问 Nginx 的地址:http://192.168.1.100

预期结果

  1. 负载均衡验证

    • 第一次刷新页面,你可能会看到 "服务器信息" 显示 127.0.0.1:8080
    • 第二次刷新页面,你可能会看到 "服务器信息" 显示 127.0.0.1:8081
    • 这证明了 Nginx 正在将请求轮流分发到两个 Tomcat 实例上。
  2. Session 共享验证

    • 在多次刷新页面,切换不同 Tomcat 服务器的过程中,你会发现 "Session ID" 始终是同一个
    • "Session 数据" 也会一直显示,不会因为切换服务器而丢失。
    • 这证明了两个 Tomcat 实例成功地从 Redis 中共享了 Session 信息。
相关推荐
计算机毕设指导62 小时前
基于微信小程序的博物馆文创系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·intellij-idea
我爱学习好爱好爱2 小时前
Prometheus监控栈 监控tomcat和消息队列
消息队列·tomcat·prometheus
saadiya~2 小时前
实战笔记:在 Ubuntu 离线部署 Vue + Nginx 踩坑与避雷指南
vue.js·笔记·nginx
Edward1111111113 小时前
tomcat_servlet
java·servlet·tomcat
胡小禾17 小时前
Tomcat10连接模型
tomcat
秋雨雁南飞20 小时前
Nginx安装
nginx
全栈工程师修炼指南1 天前
Nginx | ngx_cache_purge 模块:实现清除特定上游服务(后端)响应缓存条目
运维·nginx·缓存
清晓粼溪1 天前
SpringCloud-02-LoadBalance服务调用的负载均衡
spring·spring cloud·负载均衡
irisart1 天前
第二章【NGINX 开源功能】—— 四层反向代理
运维·nginx·开源