tp6切redis存session必须区分单点与集群场景:单点需配config/session.php的type为cache并联动config/cache.php;集群须用predis或tp6.0.13+的redis_cluster驱动,否则会话丢失且无报错。

直接结论:TP6 切 Redis 做 Session 存储,必须区分「单点 Redis」和「Redis 集群」两种场景;用错连接方式或驱动类型,会话在负载均衡后立即丢失,且错误不报、现象隐蔽(如$_SESSION为空、登录态反复失效)。
session.save_handler = redis 不适用于 ThinkPHP6
TP6 的 Session 管理完全绕过 PHP 原生 session 模块,不读取 php.ini 中的 session.save_handler 和 session.save_path。哪怕你改了这些配置,TP6 也视而不见——它只认自己的 config/session.php 和 config/cache.php。
常见错误现象:
- 改完
php.ini后,$_SESSION能写但不持久,刷新就空 - TP6 控制器里
session('user_id', 123)写入成功,但下个请求读不到 - 日志里没报错,Redis 中也查不到 key(因为根本没走 Redis)
正确做法是:把 config/session.php 中的 'type' 设为 'cache',再通过 'store' 指向已配置好的 Redis 缓存连接名(如 'redis')。
config/session.php + config/cache.php 必须联动配置
TP6 的 Session 依赖 Cache 驱动来落地存储,所以两个文件要对齐:
-
config/session.php中:'type' => 'cache','store' => 'redis'(这个字符串必须和config/cache.php里stores下的键名一致) -
config/cache.php中:'stores.redis.type' => 'redis',且'host'不能是空字符串或null;若 Redis 有密码,password字段必须显式设为字符串(如'password' => 'mypass123'),设成空字符串''或不填都会连不上 - 务必指定
'database' => 1(或其他非 0 的库),避免多个 TP 应用共用db0导致 key 冲突(比如都写think:session:abc) - 若 Redis 启用了 ACL(Redis 6+),
password实际应为'user:pass'格式,不是纯密码
验证是否生效:在控制器中执行 dump(cache()->store('redis')->handler()),返回一个 Predis\Client 或 Redis 实例对象才算通。
Redis Cluster 场景下不能直接用 'type'=>'redis' 驱动
TP6 内置的 redis Session 驱动(即 think\session\driver\Redis)只支持单点 Redis 或主从(靠哨兵发现),**不支持 Redis Cluster 自动分片与重定向**。如果你的 Redis 是集群模式(cluster nodes 输出含多个 master),却还按单点配 host,会出现:
- 部分 session key 写入失败(slot 不匹配)
- 某些用户能登录,换台机器就登出
- Redis 日志里频繁出现
(error) MOVED或(error) ASK
解决方法只有两个:
① 改用 predis/predis 客户端并自定义 Handler(推荐):
- composer require predis/predis
- 在 app/Session/RedisClusterHandler.php 中实现 SessionHandlerInterface,构造时传节点数组:['tcp://192.168.1.41:6379', 'tcp://192.168.1.42:6379'],并启用 'cluster' => 'redis'
- 在入口或中间件中调用 session_set_save_handler(new RedisClusterHandler(), true)
② 升级到 TP6.0.13+ 并使用官方 redis_cluster 驱动(需确认 Redis 服务确实是集群,不是哨兵):
- config/session.php 中设 'type' => 'redis_cluster'
- config/cache.php 中对应 store 的 type 改为 'redis_cluster',host 改为数组
用 HASH 替代 STRING 存 Session 可规避反序列化开销
TP6 默认用 Redis STRING 存整个序列化后的 session 数据,每次更新都要全量读→反序列化→改字段→序列化→写回。如果业务需要高频更新单个字段(如 last_login_time),建议切 HASH:
- 新建
app/extend/Driver/Session/RedisHash.php,继承think\session\driver\Redis - 重写
write()方法:用$cache->hSet($key, 'data', $serialized),再单独expire($key) - 重写
read()方法:用$cache->hGet($key, 'data')取值 -
config/session.php中设'type' => 'redis_hash',并确保该类已被自动加载(如加到composer.json的autoload.files)
注意:切换后老 session 数据无法自动迁移,上线前需清空 Redis 中旧的 think:session:* key,否则新代码读不到。
最易被忽略的一点:所有 Web 节点的 serialize 配置必须一致。TP6 默认用 json_encode(),但如果你在 config/session.php 里加了 'serialize' => 'php',那所有服务器都得这么配,混用会导致 unserialize() 失败、$_SESSION 始终为空——这种问题不会报错,只会静默失效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











