LRU 根据最近一次访问的时间判断热度,LFU 根据一段时间内的访问频率判断热度。最近访问过,不一定长期热门;过去很热门,也不一定现在还热门。 Redis 的实现采用近似算法,减少维护精确全局排序的成本。
用一次访问变化理解差别
假设商品 A 每分钟被访问一千次,商品 B 平时无人访问,只在刚才被扫描任务读了一次。LRU 可能因为 B 更近被访问而保留 B;LFU 更倾向于识别 A 的持续热度。若热点突然从 A 切换到 C,LRU 能较快体现访问时间变化,LFU 则需要通过频率增长和衰减适应变化。
Redis 不为所有 Key 维护一条严格的 LRU 链表。经典近似 LRU 在候选样本中判断空闲时间,并维护候选信息;maxmemory-samples 调整采样规模,样本更大通常更接近精确选择,但会增加 CPU 工作量。这是准确度与成本的取舍。
LFU 使用有限位数的计数信息,通过概率递增表示热度,避免为每次访问维护无限增长的精确计数;频率随时间衰减,防止曾经的热点永远占着内存。lfu-log-factor 和 lfu-decay-time 会影响增长与衰减,不能把计数值理解为真实访问次数。
策略与范围是两个维度
allkeys-lru 和 volatile-lru 使用的热度依据相似,但候选范围不同。前者考虑所有 Key,后者只考虑带 TTL 的 Key;LFU 也一样。讨论 LRU/LFU 时,要同时回答“按什么排序”和“从哪些 Key 中选”。
常见追问
LFU 一定比 LRU 命中率高吗?
不一定。稳定的高频热点适合频率判断,热点频繁变化或访问分布特殊时结果可能不同。应通过命中率、延迟和淘汰量评估实际负载。
使用 LFU 后还需要 TTL 吗?
需要。淘汰解决容量问题,TTL 表达缓存有效期;过期和热度不是同一个业务含义。
Redis 为什么不直接实现精确 LRU?
精确维护每次访问后的全局顺序会增加元数据和更新开销。缓存淘汰允许一定近似,采样通常能以较低成本得到可用结果。
提高采样数是不是越大越好?
更大的样本可能改善选择,但会消耗更多 CPU;只有在命中率收益足以覆盖成本时才值得调整,不能凭理论一律调大。