Apache本身不支持跨服务器Session共享,因其无状态且mod_session默认将Session存于本地;需通过Redis等外部存储由后端统一管理Session,Apache仅作反向代理。

为什么 Apache 本身不支持跨服务器 Session 共享
Apache HTTP Server 是无状态的,mod_session 默认把 Session 存在本地文件或内存里,每台机器独立维护一份。集群中用户请求被负载均衡随机打到不同节点时,PHPSESSID 或 JSESSIONID 对应的 Session 数据在另一台机器上根本不存在——直接导致登录态丢失、购物车清空、表单重复提交等典型问题。
Redis 不是“替代 Apache Session 模块”的方案,而是绕过它:让所有后端(如 PHP-FPM、Tomcat)统一把 Session 写入同一个 Redis 实例,Apache 只负责反向代理和转发,不碰 Session 数据。
PHP 场景下用 Redis 存储 Session 的实操要点
关键不是改 Apache 配置,而是改 PHP 的 Session 处理器。Apache 只需确保 mod_proxy 和 mod_proxy_balancer 正常工作,把请求透传给后端 PHP 进程即可。
-
session.save_handler必须设为redis(不是files) -
session.save_path要写成 Redis 连接字符串,例如tcp://10.0.1.5:6379?database=2&auth=mypass;若用 Unix socket,写成unix:///var/run/redis.sock?database=2 - PHP 必须装好
redis扩展(非phpredis的旧名),且版本 ≥ 5.3.0;PHP 8.0+ 推荐用pecl install redis安装最新版 - Redis 服务端需开启
timeout(避免连接堆积)、关闭protected-mode(或配好bind和requirepass),否则 PHP 连不上会静默回退到fileshandler,现象是“看似正常但实际没共享”
验证是否生效:在两台机器上分别执行 php -r "session_start(); $_SESSION['test'] = time(); echo session_id();",然后查 Redis:redis-cli -h 10.0.1.5 GET 'php:redis:abc123...',能取到序列化数据才算真正接入。
Java + Tomcat 场景下替换默认 Manager
Tomcat 原生不认 Redis,必须引入第三方 tomcat-redis-session-manager 或更现代的 spring-session-data-redis。前者侵入性强但配置简单,后者依赖 Spring Boot,适合新项目。
- 若用
tomcat-redis-session-manager,需把 JAR 放进$CATALINA_HOME/lib/,并在context.xml中替换Manager类:<manager classname="com.orangefunction.tomcat.redissessions.RedisSessionManager" host="10.0.1.5" port="6379" database="2" password="mypass" maxinactiveinterval="60"></manager>
- Spring Boot 项目只需加依赖
spring-session-data-redis,配spring.redis.host和spring.session.store-type=redis即可,Session 自动走 Redis,无需改 Controller 代码 - 注意:Tomcat 默认使用
JSESSIONIDCookie,负载均衡器(如 Apachemod_proxy_balancer)必须开启stickysession=JSESSIONID作为兜底——万一 Redis 挂了,至少单机 Session 还能用
Redis 连接与高可用避坑指南
生产环境别裸连单点 Redis。Session 写失败会导致用户立即登出,比页面慢一点更致命。
- PHP 的
session.save_path不支持 Redis Sentinel 地址列表,得用redis://mymaster/2格式,并确保 PHP redis 扩展编译时启用了哨兵支持(--enable-redis-sentinel) - Tomcat 的
tomcat-redis-session-manager不支持哨兵,必须换用spring-session或自己封装 JedisPool - 设置合理的
maxInactiveInterval(PHP 的session.gc_maxlifetime或 Tomcat 的maxInactiveInterval)要和 Redis 的EXPIRE时间一致,否则 Redis 里 key 过期了,PHP 还以为 Session 有效 - 不要把 Session 存成超大对象(比如塞整个用户权限树),Redis 是内存数据库,单个 value 超 10KB 就会影响吞吐;敏感字段(如密码、token)绝不能进 Session
最易被忽略的是连接池配置:PHP 的 redis 扩展默认不复用连接,高并发下可能耗尽文件描述符;Tomcat 的 JedisPool 若 maxTotal 设太小,线程排队等待 Redis 连接,用户请求就会卡在 Session 读写阶段。










