bigywater.tech
Redis · 24

LRU 与 LFU 对比

设计一个key历史上被访问100次但最近没碰、另有2000个key各只访问1次但更新的场景,对照LRU和LFU两种策略给出的完全相反的淘汰结果。

LRU:被淘汰
历史火但最近没访问的key的LRU命运
LFU:活下来
同一个key的LFU命运
FREQ=11
star_key的历史频率计数保护了它

做的事:设计一个能让LRU和LFU给出相反结果的场景

一个key历史上很火但最近没人碰,另一批key只访问过一次但都是刚刚发生的。

操作SET star_key,GET它100次(历史上非常火) 再SET 2000个filler_key,每个只GET 1次(但发生在star_key之后,是"最近"的访问)

验证:LRU下,star_key被淘汰了

同样的访问模式,先用allkeys-lru跑一遍。

结果LRU策略下 star_key 是否还在: 0(不在了!) DBSIZE: 713 evicted_keys: 2042

结果:哪怕star_key历史上被访问过100次,LRU只看"最后一次访问是什么时候"——它最后一次被访问,是在2000个filler_key开始被访问之前,所以在LRU眼里,它是"最久没被碰过"的那一批,被淘汰了。

验证:LFU下,同样的star_key活下来了

完全相同的访问顺序和次数,只换策略。

结果LFU策略下 star_key 是否还在: 1(活下来了!) DBSIZE: 713 evicted_keys: 3330 star_key的FREQ: 11

结果完全反过来了:LFU看的是"历史上一共被访问了多少次",star_key的100次历史访问转化成了一个较高的FREQ计数(11,同样是对数压缩后的值),哪怕它已经很久没被访问,这个累积的频率优势足够让它在淘汰竞争中活下来——filler_key们虽然"新",但每个都只被访问过1次,频率计数远低于star_key。

这个对照揭示了两种策略天生的取舍:LRU擅长应对"访问模式会随时间整体漂移"的场景(旧的热点真的过时了,理应被新热点替换);LFU擅长保护"历史证明确实重要,只是恰好有一阵子没被用到"的数据,不会因为短暂的访问空窗期就被一批"只是凑巧刚被摸了一下"的新key挤掉。没有哪个策略绝对更好,选择取决于业务的访问模式更像哪一种。

分步演示:LRU和LFU相反的判断

每一步都是本文上面用redis-cli和redis-py跑出来的原始结果。

同一份数据同一个访问顺序,两种策略给出相反的结果
这一步新验证的策略

    本文用到的工具

    • 本机 Redis 8.10.1 单节点,maxmemory=3MB
    • allkeys-lru vs allkeys-lfu:用同一份访问模式对照两种策略
    京ICP备2026067502号-1京公网安备11010502063487号