📝Redis-原理篇-4:内存回收
1 Key Expiration (Key 过期)
DB 结构
Redis 如何知道一个 key 过期?
-> 一个库中有两个 Dict 分别记录 key-value 对、key-ttl 对
是不是 TTL 到期就立刻删除了?
-> 不是,具体取决于过期策略
数据过期策略
- 惰性删除:
在访问一个 key 时检查它的存活时间,如果过期 -> 执行删除
- 定期删除:
通过一个定时任务周期性地抽样部分 key,删除其中过期的 key
-> 能确保最终所有 Dict 中的数据都被抽到
-> 不会出现过期 key 一直没清理的情况
定期删除分为两种执行模式:
- SLOW 模式:低频、高时长的清理
Redis 会设置一个定时任务 serverCron(),按照 server.hz 的频率来执行过期 key 清理,模式为SLOW
SLOW 模式规则:
- 执行频率受 server.hz 影响,默认为 10(即每秒执行 10 次,每个执行周期 100 ms)
- 执行清理的耗时不超过一次执行周期的 25%
- 逐个遍历 db,逐个遍历 db 中的 bucket,抽取 20 个 key 判断是否过期
- 如果没达到时间上限(25 ms)并且过期 key 比例大于 10% -> 再进行一次抽象;否则结束
- FAST 模式:高频、低时长的清理
Redis 的每个事件循环之前会调用 beforeSleep(),执行过期 key 清理,模式为FAST
FAST 模式规则(过期 key 比例小于 10 % 不执行):
- 执行频率受 beforeSleep() 调用频率影响,但两次 FAST 模式间隔不低于 2 ms
- 执行清理的耗时不超过 1ms(这里有争议,有的说也是 25%,或许是版本不一致?)
- 逐个遍历 db,逐个遍历 db 中的 bucket,抽取 20 个 key 判断是否过期
- 如果没达到时间上限(1 ms)并且过期 key 比例大于 10% -> 再进行一次抽象;否则结束
FAST 策略每次执行时长非常短 -> 减少对主线程的阻塞影响
2 Memory Eviction (内存淘汰)
概念
内存淘汰:当 Redis 内存使用达到配置的阈值时,会主动挑选部分 key 删除以释放更多内存的流程
内存淘汰策略
默认配置:
4 种算法,8 种策略
比较容易混淆的是 LRU 和 LFU:
- LRU (Least Recently Used,最近最少使用):当前时间 - 最后一次访问时间,这个值越大则淘汰优先级越高(“很久没来了呢~”)
- LFU (Least Frequently Used,最少频率使用):统计每个 key 的访问频率,值越小淘汰优先级越高(“来得很少呢~”)
其他
- 如何知道 LRU 中每个 key 最后一次被访问的时间?
- 如何知道每个 key 被访问的频率?
每个键值对 KV 都会被封装为 RedisObject,根据采用的不同策略,在其中时分别记录着对应的信息(上次访问时间/访问频率)
https://www.bilibili.com/video/BV1cr4y1671t/?p=175
3 总结
为了防止内存达到上限,Redis 对内存的管理策略一般分为两类:
- 内存过期策略:对过期的 key 的回收策略
- 惰性删除(单个)
每次查找 key 时判断是否过期,过期 -> 删除 - 定期删除(批量)
设置一个定时任务,周期性地采样抽取,判断并删除过期的 key- SLOW 模式:低频、高时长
- FAST 模式:高频、低时长
- 内存淘汰策略:内存使用达到上限的回收策略
4 种算法,8 种策略
- LRU Least Recently Used 回收最少最近使用 当前时间-上一次使用时间 {LRU 和 LFU 的统计信息都在 redisObject 中}
- LFU Least Frequently Used 回收使用频率最少的 key
- 随机
- TTL