
👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕Java部署这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!
文章目录
- Java 部署:Tomcat 集群部署(负载均衡 + 会话共享) 🚀
-
- 一、为什么需要 Tomcat 集群?🤔
- 二、架构设计概览 🏗️
- 三、环境准备 🛠️
-
- 1. 软件版本要求
- 2. 服务器规划(以 3 节点为例)
- 四、部署 Tomcat 节点 🖥️
-
- 1. 安装 Tomcat
- 2. 配置 server.xml(关键!)
- 3. 部署测试应用
- 五、配置 Nginx 负载均衡 ⚖️
-
- 1. 安装 Nginx
- 2. 配置 upstream 和 proxy
- 3. 重启 Nginx
- 六、实现会话共享:Redis 方案 🧠
-
- 1. 为什么选择 Redis?
- 2. 安装并启动 Redis
- 3. 集成 Tomcat 与 Redis
-
- 步骤 1:下载依赖 JAR
- 步骤 2:配置 context.xml
- 步骤 3:重启 Tomcat
- 七、验证集群功能 ✅
-
- 1. 测试负载均衡
- 2. 测试会话共享
- 3. 查看 Redis 中的 Session
- 八、Java 代码示例:自定义 Session 管理器 🧩
- 九、高级配置与优化 🚀
-
- 1. 会话粘性(Sticky Session) vs 无状态
- 2. 健康检查
- 3. SSL/TLS 终止
- 十、常见问题排查 🛠️
-
- 1. Session 未共享
- 2. 负载不均
- 3. Redis 连接泄漏
- 十一、替代方案对比 📊
- 十二、安全加固 🔒
- 十三、总结 🎯
- 附录:完整架构图 📐
Java 部署:Tomcat 集群部署(负载均衡 + 会话共享) 🚀
在现代 Web 应用开发中,单机部署 Tomcat 已经无法满足高并发、高可用的业务需求。为了提升系统稳定性、可扩展性和容错能力,Tomcat 集群部署成为企业级 Java 应用的标准实践。本文将深入探讨如何通过 负载均衡 + 会话共享 构建一个高可用的 Tomcat 集群,并提供完整的配置步骤与 Java 代码示例。
一、为什么需要 Tomcat 集群?🤔
单台 Tomcat 服务器存在以下瓶颈:
- 性能瓶颈:单机 CPU、内存、网络带宽有限,难以应对高并发请求。
- 单点故障:一旦服务器宕机,整个应用不可用。
- 扩展性差:无法通过增加机器横向扩展服务能力。
而 Tomcat 集群通过以下机制解决上述问题:
✅ 负载均衡(Load Balancing):将用户请求分发到多个 Tomcat 实例,提升吞吐量。 ✅ 会话共享(Session Replication / Sharing):确保用户在不同节点间切换时,登录状态等会话信息不丢失。 ✅ 高可用(High Availability):单个节点故障不影响整体服务。
💡 提示:集群 ≠ 分布式。集群是同一应用的多个副本,分布式是将应用拆分为多个子系统。
二、架构设计概览 🏗️
一个典型的 Tomcat 集群架构如下:
#mermaid-svg-1fm8LW21R6N7cHNu{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1fm8LW21R6N7cHNu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1fm8LW21R6N7cHNu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1fm8LW21R6N7cHNu .error-icon{fill:#552222;}#mermaid-svg-1fm8LW21R6N7cHNu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1fm8LW21R6N7cHNu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1fm8LW21R6N7cHNu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1fm8LW21R6N7cHNu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1fm8LW21R6N7cHNu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1fm8LW21R6N7cHNu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1fm8LW21R6N7cHNu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1fm8LW21R6N7cHNu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1fm8LW21R6N7cHNu .marker.cross{stroke:#333333;}#mermaid-svg-1fm8LW21R6N7cHNu svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1fm8LW21R6N7cHNu p{margin:0;}#mermaid-svg-1fm8LW21R6N7cHNu .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-1fm8LW21R6N7cHNu .cluster-label text{fill:#333;}#mermaid-svg-1fm8LW21R6N7cHNu .cluster-label span{color:#333;}#mermaid-svg-1fm8LW21R6N7cHNu .cluster-label span p{background-color:transparent;}#mermaid-svg-1fm8LW21R6N7cHNu .label text,#mermaid-svg-1fm8LW21R6N7cHNu span{fill:#333;color:#333;}#mermaid-svg-1fm8LW21R6N7cHNu .node rect,#mermaid-svg-1fm8LW21R6N7cHNu .node circle,#mermaid-svg-1fm8LW21R6N7cHNu .node ellipse,#mermaid-svg-1fm8LW21R6N7cHNu .node polygon,#mermaid-svg-1fm8LW21R6N7cHNu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1fm8LW21R6N7cHNu .rough-node .label text,#mermaid-svg-1fm8LW21R6N7cHNu .node .label text,#mermaid-svg-1fm8LW21R6N7cHNu .image-shape .label,#mermaid-svg-1fm8LW21R6N7cHNu .icon-shape .label{text-anchor:middle;}#mermaid-svg-1fm8LW21R6N7cHNu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1fm8LW21R6N7cHNu .rough-node .label,#mermaid-svg-1fm8LW21R6N7cHNu .node .label,#mermaid-svg-1fm8LW21R6N7cHNu .image-shape .label,#mermaid-svg-1fm8LW21R6N7cHNu .icon-shape .label{text-align:center;}#mermaid-svg-1fm8LW21R6N7cHNu .node.clickable{cursor:pointer;}#mermaid-svg-1fm8LW21R6N7cHNu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1fm8LW21R6N7cHNu .arrowheadPath{fill:#333333;}#mermaid-svg-1fm8LW21R6N7cHNu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1fm8LW21R6N7cHNu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1fm8LW21R6N7cHNu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1fm8LW21R6N7cHNu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1fm8LW21R6N7cHNu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1fm8LW21R6N7cHNu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1fm8LW21R6N7cHNu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1fm8LW21R6N7cHNu .cluster text{fill:#333;}#mermaid-svg-1fm8LW21R6N7cHNu .cluster span{color:#333;}#mermaid-svg-1fm8LW21R6N7cHNu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1fm8LW21R6N7cHNu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1fm8LW21R6N7cHNu rect.text{fill:none;stroke-width:0;}#mermaid-svg-1fm8LW21R6N7cHNu .icon-shape,#mermaid-svg-1fm8LW21R6N7cHNu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1fm8LW21R6N7cHNu .icon-shape p,#mermaid-svg-1fm8LW21R6N7cHNu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1fm8LW21R6N7cHNu .icon-shape rect,#mermaid-svg-1fm8LW21R6N7cHNu .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1fm8LW21R6N7cHNu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1fm8LW21R6N7cHNu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1fm8LW21R6N7cHNu :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Client
Nginx / Apache
Tomcat 1
Tomcat 2
Tomcat 3
Redis / MySQL / Memcached
- 前端负载均衡器:Nginx 或 Apache HTTP Server,负责请求分发。
- 后端 Tomcat 节点:多个运行相同 Web 应用的 Tomcat 实例。
- 会话存储中心:Redis、MySQL 或 Memcached,用于集中存储 Session 数据。
🔗 Nginx 官方文档 提供了详细的负载均衡配置指南。
三、环境准备 🛠️
1. 软件版本要求
| Java | JDK 8+(推荐 JDK 11 或 17) |
| Tomcat | 9.x 或 10.x |
| Nginx | 1.18+ |
| Redis | 6.x+(用于会话共享) |
2. 服务器规划(以 3 节点为例)
| nginx-server | 192.168.1.10 | Nginx 负载均衡器 |
| tomcat-node1 | 192.168.1.11 | Tomcat 实例 1 |
| tomcat-node2 | 192.168.1.12 | Tomcat 实例 2 |
| tomcat-node3 | 192.168.1.13 | Tomcat 实例 3 |
| redis-server | 192.168.1.20 | Redis 会话存储 |
⚠️ 所有服务器需关闭防火墙或开放对应端口(如 8080、6379、80 等)。
四、部署 Tomcat 节点 🖥️
1. 安装 Tomcat
在每台 Tomcat 节点上执行:
# 下载 Tomcat(以 9.0.85 为例)
wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.85/bin/apache-tomcat-9.0.85.tar.gz
tar -zxvf apache-tomcat-9.0.85.tar.gz
mv apache-tomcat-9.0.85 /opt/tomcat
2. 配置 server.xml(关键!)
为每个节点设置唯一的 jvmRoute,用于会话粘性(Sticky Session):
tomcat-node1 的 conf/server.xml:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="node1">
tomcat-node2:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="node2">
tomcat-node3:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="node3">
✅ jvmRoute 必须与 Nginx 中 upstream 的 server 名称一致。
3. 部署测试应用
创建一个简单的 Web 应用 cluster-demo.war,包含以下文件:
目录结构:
cluster-demo/
├── WEB-INF/
│ └── web.xml
└── index.jsp
web.xml(无需特殊配置):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Cluster Demo</display-name>
</web-app>
index.jsp(关键!用于测试会话和节点识别):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 获取当前会话ID
String sessionId = session.getId();
// 设置一个计数器,每次访问+1
Integer count = (Integer) session.getAttribute("visitCount");
if (count == null) count = 0;
count++;
session.setAttribute("visitCount", count);
%>
<html>
<head><title>Tomcat Cluster Test</title></head>
<body>
<h2>🎉 欢迎访问 Tomcat 集群!</h2>
<p>当前会话 ID: <strong><%= sessionId %></strong></p>
<p>您已访问本页面 <strong><%= count %></strong> 次。</p>
<p>当前处理节点: <strong>
<%
String jvmRoute = request.getServletContext().getServerInfo();
// 更准确的方式:通过 JSESSIONID 判断
String cookie = request.getHeader("Cookie");
if (cookie != null && cookie.contains("JSESSIONID")) {
String[] parts = cookie.split("JSESSIONID=");
if (parts.length > 1) {
String jsession = parts[1].split(";")[0];
if (jsession.contains(".node1")) out.print("Node 1 (192.168.1.11)");
else if (jsession.contains(".node2")) out.print("Node 2 (192.168.1.12)");
else if (jsession.contains(".node3")) out.print("Node 3 (192.168.1.13)");
else out.print("Unknown Node");
}
}
%>
</strong></p>
<br>
<a href="index.jsp">刷新页面</a>
</body>
</html>
将 cluster-demo.war 复制到所有 Tomcat 节点的 webapps/ 目录下。
五、配置 Nginx 负载均衡 ⚖️
在 nginx-server 上安装并配置 Nginx。
1. 安装 Nginx
# Ubuntu/Debian
sudo apt update && sudo apt install nginx
# CentOS/RHEL
sudo yum install nginx
2. 配置 upstream 和 proxy
编辑 /etc/nginx/sites-available/default 或新建配置文件:
upstream tomcat_cluster {
# 启用 sticky session(基于 cookie)
ip_hash; # 可选:基于 IP 的会话保持
# 或使用更灵活的 sticky cookie(需 nginx-plus 或第三方模块)
# sticky cookie srv_id expires=1h domain=.example.com path=/;
server 192.168.1.11:8080 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.1.12:8080 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.1.13:8080 weight=1 max_fails=2 fail_timeout=30s;
}
server {
listen 80;
server_name cluster.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;
proxy_set_header X-Forwarded-Proto $scheme;
# 重要:传递 JSESSIONID cookie
proxy_cookie_path / "/; HTTPOnly; Secure";
}
# 健康检查(可选)
location /status {
access_log off;
allow 127.0.0.1;
deny all;
stub_status on;
}
}
🔗 Nginx 负载均衡官方指南 提供了更多策略(如 least_conn、hash 等)。
3. 重启 Nginx
sudo nginx -t # 测试配置
sudo systemctl reload nginx
六、实现会话共享:Redis 方案 🧠
默认情况下,Tomcat 的 Session 存储在内存中,集群环境下无法共享。我们需要将会话数据持久化到外部存储。
1. 为什么选择 Redis?
- 高性能:内存数据库,读写极快。
- 支持过期:自动清理过期 Session。
- 成熟生态:有成熟的 Tomcat 插件支持。
🔗 Redis 官方文档 详细介绍了其数据结构和配置。
2. 安装并启动 Redis
在 redis-server 上:
# Ubuntu
sudo apt install redis-server
sudo systemctl start redis
sudo systemctl enable redis
编辑 /etc/redis/redis.conf,确保:
bind 0.0.0.0 # 允许远程连接
protected-mode no # 关闭保护模式(生产环境应设密码)
port 6379
timeout 0
tcp-keepalive 300
重启 Redis:
sudo systemctl restart redis
3. 集成 Tomcat 与 Redis
我们使用开源项目 Tomcat Redis Session Manager(简称 TRSM)。
步骤 1:下载依赖 JAR
将以下 JAR 文件放入每个 Tomcat 节点的 lib/ 目录:
- tomcat-redis-session-manager-VERSION.jar
- jedis-3.6.0.jar(Redis 客户端)
- commons-pool2-2.11.1.jar(连接池)
💡 由于不能提供 GitHub 地址,建议通过 Maven Central 搜索 tomcat-redis-session-manager 获取最新版。
步骤 2:配置 context.xml
在每个 Tomcat 节点的 conf/context.xml 中添加:
<Context>
<!– 其他配置… –>
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.1.20"
port="6379"
database="0"
maxInactiveInterval="1800"
sessionPersistPolicies="PERSIST_POLICY_DEFAULT"
sentinelMaster=""
sentinels=""
connectionTimeout="2000"
soTimeout="2000"
password=""
clientName="" />
</Context>
⚠️ 注意:className 必须与你使用的 JAR 包中的类路径一致。
步骤 3:重启 Tomcat
/opt/tomcat/bin/shutdown.sh
/opt/tomcat/bin/startup.sh
七、验证集群功能 ✅
1. 测试负载均衡
访问 http://192.168.1.10/cluster-demo/(Nginx 地址),多次刷新页面:
- 如果使用 ip_hash,同一客户端始终访问同一节点。
- 如果使用轮询(默认),节点会轮换。
观察页面显示的“当前处理节点”是否变化。
2. 测试会话共享
- 在页面上看到“访问次数”为 1。
- 刷新几次,次数递增。
- 手动停止当前节点的 Tomcat(如 node1)。
- 再次刷新,请求被转发到其他节点(如 node2)。
- 关键:访问次数应继续递增,而非重置为 1!
这证明 Session 已成功共享。
3. 查看 Redis 中的 Session
在 Redis 服务器上执行:
redis-cli
KEYS *
GET "r:YOUR_SESSION_ID"
你会看到类似:
"\\xac\\xed\\x00\\x05sr\\x00Kcom.orangefunction.tomcat.redissessions.SessionSerializationMetadata…"
说明 Session 已序列化存储。
八、Java 代码示例:自定义 Session 管理器 🧩
虽然 TRSM 已足够,但了解底层原理有助于调试。下面是一个简化版的 Redis Session 存储工具类:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.*;
import java.util.Base64;
public class RedisSessionStore {
private static final String SESSION_PREFIX = "session:";
private static JedisPool jedisPool;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(20);
config.setMaxIdle(10);
jedisPool = new JedisPool(config, "192.168.1.20", 6379);
}
/**
* 保存 Session 对象到 Redis
*/
public static void saveSession(String sessionId, Object sessionData) {
try (Jedis jedis = jedisPool.getResource()) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(sessionData);
oos.flush();
byte[] data = bos.toByteArray();
String encoded = Base64.getEncoder().encodeToString(data);
jedis.setex(SESSION_PREFIX + sessionId, 1800, encoded); // 30分钟过期
} catch (IOException e) {
throw new RuntimeException("Failed to serialize session", e);
}
}
/**
* 从 Redis 读取 Session
*/
public static Object getSession(String sessionId) {
try (Jedis jedis = jedisPool.getResource()) {
String encoded = jedis.get(SESSION_PREFIX + sessionId);
if (encoded == null) return null;
byte[] data = Base64.getDecoder().decode(encoded);
ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
} catch (Exception e) {
throw new RuntimeException("Failed to deserialize session", e);
}
}
/**
* 删除 Session
*/
public static void removeSession(String sessionId) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.del(SESSION_PREFIX + sessionId);
}
}
}
⚠️ 注意:实际生产中应使用更安全的序列化方式(如 JSON、Protobuf),避免 Java 原生序列化的安全风险。
九、高级配置与优化 🚀
1. 会话粘性(Sticky Session) vs 无状态
- Sticky Session:Nginx 将同一用户始终路由到同一 Tomcat。优点是减少跨节点 Session 访问;缺点是节点故障时需重新登录。
- 无状态(Stateless):每次请求都从 Redis 读取 Session。更灵活,但增加 Redis 压力。
建议:开启 Sticky Session + Redis 会话共享,兼顾性能与容错。
2. 健康检查
在 Nginx 中配置主动健康检查(需商业版或使用第三方模块):
upstream tomcat_cluster {
zone tomcat_cluster 64k;
server 192.168.1.11:8080 max_fails=1 fail_timeout=10s;
server 192.168.1.12:8080 max_fails=1 fail_timeout=10s;
server 192.168.1.13:8080 max_fails=1 fail_timeout=10s;
# 被动健康检查已足够
}
或在 Tomcat 中暴露 /health 接口,由外部监控系统调用。
3. SSL/TLS 终止
在 Nginx 上配置 HTTPS,卸载 Tomcat 的加密负担:
server {
listen 443 ssl;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# … 其他配置
location / {
proxy_pass http://tomcat_cluster;
proxy_set_header X-Forwarded-Proto https;
}
}
十、常见问题排查 🛠️
1. Session 未共享
- 检查 context.xml 中的 Manager 配置是否正确。
- 确认 Redis 可访问(telnet 192.168.1.20 6379)。
- 查看 Tomcat 日志是否有 ClassNotFoundException(缺少 JAR)。
2. 负载不均
- 检查 Nginx 是否启用了 ip_hash(会导致同一 IP 始终访问同一节点)。
- 使用 ab 或 wrk 压测,观察各节点日志。
3. Redis 连接泄漏
- 确保使用连接池(如 JedisPool)。
- 监控 Redis 的 connected_clients 数量。
十一、替代方案对比 📊
| Redis | 高性能、易部署 | 需维护 Redis | 通用首选 |
| Memcached | 轻量、快速 | 不支持持久化 | 纯缓存场景 |
| Tomcat 自带 DeltaManager | 无需外部依赖 | 广播风暴、扩展性差 | 小型集群(≤3节点) |
| 数据库(MySQL) | 持久化、可靠 | 性能较低 | 对一致性要求极高 |
💡 对于大多数场景,Redis 是最佳选择。
十二、安全加固 🔒
Redis 密码认证:
# redis.conf
requirepass your_strong_password
并在 context.xml 中添加 password="your_strong_password"。
禁用 Redis 危险命令:
rename-command FLUSHDB ""
rename-command FLUSHALL ""
Nginx 隐藏版本号:
server_tokens off;
Tomcat 安全:
- 删除 webapps 下的默认应用(docs, examples 等)。
- 限制管理端口访问。
十三、总结 🎯
通过本文,我们完成了:
✅ 部署多节点 Tomcat 集群 ✅ 配置 Nginx 实现负载均衡 ✅ 集成 Redis 实现会话共享 ✅ 编写 Java 代码验证集群行为 ✅ 提供生产环境优化建议
Tomcat 集群部署虽有一定复杂度,但它是构建高可用 Java Web 应用的基石。掌握这一技能,将为你在企业级开发中打下坚实基础。
🌟 最后建议:在生产环境中,务必结合监控(如 Prometheus + Grafana)、日志收集(ELK)和自动化部署(Ansible/Docker)来管理集群。
附录:完整架构图 📐
#mermaid-svg-woGmkCURshdehPca{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-woGmkCURshdehPca .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-woGmkCURshdehPca .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-woGmkCURshdehPca .error-icon{fill:#552222;}#mermaid-svg-woGmkCURshdehPca .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-woGmkCURshdehPca .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-woGmkCURshdehPca .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-woGmkCURshdehPca .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-woGmkCURshdehPca .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-woGmkCURshdehPca .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-woGmkCURshdehPca .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-woGmkCURshdehPca .marker{fill:#333333;stroke:#333333;}#mermaid-svg-woGmkCURshdehPca .marker.cross{stroke:#333333;}#mermaid-svg-woGmkCURshdehPca svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-woGmkCURshdehPca p{margin:0;}#mermaid-svg-woGmkCURshdehPca .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-woGmkCURshdehPca .cluster-label text{fill:#333;}#mermaid-svg-woGmkCURshdehPca .cluster-label span{color:#333;}#mermaid-svg-woGmkCURshdehPca .cluster-label span p{background-color:transparent;}#mermaid-svg-woGmkCURshdehPca .label text,#mermaid-svg-woGmkCURshdehPca span{fill:#333;color:#333;}#mermaid-svg-woGmkCURshdehPca .node rect,#mermaid-svg-woGmkCURshdehPca .node circle,#mermaid-svg-woGmkCURshdehPca .node ellipse,#mermaid-svg-woGmkCURshdehPca .node polygon,#mermaid-svg-woGmkCURshdehPca .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-woGmkCURshdehPca .rough-node .label text,#mermaid-svg-woGmkCURshdehPca .node .label text,#mermaid-svg-woGmkCURshdehPca .image-shape .label,#mermaid-svg-woGmkCURshdehPca .icon-shape .label{text-anchor:middle;}#mermaid-svg-woGmkCURshdehPca .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-woGmkCURshdehPca .rough-node .label,#mermaid-svg-woGmkCURshdehPca .node .label,#mermaid-svg-woGmkCURshdehPca .image-shape .label,#mermaid-svg-woGmkCURshdehPca .icon-shape .label{text-align:center;}#mermaid-svg-woGmkCURshdehPca .node.clickable{cursor:pointer;}#mermaid-svg-woGmkCURshdehPca .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-woGmkCURshdehPca .arrowheadPath{fill:#333333;}#mermaid-svg-woGmkCURshdehPca .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-woGmkCURshdehPca .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-woGmkCURshdehPca .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-woGmkCURshdehPca .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-woGmkCURshdehPca .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-woGmkCURshdehPca .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-woGmkCURshdehPca .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-woGmkCURshdehPca .cluster text{fill:#333;}#mermaid-svg-woGmkCURshdehPca .cluster span{color:#333;}#mermaid-svg-woGmkCURshdehPca div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-woGmkCURshdehPca .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-woGmkCURshdehPca rect.text{fill:none;stroke-width:0;}#mermaid-svg-woGmkCURshdehPca .icon-shape,#mermaid-svg-woGmkCURshdehPca .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-woGmkCURshdehPca .icon-shape p,#mermaid-svg-woGmkCURshdehPca .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-woGmkCURshdehPca .icon-shape rect,#mermaid-svg-woGmkCURshdehPca .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-woGmkCURshdehPca .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-woGmkCURshdehPca .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-woGmkCURshdehPca :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Session Store
Application Servers
Load Balancer
HTTP/HTTPS
Proxy
Proxy
Proxy
Read/Write
Read/Write
Read/Write
Client
Nginx
Tomcat Node 1\\njvmRoute=node1
Tomcat Node 2\\njvmRoute=node2
Tomcat Node 3\\njvmRoute=node3
Redis Server\\n192.168.1.20:6379
现在,你已经具备了构建高可用 Tomcat 集群的能力!动手实践吧,遇到问题欢迎留言讨论 💬。
🙌 感谢你读到这里! 🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。 💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友! 💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿 🔔 关注我,不错过下一篇干货!我们下期再见!✨



