核心是让同一用户的请求始终落到同一台tomcat或共享session数据;启用sticky session需配置stickysession=jsessionid|jsessionid、balancermember的route参数及tomcat的jvmroute一致,或改用redis等集中式session存储实现非粘性会话。

核心是让同一用户的请求始终落到同一台 Tomcat,或让所有 Tomcat 能读写同一份 Session 数据。不能只靠轮询分发,必须主动干预会话路由或存储机制。
启用 Sticky Session(会话粘性)
这是最直接、改动最小的方案,适用于大多数中小规模部署。
- 在 Apache 的
<proxy></proxy>块中配置stickysession=JSESSIONID|jsessionid,并确保每个BalancerMember指定route参数,例如route=server1 - Tomcat 的
server.xml中,<engine></engine>标签必须设置相同值的jvmRoute,如jvmRoute="server1",否则 Apache 无法从JSESSIONID=ABC123.server1中提取 route 并匹配 - 若应用上下文路径不一致(如后端分别是
/app1和/app2),会导致 Cookie Path 冲突,JSESSIONID 无法被正确携带。应统一后端应用路径,或用ProxyPassReverseCookiePath /app1 /强制修正 Cookie 存储路径
改用集中式 Session 存储
当需要高可用、弹性扩缩容或容忍单节点故障时,推荐此方式。Apache 完全无需感知 Session,纯负载转发即可。
- Redis 是首选:Spring Boot 项目可直接集成
spring-session-data-redis;传统 Tomcat 可使用tomcat-redis-session-manager,需确保序列化兼容且避免存ThreadLocal等非序列化对象 - JDBCStore 适合已有关系数据库且读写压力不高的场景,但性能明显低于 Redis,且表结构和连接池需额外维护
- 所有 Java 对象存入 Session 前必须实现
java.io.Serializable,否则反序列化失败会导致 500 错误
检查并规避常见干扰项
很多“漂移”现象其实不是集群逻辑问题,而是配置疏漏或环境异常导致的假象。
- 确认浏览器未禁用 Cookie,或服务端未关闭 URL 重写(
sessionConfig.isUsingCookies()为 false 时会 fallback 到 URL 参数,但易丢失) - 检查 Apache 是否启用了
ProxyPreserveHost On,否则 Host 头丢失可能影响部分依赖域名的 Session 策略 - 验证 Tomcat 的
sessionCookiePathUsesTrailingSlash设为false(默认为 true),避免因路径末尾斜杠不一致导致 Cookie 不被发送 - 注意
nofailover=On与nofailover=Off的区别:前者在后端宕机时直接报错,后者尝试转发到其他节点——若开启 failover 但未配集中存储,就会触发真正的 Session 丢失










