使用 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 信息。
相关推荐
何中应3 天前
Nginx转发请求错误
前端·后端·nginx
大大水瓶4 天前
Tomcat
java·tomcat
芝士雪豹只抽瑞克五4 天前
Nginx 高性能Web服务器笔记
服务器·nginx
失重外太空啦4 天前
Tomcat
java·服务器·tomcat
屎到临头想搅便4 天前
TOMCAT
java·tomcat
失重外太空啦4 天前
nginx
运维·nginx
大大水瓶4 天前
HAProxy 从入门到实战:负载均衡与流量管理全解析
运维·负载均衡
微风起皱4 天前
企业级WEB应用服务器TOMCAT
java·前端·tomcat
天蓝不会忘记024 天前
lvs,haproxy,keepalived,nginx,tomcat介绍和实验
nginx·tomcat·lvs