过期机制是怎么工作的
给键设置过期时间只是登记了一个到期时刻,真正的删除由两套机制配合完成:一是惰性删除,任何命令访问到某个键时先检查它是否已过期,过期就删除并按不存在处理;二是定期抽样,服务端在事件循环的空闲时段随机抽取一部分设置了过期时间的键,删除其中已过期的并检查是否执行完毕。两者合起来保证过期键最终会被清理,但删除时刻与到期时刻之间可能存在延迟。
基本信息
| 两套机制 | 惰性删除(访问时判定)与定期抽样(后台主动清理) |
|---|---|
| 抽样强度 | active-expire-effort 取值 1 到 10,默认 1,值越大清理越积极 |
| 轮询频率 | hz 默认 10,即每秒 10 次,可调高 |
| 内存影响 | 未及时清理的过期键仍占内存,直到被抽样命中 |
| 从库行为 | 从库不主动删除,读到逻辑过期的键返回空,实际删除等主库的 DEL 同步 |
典型使用场景
- 排查内存与键数不符:键数看起来不多但内存占用高,往往存在大量已过期尚未清理的键
- 大批键同时到期的治理:给 TTL 加随机抖动,避免同一秒集中过期引发清理压力
- 读写分离下的正确性:理解从库读到过期键返回空值的行为,避免误判为数据丢失
- 空闲时段资源紧张时调 hz:需要更及时的过期与内存回收时小步上调,观察 CPU 变化
- TTL 设置的合理性评估:核心缓存键应都有明确 TTL,只有持久业务键才允许为负一
观察过期状态
观察过期状态
redis-cli CONFIG GET hz # 默认 10
redis-cli CONFIG GET active-expire-effort # 默认 1,越大越积极
redis-cli TTL somekey # -1 有键无 TTL,-2 键不存在或已过期
redis-cli INFO keyspace # 各库键数与带过期时间的键数
redis-cli DBSIZE # 键总数,与 keyspace 交叉核对
redis-cli INFO stats | grep expired_keys # 累计过期删除计数
redis-cli --scan --pattern 'cache:*' | wc -l # 抽样统计实际存在的键数量两种机制对照
| 机制 | 触发时机 | 覆盖范围 |
|---|---|---|
| 惰性删除 | 命令访问到该键时 | 只清理被访问到的键,保证读取语义正确 |
| 定期抽样 | 事件循环的空闲时段 | 每次随机抽一批设有 TTL 的键,逐步收敛 |
| 抽样强度 | active-expire-effort 控制单轮投入 | 强度越高,单轮清理越彻底 |
| 轮询频率 | hz 控制每秒执行次数 | 频率越高,单位时间内的清理机会越多 |
过期键不是按时删除的:即便到期时刻已过,只要没有任何命令访问它、也没被抽样命中,它就会继续占用内存。因此「内存里键数一直不降」在写入量大的实例上并不罕见,判断时应结合 expired_keys 计数与内存趋势,而不是只看键数。
大量键在同一秒集中过期会给主线程带来阵发性负担:抽样清理、内存回收、以及紧随其后的重建请求会同时发生。设置 TTL 时统一加一段随机抖动是最有效的预防手段,成本却几乎为零。