Redis的LFU(Least Frequently Used)策略通过动态跟踪键的访问频率实现淘汰决策,其核心工作逻辑可分为以下四个部分:
- 数据结构设计
字段拆分:每个Redis对象(redisObject)的lru字段(24位)被拆分为两部分:
高16位(ldt):记录最后一次访问的时间戳(精度为秒),用于计算访问间隔和频率衰减。
低8位(logc):逻辑计数器,初始值为5,表示访问频率的近似值,值越低越可能被淘汰。 - 访问频率衰减机制
动态衰减逻辑:每次访问键时,根据当前时间与ldt的差值计算logc的衰减量:
时间间隔越大,衰减幅度越大(如长时间未访问的键,logc显著降低)。
衰减公式:logc = logc - (当前时间 - ldt) * 衰减系数(默认衰减系数为1)。
目的:避免历史高频但近期不再使用的键长期驻留内存。 - 访问频率更新策略
概率性增加:在衰减后,logc的值通过概率算法更新:
计数器越高,进一步增加的概率越低(如logc=10时,增加概率为1/(10+1)=9.1%)。
计算公式:p = 1.0 / (logc_current * lfu_log_factor + 1)(lfu_log_factor默认为10)。
目的:防止短暂突发访问导致logc快速膨胀,确保长期高频访问的键才具有高优先级。 - 淘汰执行流程
内存监控:Redis每秒检查10次内存使用情况,触发淘汰的条件为内存超过maxmemory阈值。
候选集筛选:根据策略(如volatile-lfu或allkeys-lfu),从对应键空间中随机抽样maxmemory-samples个键(默认5个)。
淘汰决策:选择抽样中logc值最小的键;若logc相同,则比较ldt时间戳(更早未被访问的键优先淘汰)。
配置参数
lfu-log-factor:控制logc增长的难度(值越大,增长越慢)。
lfu-decay-time:定义衰减时间窗口(单位:分钟),默认1分钟触发一次衰减计算。
通过以上机制,Redis的LFU在有限内存和计算开销下,实现了对高频访问键的高效保留,同时避免传统LFU算法的内存与性能瓶颈。