必须为每个 session key 显式设置 TTL,否则 volatile-lru 等策略失效,allkeys-lru 会误删活跃会话;应使用 SETEX 或 SET+EX 原子写入,禁用分步 SET+EXPIRE;漏设 TTL 导致 key 永生、内存泄漏。

必须给每个 session key 显式设置 TTL,否则 volatile-lru 等策略完全不生效,而 allkeys-lru 会无差别淘汰刚写入的会话数据——这不是配置问题,是数据写入逻辑缺陷。
session key 必须用 SETEX/SETEX 或 SET + EX 写入
单独 SET 后跟 EXPIRE 是危险的:网络抖动、客户端崩溃或中间异常都可能导致 TTL 漏设。漏设一个 key,它就变成永生 key,既不参与淘汰,又持续占内存。
-
SETEX session:abc123 1800 "{...}"(原子性,推荐) -
SET session:abc123 "{...}" EX 1800(Redis 2.6+,同样原子) - 避免:
SET session:abc123 "{...}"+EXPIRE session:abc123 1800(两步非原子)
为什么不能依赖 allkeys-lru 保 session 安全
allkeys-lru 看似“兜底”,实则把 session 的生命周期交给了内存压力——只要 LRU 队列里有比它更久未访问的 key,哪怕 session 刚创建 5 秒、正在被高频 GET,也会被删。
- 会话数据本应由业务语义(如登录后 30 分钟)控制,不是由“谁最近没被读”决定
- 在高并发登录场景下,大量新 session 写入后若未立即访问,极易在首次 GET 前就被淘汰
- 监控
evicted_keys指标如果突增且含session:前缀,基本可判定误用了allkeys-*策略
如何验证现有 session 是否都带 TTL
不能只信代码逻辑,必须线上抽检。Redis 不提供 “查所有无 TTL 的 key” 的命令,得组合扫描:
- 用
SCAN 0 MATCH session:* COUNT 1000拿一批 key - 对每个返回 key 执行
TTL keyname;返回-1表示没设过期时间,-2表示 key 不存在 - 脚本化检查(Python 示例):
for key in redis.scan_iter("session:*", count=1000):<br> if redis.ttl(key) == -1:<br> print(f"MISSING TTL: {key}")
volatile-lru 配置后仍 OOM?先查漏设 TTL,再调 maxmemory
现象:CONFIG GET maxmemory-policy 返回 volatile-lru,但 INFO memory 显示 used_memory 持续上涨,最终触发 (error) OOM command not allowed when used memory > 'maxmemory'。
- 根本原因:大量 session key 没设 TTL →
volatile-lru淘汰池为空 → 实际退化为noeviction - 临时缓解:
CONFIG SET maxmemory-policy allkeys-lru(仅应急,非长期方案) - 真正解法:修复写入路径,补全 TTL,并用上述 SCAN+TTL 方式清查存量
- 注意:
maxmemory要比used_memory_peak高出至少 20%,否则即使全带 TTL,也可能因采样偏差或大 value 写入瞬间打满
最易被忽略的一点:TTL 不是“可选项”,而是 volatile-* 策略的准入门槛——没 TTL,就不在淘汰范围内,连被选中的资格都没有。保护 session 的第一道防线,永远在写入端,不在配置端。


















