必须改用 Redis 等共享存储替代默认 file 驱动,配置 host/port/database 并设 prefix 区分应用,确保多机访问同一 Redis 实例且序列化方式一致。

Session 默认文件存储在分布式环境下必然失效
ThinkPHP 默认用 file 驱动存 Session,每台服务器写本地磁盘,用户请求轮到不同机器时就找不到 Session,直接登出或状态丢失。这不是 Bug,是设计使然——文件驱动天然不共享。
必须切到支持跨服务访问的存储后端,Redis 是最常用、最稳妥的选择,前提是所有服务器能连通同一套 Redis 实例(或集群)。
- 确认 Redis 服务可被所有 Web 服务器通过内网 IP + 端口访问,防火墙/安全组要放行
- 避免用
127.0.0.1或localhost作为 Redis host,多机部署时会连错本机 - ThinkPHP 6.x 要求 Redis 扩展为
ext-redis(非phpredis别名),且版本 ≥ 5.3;TP 5.1 可兼容更低版本但需注意序列化差异
配置 session.driver = redis 时必须显式设 host/port/database
只改 driver 不够,ThinkPHP 不会自动 fallback 到 redis:// DSN 或读取环境变量。漏配会导致连接失败,错误常表现为:Connection refused 或空 Session,但日志里未必报错。
以 ThinkPHP 6.1+ 为例,在 config/session.php 中:
立即学习“PHP免费学习笔记(深入)”;
'type' => 'redis', 'driver' => 'redis', 'host' => '10.0.1.100', 'port' => 6379, 'password' => 'your_pass', 'database' => 1, 'expire' => 3600,
-
database必须明确指定(默认 0 可能被其他服务占用),不要留空或设为null - 若 Redis 启用了 ACL(如 Redis 6+),
password实际是用户认证凭据,格式为user:pass,不是纯密码 - TP 6.0.13+ 支持
redis_cluster驱动,但要求 Redis 服务本身是集群模式,普通主从不适用
session_id 重复或过期快?检查 Redis key 前缀和序列化方式
多个 ThinkPHP 应用共用一个 Redis DB 时,若没设 prefix,Session key 会撞车(比如都叫 think:session:abc123),导致 A 用户登录后顶掉 B 的会话。
另外,TP 5.x 和 6.x 默认序列化方式不同:5.x 用 serialize(),6.x 默认用 json_encode()。混用会解不出数据,表现是 $_SESSION 始终为空。
- 务必在配置中加
'prefix' => 'tp6_app1_',区分不同项目 - TP 6.x 如需兼容老数据或含资源句柄的 Session,可强制设
'serialize' => 'php' - Redis 内存不足或设置了
maxmemory-policy noeviction以外的策略时,Session 可能被误删,建议监控evicted_keys指标
上线前必须验证 Session 是否真跨机器生效
光看单机写入 Redis 不代表成功。真实分布式场景下,得确认:同一浏览器发起的连续请求,哪怕落到不同服务器,也能读到同一个 PHPSESSID 对应的数据。
简单验证法:在两台机器上分别部署相同代码,用 curl 指定 Cookie 发起两次请求:
curl -b "PHPSESSID=abc123" http://server1/test.php curl -b "PHPSESSID=abc123" http://server2/test.php
- 两台机器输出的
$_SESSION内容必须完全一致 - 手动删掉 Redis 里对应 key,再刷新页面,应触发新 Session 创建,而不是复用旧数据
- 负载均衡器(如 Nginx upstream)若开了 sticky session,会掩盖问题,测试时建议先关掉
Redis 连接超时、密码错误、database 权限不足,这三类问题在线上最隐蔽——因为它们往往不抛异常,只是静默退化成 file 驱动,你根本意识不到 Session 已经不共享了。


















