PHP多服务器环境Redis会话管理:读取时TTL不更新问题咨询
这确实是PHP Redis会话扩展的预期行为!
先给你理清楚来龙去脉,以及不用急着换存储后端或者自己造轮子的解决方案:
为什么读取会话不更新TTL?
PHP官方的会话处理逻辑里,默认只有会话数据被修改时(比如你更新了$_SESSION的内容,或者脚本结束自动触发session_write_close),才会通知存储后端更新会话的过期时间。phpredis扩展完全遵循这个设计逻辑——读取操作只是从Redis拉取数据,不会触发TTL刷新。
这个设计是为了性能考量:如果只读请求(比如用户浏览静态页面、查看内容)每次都刷新TTL,会产生大量不必要的Redis写操作,在高并发场景下会显著增加Redis的负载。
你不需要换Memcached
别折腾换Memcached了,它的PHP会话扩展(memcached)默认也是同样的行为——只有写入会话时才更新TTL,读取不触发。所以换存储后端根本解决不了你的问题,反而还要重新适配配置。
更优雅的解决方案(不用写dummy值)
你现在用的$_SESSION['dummy'] = time();是一种临时 workaround,但有更合适的方式:
方案1:利用phpredis扩展的配置(推荐)
如果你的phpredis版本在5.3.0及以上,可以直接在php.ini里添加或修改这个配置:
redis.session.refresh_ttl = 1
开启这个选项后,每次会话读取操作都会自动刷新Redis中对应session key的TTL,完全不用手动修改$_SESSION内容。
方案2:手动刷新TTL(兼容旧版本)
如果你的phpredis版本比较旧,不支持refresh_ttl配置,可以在每个请求启动会话后,手动调用Redis客户端刷新当前session的TTL:
// 先启动会话 session_start(); // 获取当前session ID $sessionId = session_id(); // 连接Redis(这里假设你已经有Redis连接实例,或者重新创建) $redis = new Redis(); $redis->connect('127.0.0.1', 6379); // 刷新TTL,时间和session.gc_maxlifetime保持一致 $ttl = ini_get('session.gc_maxlifetime'); $redis->expire("PHPREDIS_SESSION:$sessionId", $ttl);
把这段代码放到全局的入口文件(比如index.php或者框架的中间件里),就能自动处理所有请求的TTL刷新。
完全没必要自己写PHP会话模块
自己实现会话模块不仅需要熟悉PHP的会话处理接口,还要考虑并发、锁机制、异常处理等细节,很容易引入bug,维护成本极高。现有扩展已经经过大量生产环境验证,用现成的方案就足够了。
内容的提问来源于stack exchange,提问作者eXe

