Nginx+Tomcat+Redis之Session 共享
一、原理
参考:tomcat原理,redis 集群原理与部署,nginx原理与安装,nginx配置章节,示例配置归集
1.1、服务说明
-
Nginx:作为前端反向代理和负载均衡器,接收所有客户端请求,按配置规则分发到后端多个 Tomcat 节点,实现请求分流(负载均衡)。
-
Tomcat 集群:多个 Tomcat 实例部署相同的业务应用,并行处理 Nginx 转发的请求,提升系统并发能力和可用性(单节点故障不影响整体服务)。
-
Redis:作为分布式 Session 存储中心,所有 Tomcat 节点将 Session 数据统一写入 Redis,读取 Session 时也从 Redis 获取,实现多节点 Session 共享。
-
keepalived: 如果没有F5之类的负载可以在加个kp服务(本章没加,还没复习到)
-
逻辑图

-
会话逻辑图

1.2、负载&会话共享原理
- 负载均衡原理(Nginx 侧)
- Nginx 通过
upstream模块定义 Tomcat 集群,支持多种负载均衡策略:- 轮询(默认):请求挨个分,Tomcat 性能一致用。
- 权重(weight):性能好的多接单。
- IP 哈希(ip_hash):基于客户端 IP 哈希分配节点,同一用户固定连一个 Tomcat(会影响负载均衡均匀性)。
- URL 哈希(url_hash):同一网址固定连一个 Tomcat(适合静态资源)。
- Nginx 通过
- Session 共享原理(Redis+Tomcat 侧)
- 默认情况下,Tomcat 的 Session 存储在本地 JVM 内存中,多节点部署时会出现 "Session 不一致" 问题(如用户在 Tomcat1 登录后,请求被转发到 Tomcat2,因 Tomcat2 无该 Session 导致重新登录)。
- 解决方案 :将 Session 从 "Tomcat 本地内存" 迁移到 "分布式 Redis",流程如下:
- 用户首次登录:Tomcat1 验证账号密码成功后,生成 Session 对象,通过
Tomcat-Redis-Session-Manager插件将 Session 数据(SessionID、用户信息、过期时间等)写入 Redis。 - 后续请求:Nginx 将请求转发到任意 Tomcat 节点(如 Tomcat2),Tomcat2 通过 SessionID 从 Redis 读取 Session 数据,验证用户状态,实现 "一次登录,多节点共享"。
- Session 过期:Redis 自动维护 Session 的过期时间(与 Tomcat Session 过期时间一致),过期后自动删除,避免垃圾数据堆积。
- 用户首次登录:Tomcat1 验证账号密码成功后,生成 Session 对象,通过
二、安装配置
2.1、环境准备
-
组件说明
组件 版本建议 作用 Nginx 1.29 反向代理 + 负载均衡 Tomcat 8.5.100 应用服务器( 2 个节点) Redis 7.2.12 分布式 Session 存储 JDK 1.8.461 Tomcat 运行依赖 操作系统 CentOS 7 / 麒麟10 服务器环境 -
节点规划&端口划分
节点 ip地址 tomcat redis集群 nginx node1 10.4.50.130 18080 6379,6380 8080 node2 10.4.50.139 18080 6379,6380 - node3 10.4.50.167 18080 6379,6380 - -
安装配置
-
关闭防火墙或开放端口:
bash# 临时关闭防火墙(CentOS) systemctl stop firewalld # 仅8080对外访问的节点开全局防火培 firewall-cmd --permanent --add-port=8080/tcp # 其它端口间访问用富策略,三台之间互通就行, # 避免生产用久了要修复版本漏洞怪麻烦,如果在机房 ssh端口都建议关掉 firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.4.50.130" protocol value="tcp" accept' firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.4.50.139" protocol value="tcp" accept' firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.4.50.167" protocol value="tcp" accept' firewall-cmd --reload # 部署前先 stop, 实际用的时候在打开防火墙 # 如果要单个放 列表: 18080,6379,6380,16379,16380,8080
2.2、开始配置
-
部署redis session插件
bash# 下载 SLF4J API 包(核心依赖) wget https://repo.huaweicloud.com/repository/maven/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar # 下载 SLF4J 简单绑定包(避免 "Failed to load class org.slf4j.impl.StaticLoggerBinder" 警告) wget https://repo.huaweicloud.com/repository/maven/org/slf4j/slf4j-simple/1.7.36/slf4j-simple-1.7.36.jar # 下载 Jedis(Redis 客户端) wget https://repo.huaweicloud.com/repository/maven/redis/clients/jedis/3.6.3/jedis-3.6.3.jar # 下载 commons-pool2(Jedis 连接池依赖) wget https://repo.huaweicloud.com/repository/maven/org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1.jar redis-session-cluster-plugin.jar <-- 用豆包ai生成的,有点长,已放网盘 or 对应的jar包 顶上的示例配置归集也有- 链接 提取码:1234
-
配置 Tomcat 的 conf/context.xml
-
单机redis
bash<Context> <!-- Redis Session共享配置 --> <Valve className="com.naritech.nicole.gump.RedisSessionHandlerValve" /> <Manager className="com.naritech.nicole.gump.RedisSessionManager" host="192.168.1.100" <!-- Redis服务器IP --> port="6379" <!-- Redis端口 --> password="123456" <!-- Redis密码(无则省略) --> database="0" <!-- Redis数据库编号(默认0) --> maxInactiveInterval="1800" <!-- Session过期时间(秒,与Tomcat默认一致) --> timeout="2000" <!-- Redis连接超时时间 --> /> </Context> -
集群redis <--- 当前示例 完整的整个配置
bash<?xml version="1.0" encoding="UTF-8"?> <Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> <Resources cachingAllowed="true" cacheMaxSize="102400" /> <!-- Redis Cluster Session 共享配置(正确闭合格式) --> <Valve className="com.naritech.nicole.gump.RedisSessionHandlerValve" /> <Manager className="com.naritech.nicole.gump.RedisSessionManager" nodes="10.4.50.130:6379,10.4.50.139:6379,10.4.50.167:6379,10.4.50.130:6380,10.4.50.139:6380,10.4.50.167:6380" password="xiong" database="0" maxInactiveInterval="1800" timeout="3000" maxRedirections="5" cluster="true" /> </Context> -
主从+哨兵模式
bash# 只需填哨兵节点地址 <Manager className="com.naritech.nicole.gump.RedisSessionHandlerValve" sentinelMaster="mymaster" <!-- 哨兵监控的主节点名称 --> sentinels="192.168.1.100:26379,192.168.1.103:26379" <!-- 哨兵节点列表 --> password="123456" database="0" maxInactiveInterval="1800" />
-
-
部署测试应用(验证 Session 共享)
bashmkdir /data/tomcat18080/webapps/ROOT/ vim /data/tomcat18080/webapps/ROOT/index.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.net.InetAddress" %> <%@ page import="java.net.NetworkInterface" %> <%@ page import="java.util.Enumeration" %> <%@ page import="java.io.File" %> <html> <head> <title>Tomcat 核心信息查询(含运行路径)</title> </head> <body> <h3>🎯 Tomcat 核心信息汇总</h3> <hr> <p><strong>📌 Session 信息:</strong></p> <p>Session ID:<%= session.getId() %></p> <p>创建时间:<%= new java.util.Date(session.getCreationTime()) %></p> <p>最后活动时间:<%= new java.util.Date(session.getLastAccessedTime()) %></p> <p>会话超时时间:<%= session.getMaxInactiveInterval() / 60 %> 分钟</p> <hr> <p><strong>🖥️ 服务器信息:改成服务器ip </strong></p> </body> </html>- 三台都要加上,然后访问 ip:18080
-
nginx配置,放到 conf.d/tomcat.conf下
bashupstream backend_servers { server 10.4.50.130:18080 weight=5; # 服务器 1,权重 5(请求占比更高) server 10.4.50.139:18080 weight=3; # 服务器 2,权重 3 server 10.4.50.167:18080 weight=3; # 服务器 2,权重 3 } # 反向代理的 server 块 server { listen 8080; server_name 127.0.0.1; # 客户端访问的域名 # 所有请求转发到 backend_servers 集群 location / { proxy_pass http://backend_servers; # 转发到负载均衡集群 proxy_set_header Host $host; # 传递客户端 Host 头到后端 proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实 IP 到后端 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递代理 proxy_connect_timeout 30; # 与后端服务器连接超时时间 proxy_read_timeout 60; # 读取后端响应超时时间 } }
2.3、功能验证
-
如果nginx访问一台正常, 其它500,那就只能说明你的session会话没有配对,在多检查一下
-
正常如下

三、补充
3.1关键注意事项
- Redis 高可用:生产环境需部署 Redis 主从 + 哨兵或 Redis Cluster,避免 Redis 单点故障导致 Session 丢失。
- Session 过期时间 :Tomcat 的
maxInactiveInterval需与 Redis 的 Session 过期时间一致(默认 1800 秒,即 30 分钟)。 - Jar 包版本兼容:Tomcat、Jedis、commons-pool2 的版本需匹配(如 Tomcat8.5 推荐 Jedis 3.x,避免版本冲突导致 Session 写入失败)。
- Nginx 转发配置 :必须添加
proxy_set_header传递客户端信息,否则 Tomcat 会将 Nginx 的 IP 当作客户端 IP,可能导致 IP 哈希策略失效。