Java 部署:Tomcat 集群部署(负载均衡 + 会话共享)

Java 部署:Tomcat 集群部署(负载均衡 + 会话共享)
在这里插入图片描述
👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Java部署这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!

文章目录

Java 部署:Tomcat 集群部署(负载均衡 + 会话共享) 🚀

在现代 Web 应用开发中,单机部署 Tomcat 已经无法满足高并发、高可用的业务需求。为了提升系统稳定性、可扩展性和容错能力,Tomcat 集群部署成为企业级 Java 应用的标准实践。本文将深入探讨如何通过 负载均衡 + 会话共享 构建一个高可用的 Tomcat 集群,并提供完整的配置步骤与 Java 代码示例。


一、为什么需要 Tomcat 集群?🤔

单台 Tomcat 服务器存在以下瓶颈:

  • 性能瓶颈:单机 CPU、内存、网络带宽有限,难以应对高并发请求。
  • 单点故障:一旦服务器宕机,整个应用不可用。
  • 扩展性差:无法通过增加机器横向扩展服务能力。

而 Tomcat 集群通过以下机制解决上述问题:

负载均衡(Load Balancing):将用户请求分发到多个 Tomcat 实例,提升吞吐量。
会话共享(Session Replication / Sharing):确保用户在不同节点间切换时,登录状态等会话信息不丢失。
高可用(High Availability):单个节点故障不影响整体服务。

💡 提示:集群 ≠ 分布式。集群是同一应用的多个副本,分布式是将应用拆分为多个子系统。

二、架构设计概览 🏗️

一个典型的 Tomcat 集群架构如下:

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. 软件版本要求

组件版本建议
JavaJDK 8+(推荐 JDK 11 或 17)
Tomcat9.x 或 10.x
Nginx1.18+
Redis6.x+(用于会话共享)

2. 服务器规划(以 3 节点为例)

主机名IP 地址角色
nginx-server192.168.1.10Nginx 负载均衡器
tomcat-node1192.168.1.11Tomcat 实例 1
tomcat-node2192.168.1.12Tomcat 实例 2
tomcat-node3192.168.1.13Tomcat 实例 3
redis-server192.168.1.20Redis 会话存储
⚠️ 所有服务器需关闭防火墙或开放对应端口(如 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

<Enginename="Catalina"defaultHost="localhost"jvmRoute="node1">

tomcat-node2

<Enginename="Catalina"defaultHost="localhost"jvmRoute="node2">

tomcat-node3

<Enginename="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-appxmlns="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/Debiansudoapt update &&sudoaptinstall nginx # CentOS/RHELsudo 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 上:

# Ubuntusudoaptinstall 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><!-- 其他配置... --><ValveclassName="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve"/><ManagerclassName="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 存储工具类

importredis.clients.jedis.Jedis;importredis.clients.jedis.JedisPool;importredis.clients.jedis.JedisPoolConfig;importjava.io.*;importjava.util.Base64;publicclassRedisSessionStore{privatestaticfinalString SESSION_PREFIX ="session:";privatestaticJedisPool jedisPool;static{JedisPoolConfig config =newJedisPoolConfig(); config.setMaxTotal(20); config.setMaxIdle(10); jedisPool =newJedisPool(config,"192.168.1.20",6379);}/** * 保存 Session 对象到 Redis */publicstaticvoidsaveSession(String sessionId,Object sessionData){try(Jedis jedis = jedisPool.getResource()){ByteArrayOutputStream bos =newByteArrayOutputStream();ObjectOutputStream oos =newObjectOutputStream(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){thrownewRuntimeException("Failed to serialize session", e);}}/** * 从 Redis 读取 Session */publicstaticObjectgetSession(String sessionId){try(Jedis jedis = jedisPool.getResource()){String encoded = jedis.get(SESSION_PREFIX + sessionId);if(encoded ==null)returnnull;byte[] data =Base64.getDecoder().decode(encoded);ByteArrayInputStream bis =newByteArrayInputStream(data);ObjectInputStream ois =newObjectInputStream(bis);return ois.readObject();}catch(Exception e){thrownewRuntimeException("Failed to deserialize session", e);}}/** * 删除 Session */publicstaticvoidremoveSession(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 始终访问同一节点)。
  • 使用 abwrk 压测,观察各节点日志。

3. Redis 连接泄漏

  • 确保使用连接池(如 JedisPool)。
  • 监控 Redis 的 connected_clients 数量。

十一、替代方案对比 📊

方案优点缺点适用场景
Redis高性能、易部署需维护 Redis通用首选
Memcached轻量、快速不支持持久化纯缓存场景
Tomcat 自带 DeltaManager无需外部依赖广播风暴、扩展性差小型集群(≤3节点)
数据库(MySQL)持久化、可靠性能较低对一致性要求极高
💡 对于大多数场景,Redis 是最佳选择

十二、安全加固 🔒

  1. Tomcat 安全
    • 删除 webapps 下的默认应用(docs, examples 等)。
    • 限制管理端口访问。

Nginx 隐藏版本号

server_tokens off; 

禁用 Redis 危险命令

rename-command FLUSHDB "" rename-command FLUSHALL "" 

Redis 密码认证

# redis.conf requirepass your_strong_password 

并在 context.xml 中添加 password="your_strong_password"


十三、总结 🎯

通过本文,我们完成了:

✅ 部署多节点 Tomcat 集群
✅ 配置 Nginx 实现负载均衡
✅ 集成 Redis 实现会话共享
✅ 编写 Java 代码验证集群行为
✅ 提供生产环境优化建议

Tomcat 集群部署虽有一定复杂度,但它是构建高可用 Java Web 应用的基石。掌握这一技能,将为你在企业级开发中打下坚实基础。

🌟 最后建议:在生产环境中,务必结合监控(如 Prometheus + Grafana)、日志收集(ELK)和自动化部署(Ansible/Docker)来管理集群。

附录:完整架构图 📐

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 集群的能力!动手实践吧,遇到问题欢迎留言讨论 💬。


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Read more

【HarmonyOS 6.0】Media Kit:细粒度控制屏幕捕获,详解图像填充模式C API

【HarmonyOS 6.0】Media Kit:细粒度控制屏幕捕获,详解图像填充模式C API

文章目录 * 1 -> 概述:从“能录”到“录得好”——Media Kit的战略性升级 * 2 -> 基础概念:理解屏幕捕获中的“画布”与“填充” * 2.1 -> 捕获源与目标区域 * 2.2 -> 矛盾的焦点:宽高比不一致 * 2.3 -> 填充模式 (`OH_AVScreenCapture_FillMode`) * 3 -> API详解:设置捕获策略的完整链路 * 3.1 -> 核心数据结构:`OH_AVScreenCapture_

By Ne0inhk
云开发 Copilot ——让开发变得更简单

云开发 Copilot ——让开发变得更简单

声明:本篇博客为云开发 Copilot体验文章,非广告 目录 前言: 游客体验 云开发 Copilot实战: 一、图片生成需求 二、云开发 Copilot实现需求 三、AI生成低代码页面 Copilot 的亮点功能 使用场景 云开发 Copilot开发的前景展望 前言: 在云开发AI+中,腾讯云提供一系列与 AI 相关的功能,如大模型接入、 Agent 等,帮助开发者为自己的小程序、web 或者应用快速接入 AI 能力,同时也提供了云开发 Copilot,来加速用户的开发,帮助用户更快构建自己的应用。下面博主将会为大家实战使用云开发 Copilot来助力开发。 云开发 Copilot是云开发推出的一款 AI 开发辅助工具,可以帮助用户快速生成多种类型的应用功能,包括低代码应用、页面、组件、数据模型、

By Ne0inhk

龙虾尝鲜记(2)——装ubuntu(续)

装 ubuntu 还折腾了好几下,现在终于把系统能稳妥了。回头再来记一下,给看到想弄龙虾的同学提个醒,对应工作先做到前面,免得遇到问题解决不了,还没入门就出门了。         一、系统版本的确定         这个问题我个人以为要结合自己的实际情况:如果是在虚拟机上装,建议选择 2404 LTS,相对稳定;如果是在实体机上装,要根据自己的硬件来避坑,据某 AI 说对 N 卡的支持不是很好,有特定的版本要求。还有就是是否强烈需要蓝牙、指纹、隐藏网络、摄像头等方面的功能。         因为装(实体机) 2404 2404 就是因为驱动(MX250)有些问题,折腾了好几下实在懒得折腾就问了下 AI,它给推荐了 Pop_OS 2404, 结果掉进更大的坑里:蓝牙键盘连上了打不出字来、指纹不能用(到现在也不能用,因为指纹不太关痛痒,没修复好就暂时作罢)、无法连接到隐藏网络……         指纹不能用问题不大,

By Ne0inhk
LLaMA-Factory使用

LLaMA-Factory使用

文章目录 * 一、LLAMA-Factory简介 * 二、安装LLaMA-Factory * 三、准备训练数据 * 四、模型训练 * 1. 模型下载 * 2. 全量微调 * 3.lora微调 * 4.QLora微调 * 五、合并模型权重 * 1.模型合并 * 2.测试 一、LLAMA-Factory简介 LLaMA-Factory是一个简单易用且高效的大模型训练框架,支持上百种大模型的训练,框架特性主要包括: * 模型种类:LLaMA、LLaVA、Mistral、Mixtral-MoE、Qwen、Yi、Gemma、Baichuan、ChatGLM、Phi 等等。 * 训练算法:(增量)预训练、(多模态)指令监督微调、奖励模型训练、PPO 训练、DPO 训练、

By Ne0inhk