登录状态老是掉线?排查Redis内存淘汰是否清除了Session

来源:互联网 时间:2026-10-29

后台登录着,点两下就退回登录页。白天访问量大的时候特别频繁,凌晨几乎不掉。这种跟时间带关系的掉线,多半不是代码里哪里写错了。

PHP的session存在Redis里,Redis配了maxmemory和allkeys-lru。缓存和session混在同一个db,内存一满,LRU按最近最少使用淘汰,一整天没访问的老session先被清掉,正在用的那些也可能被扫到。用户刚登录,下一次请求session没了,程序认为没登录,跳回登录页。淘汰是静默的,Redis不报错,日志里也没有痕迹,只有evicted_keys这个计数器在动。一个人在后台的操作越少,session被扫到的概率越高,这也解释了为什么后台用户投诉多、前台访客很少提。

redis-cli info stats里看evicted_keys。这个数一直往上涨,说明确实在淘汰。再看info memory的used_memory_human和maxmemory_human,两个贴得很近,就是内存满了。db0里key的数量和总key数比一比,能估出session占多大比例。还有一条更直接:redis-cli --scan --pattern 'PHPREDIS_SESSION:*' | wc -l,数出来就是session的个数。前缀取决于用的扩展,predis和phpredis不完全一样。

改法是把session挪出去。同一个Redis实例换个db不够,淘汰策略是实例级的,db1的key照样被allkeys-lru扫到。要么单独开一个实例,配noeviction或者volatile-lru;要么给session的key全部带上过期时间,用volatile-lru,只淘汰设了TTL的那部分。后一种省机器,前提是写session的代码确实设了EXPIRE,没设的一律免死。验证办法是redis-cli ttl某个session的key,返回-1就是没设过期时间。

session.gc_maxlifetime是1440秒,Redis里的TTL却写着3600,两边对不上。PHP认为过期了,Redis还留着;反过来更糟,PHP还在用,Redis先删了。两个值要一起改,改完重载php-fpm和Redis两边的配置。

你有多台web服务器的话,session还得共享。负载均衡没做会话保持,请求落到A机器登录、B机器校验,B上根本没有这个session,一样掉线。这种和Redis淘汰在前端看起来一模一样,查的时候要分开:看请求落到哪台机器、那台上的key在不在。会话保持能临时缓解,代价是某台机器挂了,那批用户的登录态一起丢。会话保持按来源IP做的话,移动网络下IP一变,照样掉。

给evicted_keys和session的key数量各配一个监控。淘汰数从零开始涨的那一天,就是该扩容或者改策略的时候,不用等用户来投诉。告警阈值别设在淘汰开始之后,设在内存用到八成的时候。

登录态不适合跟缓存抢同一块内存。缓存丢了能重建,登录态丢了用户得重新登一次。这两类数据的淘汰策略本来就该分开配。分开之后内存规划也好做,缓存那边可以放心用LRU,不用替登录态兜底。

相关文章

标签:

A5创业网 版权所有