整个过程可以分为以下几个核心步骤:
- 环境准备:准备好 Nginx 和多个 Tomcat 实例。
- 配置 Tomcat 集群 :确保所有 Tomcat 实例配置一致,并能通过
session共享来维持用户登录状态。 - 配置 Nginx 负载均衡:设置 Nginx 反向代理,将请求分发到不同的 Tomcat 实例。
- 验证与测试:验证集群是否正常工作。
1. 环境准备
- 一台 Nginx 服务器:用于接收外部请求并分发。
- 两台或多台 Tomcat 服务器 :构成应用服务器集群。为了简单演示,我们可以在同一台服务器上启动多个 Tomcat 实例,通过修改端口来区分它们。
示例场景:
- Nginx 服务器 :
192.168.1.100,监听80端口。 - Tomcat 集群 :
- Tomcat 1: 监听
8080端口 - Tomcat 2: 监听
8081端口
- Tomcat 1: 监听
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。
预期结果:
-
负载均衡验证:
- 第一次刷新页面,你可能会看到 "服务器信息" 显示
127.0.0.1:8080。 - 第二次刷新页面,你可能会看到 "服务器信息" 显示
127.0.0.1:8081。 - 这证明了 Nginx 正在将请求轮流分发到两个 Tomcat 实例上。
- 第一次刷新页面,你可能会看到 "服务器信息" 显示
-
Session 共享验证:
- 在多次刷新页面,切换不同 Tomcat 服务器的过程中,你会发现 "Session ID" 始终是同一个。
- "Session 数据" 也会一直显示,不会因为切换服务器而丢失。
- 这证明了两个 Tomcat 实例成功地从 Redis 中共享了 Session 信息。