Redis 6.0+才支持LFU但默认仍是LRU,需显式配置maxmemory-policy为volatile-lfu或allkeys-lfu才生效;OBJECT FREQ返回8位对数频次(0–255),非精确访问次数;LFU衰减和增长受lfu-decay-time与lfu-log-factor影响,需按业务调优。

LFU在Redis里不是默认启用的
Redis 6.0+ 才正式支持 lfu 淘汰策略,但默认仍是 lru。想用LFU,必须显式配置 maxmemory-policy 为 allkeys-lfu 或 volatile-lfu,否则哪怕版本够新也完全不生效。
常见错误是只升级Redis却没改配置,结果观察 OBJECT FREQ 返回值始终为0——那是因为LFU统计根本没开。
- 检查当前策略:
CONFIG GET maxmemory-policy - 临时切换(重启后失效):
CONFIG SET maxmemory-policy volatile-lfu - 永久生效:在
redis.conf中写入maxmemory-policy volatile-lfu
OBJECT FREQ返回值不是访问次数,而是对数频次
OBJECT FREQ 查看的是LFU的内部计数器,它用8位存储(0–255),且采用对数增长:低频访问时增量明显,高频后增长极慢。比如1次访问可能是1,10次可能是10,但100次可能还是12,1000次可能才到17。
这设计是为了防止计数器溢出,也降低更新开销,但容易让人误判“这个key明明被狂刷,怎么freq还不涨”。别拿它当精确计数器用,只适合做相对热度比较。
- 执行
OBJECT FREQ mykey前,确保该key最近被访问过(LFU计数器只在访问时按概率更新) - 刚写入的key,
OBJECT FREQ可能返回0,不代表没被记录,只是还没触发首次衰减或提升 - 如果需要真实访问统计,得自己用
INCR+ 过期时间模拟,Redis不提供原生计数
LFU衰减周期和counter-log-base影响实际淘汰行为
LFU有两个关键配置项:lfu-decay-time(单位:分钟)控制计数器衰减频率;lfu-log-factor(默认10)影响对数增长曲线斜率。它们不写进配置文件就用默认值,但默认值在高并发场景下常导致“冷热混杂”——老热点因衰减过快被误删,新突发流量又顶不上去。
比如默认 lfu-decay-time 1 表示每分钟把所有计数器右移一位(等效除以2),若业务有小时级周期性高峰,这个衰减就太猛了。
- 调大
lfu-decay-time(如设为60)可让热度留存更久,适合日志类、报表类缓存 - 调小
lfu-log-factor(如设为1)会让计数器对初始几次访问更敏感,适合短时爆发场景 - 修改后需
CONFIG REWRITE持久化,且不会立即重算历史counter,只影响后续更新
volatile-lfu和allkeys-lfu的区别不只是“有没有过期时间”
表面看 volatile-lfu 只淘汰带TTL的key,allkeys-lfu 淘汰全部key,但实际影响更大:前者在内存不足时,**只在带TTL的key里按LFU选;后者则把所有key(包括永不过期的)都扔进LFU池子比热度**。这意味着,如果你混用了 SET 和 SETEX,又用了 allkeys-lfu,一个永不超时的配置key可能因为访问少,被频繁读取的临时数据挤出去。
更隐蔽的问题是:Redis对无TTL key的LFU counter初始化逻辑不同,刚设置的永不过期key,初始counter偏低,容易在第一次内存压力时就被误杀。
- 确认key是否真需要永不过期——多数缓存场景建议统一加TTL,再配
volatile-lfu - 用
TTL mykey检查key是否有有效过期时间,-1表示永不过期,-2表示key不存在 - 如果必须保留部分永不过期key,别用
allkeys-lfu,改用volatile-lfu+ 应用层兜底加载
LFU不是开了就自动变聪明的开关,它的计数器更新是概率性的,衰减是周期性的,而你的业务访问模式可能非均匀、非稳态。最常被忽略的是:不验证 CONFIG GET maxmemory-policy 是否真生效,以及把 OBJECT FREQ 当作精确访问量看。

















