Tomcat8集群Redis Session共享实战:配置、链路与排错

发布时间:2026/10/27 20:11:08
Tomcat8集群Redis Session共享实战:配置、链路与排错 简介这份包集合面向在 Tomcat 8 与 JDK 1.8 环境下开发、需要解决分布式会话共享问题的 Java 开发者核心是把 Redis 接入 Tomcat 的 Session 管理流程让多实例之间能够读取一致的会话数据从而减轻单机内存压力并提升横向扩展能力。压缩包共 6 个文件包含 4 个 jar 依赖、1 个 xml 配置示例和 1 个 txt 说明文档整体约 445KB便于直接补齐集成所需组件并对照配置项。已有 941 人学习或下载。包内将 Redis 会话存储所需的依赖与基础配置集中在一起读者可据此了解 SessionManager 替换、连接参数设置和序列化选择等关键环节减少逐个查找版本与依赖的时间也方便在测试环境中快速验证会话迁移和共享效果。1. tomcat8 双节点登录态乱跳这套 Redis session 包到底顶不顶用单机 Tomcat8 跑得好好的一上两台就出现登录态乱跳十有八九不是登录逻辑坏了而是 session 还留在各自 JVM 里。tomcat-redis-session-manager 这类包集合解决的就是把 session 从 Tomcat 本地内存搬到 Redis让 tomcat8 集群里任意节点都能认同一份会话。它适合已经在用 Redis、又不想把应用改成无状态 token 的团队尤其是老系统只换会话存储、不动业务代码的场景。这套包不是 Spring Session不依赖框架改造核心是替换 Tomcat 的 Manager 和 Valve。好处是接入面小代价是 jar 必须由容器类加载器可见序列化边界也得自己兜住。后面按包集合、配置、链路、参数和排查顺序拆新手能照做熟手重点看第 4、5 章的边界。2. 包集合落进 Tomcat8jar 放哪、context.xml 怎么写、启动看什么拿到包集合后先别急着把 jar 复制到应用的 WEB-INF/lib。Tomcat8 里 context.xml 声明的 Manager 是容器组件实例化它的是容器类加载器不是应用类加载器。放错位置启动日志会直接抛 ClassNotFoundException很多人会误以为是包不完整实际上是类加载器没看见。2.1 包集合的组成与类加载位置包集合通常由主 jar、Jedis 客户端和 commons-pool2 连接池组成有的分支还会带示例 context.xml 或 README。主 jar 提供 RedisSessionManager 和 RedisSessionHandlerValveJedis 负责跟 Redis 通信commons-pool2 负责连接池。这三类东西必须让 Tomcat 容器加载到所以我一般统一放 $CATALINA_HOME/lib而不是 WEB-INF/lib。业务应用里不要再带同名不同版本的 Jedis 和 commons-pool2。容器 lib 里有一份应用里再带一份类加载时容易出现 NoSuchMethodError 或 LinkageError这种冲突比配置写错更难查。血泪经验是先备份 lib再复制最后用 find 扫一遍 webapps 下有没有残留 jar。备份不是形式回滚时没有备份就得重新找包。# 进入 Tomcat 安装目录先备份原 lib避免回滚时抓瞎 cd /opt/tomcat8 tar -czf lib-backup-$(date %F).tar.gz lib # 把包集合里的主 jar、Jedis、commons-pool2 复制到容器 lib cp /tmp/tomcat-redis-session-manager-package/*.jar $CATALINA_HOME/lib/ # 确认 webapps 下没有残留的 Jedis 或连接池 jar输出为空最好 find $CATALINA_HOME/webapps -name jedis-*.jar -o -name commons-pool2-*.jar上面三段命令分别做备份、复制、冲突检查。$CATALINA_HOME 要指向实际的 Tomcat8 目录不要照抄 /opt/tomcat8。cp 用通配符是为了少写文件名但复制完要确认目标目录里没有同名旧 jar 被覆盖后版本错位。find 的输出如果非空说明应用自带同类依赖需要在打包时排除或者统一到容器 lib 的版本。提示主 jar 和依赖 jar 都放 $CATALINA_HOME/lib不要只放主 jar。漏了 Jedis 或 commons-pool2启动时同样会报类找不到。还有一个容易忽略的点是文件权限。用 root 复制、用 tomcat 用户启动时jar 权限至少要可读。复制完可以顺手看一眼 ls -l确认 tomcat 用户能读。权限问题不会在编译期暴露只会在容器启动加载 Manager 时翻车。2.2 context.xml 的 Manager/Valve 配置配置位置有三种conf/context.xml 是全局conf/Catalina/localhost/ .xml 是应用级war 内 META-INF/context.xml 会被 Tomcat 复制到 conf/Catalina/localhost。全局配置会影响同一个 Tomcat 下所有应用多应用共用一个容器时很容易串 session所以我更倾向应用级配置。文件名要和 context path 对上比如应用部署为 app.war就写 conf/Catalina/localhost/app.xml。Context !-- Valve 负责在请求结束时把变更后的 session 写回 Redis -- Valve classNamecom.orangefunction.tomcat.redissessions.RedisSessionHandlerValve / !-- Manager 负责 session 的创建、查找、过期和持久化 -- Manager classNamecom.orangefunction.tomcat.redissessions.RedisSessionManager host127.0.0.1 port6379 database0 password timeout2000 maxInactiveInterval1800 / /ContextclassName 以包内实际类名为准不同分支可能改过包名配置前先看 jar 里的类。Valve 放在 Manager 前面两个都要配只配 Manager 常见表现是 session 能读但写回不及时或者过期时间不刷新。host、port、database、password 是 Redis 连接四件套timeout 是连接和读写超时maxInactiveInterval 是会话空闲过期秒数。参数示例值作用边界host127.0.0.1Redis 地址排查时别混用 localhost 和 IPv6 解析port6379Redis 端口和实际实例一致database0选库session 单独库避免和缓存混用password空认证有密码必须填空字符串不等于没配置timeout2000连接/读写超时太小频繁超时太大请求堆积maxInactiveInterval1800会话过期秒数与业务登录超时对齐属性名不同分支可能有差异比如连接池参数叫 maxTotal 还是 maxTotalConnections以类里的 setter 为准。配置改完要重启 Tomcat不要只热部署应用。war 内 META-INF/context.xml 被复制到 conf/Catalina/localhost 后后续改 war 里的文件不一定生效得看实际部署目录下的那份。注意同一个 context 不要同时保留旧的 Manager 配置。两个 Manager 同时存在时行为不可预测日志也不一定报错。2.3 启动与最小验证启动前先确认 Redis 可达别让 Tomcat 背锅。用 redis-cli ping 返回 PONG再启动 Tomcat8tail catalina.out 看 RedisSessionManager 初始化有没有异常。访问一次应用后用 redis-cli --scan 找 session key。生产环境不要用 keys *扫描大库会阻塞。# 确认 Redis 可达 redis-cli -h 127.0.0.1 -p 6379 ping # 启动 Tomcat8观察容器日志中的 Manager 初始化记录 $CATALINA_HOME/bin/startup.sh tail -n 100 $CATALINA_HOME/logs/catalina.out # 访问一次应用观察是否出现 session key前缀以包内实现为准 redis-cli -h 127.0.0.1 -p 6379 --scan --pattern *session* | headping 返回 PONG 只说明网络和认证通不代表 database 选对了。--scan 的 pattern 要根据实际 key 前缀调整不同实现可能带 tomcat:session: 之类的固定前缀。如果扫描不到先确认应用有没有创建 sessionJSP 默认会创建Spring 应用可能延迟到第一次写 session 属性。最小验证还要看 Cookie 和 TTL。用 curl 拿一次 JSESSIONID再带 Cookie 访问观察 key 的 TTL 有没有续期。# 第一次访问保存 Cookie curl -i -c /tmp/session.cookie http://127.0.0.1:8080/app/ # 带 Cookie 再访问确认 JSESSIONID 没变 curl -i -b /tmp/session.cookie http://127.0.0.1:8080/app/如果第二次返回了新的 JSESSIONID说明 session 没被 Manager 接管或者应用主动 invalidate 了。TTL 用 redis-cli ttl 看返回 -1 表示没有过期时间返回 -2 表示 key 不存在。TTL 应该接近 maxInactiveInterval访问后变小再变大才说明续期生效。3. RedisSessionManager 的请求链路一次 session 读写到底经过哪些对象配置能启动只是第一关真正要确认的是请求链路有没有走到 Redis。Tomcat8 的 session 管理不是单一类完成的Valve 和 Manager 各管一段Valve 管请求边界Manager 管 session 的创建、查找、写回和过期。链路不清楚排查时只能看日志猜。3.1 请求拦截与 session 查找请求进来先过 RedisSessionHandlerValveValve 在调用业务前向 Manager 要 session。Manager 拿 JSESSIONID 去 Redis 查 key命中就反序列化未命中就创建新 session 并生成新 id。业务执行完Valve 在请求结束阶段判断 session 有没有变更有就写回 Redis同时刷新 TTL。只配 Manager 不配 Valve常见表现是 session 能读但写回不及时或者过期时间不刷新。Tomcat8 的 Manager 接口里 createSession、findSession、add、remove 是核心动作RedisSessionManager 的实现就是把这些动作映射到 Redis 的 get、set、expire、del。排查时先看请求有没有带 JSESSIONID再看 Manager 有没有查 Redis最后才怀疑序列化。日志级别调低能看到 key 和异常但生产不要长期开 debug。# 先确认请求链路是否进入 RedisSessionManager关键字以日志实际输出为准 grep -n RedisSessionManager\|RedisSessionHandlerValve $CATALINA_HOME/logs/catalina.out | tail -n 50grep 的关键字要看包内日志实际打印什么有的分支只打印初始化不打印每次读写。tail 看最近 50 行避免翻整份日志。如果日志里只有初始化没有后续说明请求可能没进 Valve或者应用根本没创建 session。3.2 序列化与过期时间Redis 里存的是序列化后的 session 属性常见实现用 Java 序列化。放进 session 的对象必须实现 Serializable属性类里的字段也要能序列化。有人塞数据库连接、线程池、InputStream平时不报错一重启或换节点就 NotSerializableException登录态直接丢。过期时间是双轨Tomcat 的 maxInactiveInterval 管本地判断Redis 的 TTL 管键过期每次访问是否续期取决于实现验证时务必看 TTL 有没有变。public class LoginUser implements Serializable { private static final long serialVersionUID 1L; // 版本变化时反序列化不炸 private String userId; private String tenantId; // 不要塞 Connection、ThreadLocal、InputStream 这类不可序列化对象 }serialVersionUID 固定下来发布时新增字段给默认值删除字段先灰度。属性类改包名、改字段类型都可能让旧 session 反序列化失败。包内如果提供 sessionSerializerClass 或 PersistFactory可以换兼容序列化实现没有就管住属性类。序列化是黑匣子出错日志不一定直观最好在测试环境模拟一次重启和类变更。3.3 连接池与 Redis 选库Manager 每次读写 session 都要拿 Jedis 连接连接池参数直接决定高并发下会不会排队。常见参数有 maxTotal、maxIdle、minIdle、maxWaitMillis不同分支属性名可能不同以类里的 setter 为准。maxTotal 不是越大越好Redis 单线程处理命令连接太多反而增加上下文切换maxWaitMillis 不要设 -1 无限等否则 Redis 抖动会把 Tomcat 线程拖死。session 建议单独 database不要和业务缓存混用。混用之后一次 flushdb 就可能把登录态清空恢复起来很麻烦。连接池打满的典型现象是请求变慢、日志里出现 JedisConnectionException 或超时Redis 的 connected_clients 接近 maxTotal。# 观察 Redis 客户端连接数和命中情况判断连接池是否打满 redis-cli -h 127.0.0.1 -p 6379 -n 0 info clients redis-cli -h 127.0.0.1 -p 6379 -n 0 info stats | grep -E keyspace_hits|keyspace_missesconnected_clients 持续接近 maxTotal要查连接泄漏或并发估算偏低。keyspace_hits 低、misses 高可能是 key 前缀不对、session 过期太快或者请求根本没带 JSESSIONID。生产环境不要频繁执行 info观察频率按监控系统来。4. 参数不是拍脑袋maxInactiveInterval、连接池与序列化边界怎么定参数配错不一定启动报错更多是运行期表现用户填一半表单掉登录、Redis 内存慢慢涨、高并发时 Tomcat 线程被拖住。下面三个参数组是实际落地时最常调的先定边界再压测不要照抄示例值。4.1 maxInactiveInterval 与 Redis TTL这个参数单位是秒Tomcat 默认 1800 秒。设太短用户填表单填一半掉登录设太长Redis 里堆积大量僵尸 session内存和序列化开销都上来。我一般先跟业务确认登录态允许空闲多久再把这个值对齐比如 1800 或 3600。Redis TTL 最好和它一致或略大给写回留一点余量。验证时不要只看第一次 TTL访问一次再 ttl 一次确认续期。场景maxInactiveInterval说明后台管理系统1800空闲 30 分钟重新登录面向用户的长表单3600避免填写过程掉线内部低频系统7200降低登录频率但增加堆积内存估算可以用 session 平均序列化大小乘以峰值在线用户数再留 1.5 到 2 倍冗余。不要拍脑袋给 Redis 很小内存session 膨胀比缓存膨胀更隐蔽。TTL 返回 -1 表示没有过期时间必须查配置返回 -2 表示 key 已不存在可能过期太快或根本没写进去。4.2 Jedis 连接池参数maxTotal 可以粗算单节点 QPS 乘以一次 session 操作平均占用连接的时间秒数再乘安全系数 2。比如 200 QPS、每次 2ms2000.0022≈0.8理论值很小但突发流量和慢查询要留余量实际会给到几十。maxIdle 接近 maxTotal 的 50% 到 80%minIdle 留少量热连接。maxWaitMillis 设 1000 到 3000ms超时就抛异常不要无限等timeout 设 2000ms 左右Redis 慢时快速失败比拖死 Tomcat 好。!-- 连接池参数名以包内实现为准这里只示意常见写法 -- Manager classNamecom.orangefunction.tomcat.redissessions.RedisSessionManager host127.0.0.1 port6379 database0 timeout2000 maxTotal64 maxIdle32 minIdle8 maxWaitMillis2000 /maxTotal 64 只是示例要按实际并发调。属性名不支持时启动会报错或忽略配置后看日志和 Redis connected_clients 验证。连接泄漏的典型现象是 connected_clients 持续上涨重启 Tomcat 才降。Manager 内部一般会归还连接但自定义 Valve 或序列化实现里手动 getResource 没 close 就会漏。4.3 序列化兼容与 session 属性治理session 里只放登录标识、权限摘要、少量上下文。不要把查询结果集、大列表、文件流塞进去序列化后体积大跨节点传输和 Redis 内存都吃不消。属性类加 serialVersionUID发布时不要随意改包名和字段类型新增字段给默认值删除字段先灰度。新旧版本本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询