1 Key Expiration (Key 过期)

DB 结构

image-20250607233659203

image-20250607233712076

Redis 如何知道一个 key 过期?
-> 一个库中有两个 Dict 分别记录 key-value 对、key-ttl 对

是不是 TTL 到期就立刻删除了?
-> 不是,具体取决于过期策略

数据过期策略

  1. 惰性删除:

在访问一个 key 时检查它的存活时间,如果过期 -> 执行删除

  1. 定期删除:

通过一个定时任务周期性地抽样部分 key,删除其中过期的 key
-> 能确保最终所有 Dict 中的数据都被抽到
-> 不会出现过期 key 一直没清理的情况

定期删除分为两种执行模式:

  • SLOW 模式:低频、高时长的清理

Redis 会设置一个定时任务 serverCron(),按照 server.hz 的频率来执行过期 key 清理,模式为SLOW

SLOW 模式规则:

  1. 执行频率受 server.hz 影响,默认为 10(即每秒执行 10 次,每个执行周期 100 ms
  2. 执行清理的耗时不超过一次执行周期的 25%
  3. 逐个遍历 db,逐个遍历 db 中的 bucket,抽取 20 个 key 判断是否过期
  4. 如果没达到时间上限(25 ms)并且过期 key 比例大于 10% -> 再进行一次抽象;否则结束
  • FAST 模式:高频、低时长的清理

Redis 的每个事件循环之前会调用 beforeSleep(),执行过期 key 清理,模式为FAST

FAST 模式规则(过期 key 比例小于 10 % 不执行):

  1. 执行频率受 beforeSleep() 调用频率影响,但两次 FAST 模式间隔不低于 2 ms
  2. 执行清理的耗时不超过 1ms这里有争议,有的说也是 25%,或许是版本不一致?
  3. 逐个遍历 db,逐个遍历 db 中的 bucket,抽取 20 个 key 判断是否过期
  4. 如果没达到时间上限(1 ms)并且过期 key 比例大于 10% -> 再进行一次抽象;否则结束

FAST 策略每次执行时长非常短 -> 减少对主线程的阻塞影响

2 Memory Eviction (内存淘汰)

概念

内存淘汰:当 Redis 内存使用达到配置的阈值时,会主动挑选部分 key 删除以释放更多内存的流程

内存淘汰策略

默认配置:

4 种算法,8 种策略

image-20250607233725861

比较容易混淆的是 LRU 和 LFU:

  • LRU (Least Recently Used,最近最少使用):当前时间 - 最后一次访问时间,这个值越大则淘汰优先级越高(“很久没来了呢~”)
  • LFU (Least Frequently Used,最少频率使用):统计每个 key 的访问频率,值越小淘汰优先级越高(“来得很少呢~”)

其他

  1. 如何知道 LRU 中每个 key 最后一次被访问的时间?
  2. 如何知道每个 key 被访问的频率?

image-20250607233736747

每个键值对 KV 都会被封装为 RedisObject,根据采用的不同策略,在其中时分别记录着对应的信息(上次访问时间/访问频率)

image-20250607233745609

https://www.bilibili.com/video/BV1cr4y1671t/?p=175

3 总结

为了防止内存达到上限,Redis 对内存的管理策略一般分为两类:

  1. 内存过期策略:对过期的 key 的回收策略
  • 惰性删除(单个)
    每次查找 key 时判断是否过期,过期 -> 删除
  • 定期删除(批量)
    设置一个定时任务,周期性地采样抽取,判断并删除过期的 key
    • SLOW 模式:低频、高时长
    • FAST 模式:高频、低时长
  1. 内存淘汰策略:内存使用达到上限的回收策略

4 种算法,8 种策略

  • LRU Least Recently Used 回收最少最近使用 当前时间-上一次使用时间 {LRU 和 LFU 的统计信息都在 redisObject 中}
  • LFU Least Frequently Used 回收使用频率最少的 key
  • 随机
  • TTL