← [ BACK_TO_NOTES ]

BodySense Redis 第 3 课:TTL、Expiration 与 Eviction

区分 TTL 的逻辑过期、Redis 的实际清理与内存压力下的 Eviction,并推导这些机制对 BodySense Session authority 和 Rate Limit 的不同风险。

#course #growing #backend #redis #bodysense

[!info] related notes

BodySense Redis 第 3 课:TTL、Expiration 与 Eviction

[!abstract] 学习进度 第 3 / 12 课。核心问题:“Key 消失”可能有完全不同的业务原因,不能只看最终结果。

TTL 是什么:把“生命周期”直接附着在 Key 上

TTL = Time To Live,直译就是“还能活多久”。

Redis 允许给 Key 绑定一个过期时间:

SET verification:abc user-42 EX 300

这里同时做了两件事:

verification:abc = user-42
expire after 300 seconds

也可以先写再设置:

SET verification:abc user-42
EXPIRE verification:abc 300

但是两条命令之间有失败窗口;如果语义允许,优先用 SET ... EX 一次表达会更完整。

TTL / PTTL 怎么观察

TTL verification:abc
PTTL verification:abc

TTL 返回秒,PTTL 返回毫秒。

常见特殊结果:

-2 → Key 不存在
-1 → Key 存在,但没有 expiration
>=0 → 剩余 TTL

这在排查 Rate Limit 或 Session 时非常有用:

counter 还在,但 TTL = -1

往往说明原本应该有生命周期的 Key 被错误写成了永久 Key。

TTL 是 Key 的属性,不是“值里面的 expires_at 字段”

PostgreSQL 常见:

row.expires_at = 2026-09-18 20:00

应用查询时要自己判断是否过期,并考虑清理。

Redis TTL 则由 Redis 自己参与生命周期判断:

Key metadata
├─ value
└─ expire_at

到期后,应用读取时 Redis 会把它当成不存在。

一个常见坑:重新 SET 可能改变 TTL

当你重新写一个已有 Key 时,要明确自己是否希望保留旧 TTL。不要把“更新 Value”和“保留生命周期”想当然地绑定在一起。

例如某些更新方式会替换 Key 原有过期语义;需要保留时应显式使用支持 KEEPTTL 的语义,或重新设置 TTL。

所以每次设计临时状态都应问:

谁创建 TTL?
谁续期?
谁主动删除?
重写 Value 时 TTL 是否应延长?

Expiration:时间到了,应该失效

例如:

验证码      5 min
Session     refresh lifetime
rate limit  10 min
idempotency 24 h

这些到期具有业务意义。

Expiration
→ 时间到了
→ 应用认为它应该死

TTL 到 0 是否“瞬间物理删除”

要区分:

逻辑过期
vs
物理内存清理

当 Key 已到期,从应用语义上:

GET expired-key
→ 不存在

即使 Redis 内部对应内存对象尚未在那一纳秒完成物理回收,也不会把过期值继续作为有效结果返回。

被动 / Lazy Expiration

访问时发现过期:

GET session:s1
→ Redis 检查 expire time
→ 已过期
→ 删除 / 视为不存在

主动 / Active Expiration

如果没人访问,Redis 也会在后台主动清理已过期 Key,避免永久占用内存。

因此:

TTL 到期定义逻辑生命周期,不等于精准垃圾回收时刻。

Eviction:内存不够,不得不提前淘汰

假设:

maxmemory = 1 GB
used       = 1 GB

新的写入到来,需要根据 maxmemory-policy 决定是否淘汰已有 Key。

Eviction
→ 内存压力
→ Redis 为腾空间提前移除数据

这可能发生在 TTL 还剩 30 分钟时。

Expiration vs Eviction

ExpirationEviction
原因TTL 到期内存不足
谁定义业务生命周期Redis memory policy
时间可预期取决于内存压力
语义正常失效被迫提前移除
Cache正常常可接受
Session正常登出/过期可能提前掉登录
Rate Limit窗口结束可能降低安全保护

一句话:

Expiration 是“应该死”;Eviction 是“不得不死”。

BodySense Session 被 Eviction 会怎样

假设:

session:s1
TTL 还有 25 分钟

由于内存压力被提前淘汰。

用户请求:

JWT signature ✓
JWT exp       ✓
GET session:s1 → nil

如果 Redis 是认证 authority:

→ 不再能证明在线授权
→ fail closed
→ 用户被提前登出 / 请求失败

安全上不会因为 Redis 丢状态而自动放行,但可用性会变差。

Rate Limit 被 Eviction 更危险

login_failed:ip = 4
TTL = 10 min

本来第 5 次应该被限制。

如果 Key 被提前 eviction:

下一次 INCR
→ 1

攻击窗口被意外重置。

所以 Session、Refresh Replay Tombstone、Rate Limit 等不是普通缓存。

Eviction 不是 TTL 的另一个名字

Redis 可以同时有:

TTL = 30 min
但
memory pressure = now

如果配置允许淘汰,这个 Key 完全可能在 30 分钟结束前消失。

所以一个非常重要的公式是:

TTL
= 最晚什么时候应该失效

Eviction policy
= 内存不够时 Redis 是否允许更早删它

这两个机制必须分开推理。

maxmemory-policy 的基础分类

noeviction

内存满
→ 不自动赶走已有 Key
→ 新写入失败

对于 security-critical runtime state,通常比静默丢状态更容易推理。

allkeys-*

可以从所有 Key 中淘汰,例如 LRU / LFU 类策略。常见于纯缓存实例。

volatile-*

只从设置了 TTL 的 Key 中选择淘汰候选。

[!warning] volatile 不等于“只删已经过期的 Key” session:s1 即使 TTL 还有 25 分钟,只要它有 TTL,也可能属于候选。

为什么 Critical State 与 Disposable Cache 要考虑隔离

一个 Redis 同时:

├─ Session
├─ Refresh Token
├─ Rate Limit
├─ AI Cache
└─ Workspace Cache

如果大量可重建 Cache 占满内存,却让认证状态一起被淘汰:

不同丢失语义的数据进入了同一个 eviction / failure domain。

长期可以考虑:

redis-critical
├─ session
├─ refresh
├─ revocation
└─ critical auth rate-limit

redis-fast
├─ cache
├─ pub/sub
├─ wakeup
└─ optional queue

当前规模小时不一定立即拆实例,但必须理解这个边界。

Fail Closed

如果 Redis 是 auth authority,登录流程出现:

密码验证成功
JWT 已生成
Redis Session 写入失败

不能继续告诉客户端“登录成功”。

正确思路:

无法写入授权 authority
→ 登录流程失败 / 服务暂不可用

监控指标

两个信号不要混:

expired_keys
→ TTL 正常到期

evicted_keys
→ 内存压力导致淘汰

如果 Redis 承担 Session,evicted_keys 增长是高优先级信号。

Prediction

[!question] 先判断“为什么 Key 消失”,再判断业务影响

A. 验证码 TTL 到期后消失:Expiration 还是 Eviction?
B. Session TTL 还有 30 分钟,但 Redis 因内存压力把它删掉:是什么?用户会看到什么?
C. Session / Refresh / AI Cache 共用 allkeys-lru 有什么架构问题?
D. Redis Session 写入失败时,登录是否还能算成功?
E. Key 已逻辑过期,但 Redis 还没在后台完成物理内存回收,GET 应看到什么?
F. TTL key 返回 -1,对一个本应 10 分钟后过期的 Rate Limit counter 意味着什么?

[!success]- Answer / 解析 A → Expiration。 生命周期按业务预期结束,是正常失效。

B → Eviction。 Key 在 TTL 前被迫移除;如果它是 Session authority,后续请求会得到 definitive miss,用户可能提前掉登录。安全上通常 fail closed,但可用性受损。

C → 不同丢失语义混在同一 eviction domain。 可重建 AI Cache 可以被丢,但 Session/Refresh/Rate Limit 被提前丢会改变认证和安全语义。

D → 不应该。 BodySense 把 Session Redis 状态当 revocation authority;无法建立这个 authority 时不应向客户端交付一个“登录成功但下一请求无法安全验证”的 credential。

E → 不存在。 TTL 到期决定逻辑可见性;物理清理可以稍后发生。

F → Key 存在但没有 expiration。 对本应有窗口的 limiter 来说这是异常,可能意味着 INCR 成功但 TTL 没建立,或后续写入错误移除了过期语义。

Explain-back / L4 Gate

能够解释:

  1. TTL、Expiration、Eviction 三者关系;
  2. 为什么 volatile-* 仍可能提前删除未到 TTL 的 Session;
  3. 为什么 Cache Redis 和 Auth Redis 的内存策略不能机械共用;
  4. 为什么 expired_keys 与 evicted_keys 的运维含义完全不同。
创建于 2026/9/18 更新于 2026/9/18
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本