Redis LFU计数器按需衰减而非定时衰减,衰减仅在key被访问或采样时触发,由lfu-decay-time控制检查时机;OBJECT FREQ返回当前logc快照,不包含待执行衰减;调小该值会引发震荡、误判与性能开销;衰减非原子操作,多线程下结果不可预测。
Redis的LFU计数器不是“自动定时衰减”,而是按需触发、延迟执行的——lfu-decay-time 控制的是衰减时机,不是衰减节奏。
这个配置项(单位:分钟)只决定 Redis 什么时候“愿意去算一算该不该衰减”,而不是每过这么多分钟就无条件执行一次 -1。实际衰减发生在两个时刻之一:
lfu-decay-time 分钟?如果是,就立刻对它的 logc 执行一次右移 1 位(即除以 2 向下取整)这意味着:一个长期没人碰的 key,它的 logc 值可能几个月都不变——直到下一次被访问或被采样到才衰减。这不是 bug,是设计上的懒加载优化。
OBJECT FREQ 返回的是当前内存里存着的那个 logc 快照,它不包含“未来待执行的衰减”。常见误解场景:
OBJECT FREQ 返回 5 → 正常,初始值就是 5OBJECT FREQ,大概率变成 2(5 >> 1)→ 衰减在 lookupKey 前就完成了所以别用 OBJECT FREQ 判断“衰减是否准时”,而要用“访问前后对比”来验证逻辑是否生效。
把 lfu-decay-time 从默认 1 改成 0.1(6 秒),看似更灵敏,实则引入三重风险:
logc 震荡(比如 10 → 5 → 6 → 3)logc 被削得太快,刚涨到 3 就被衰减到 1,容易和真正冷数据混淆官方建议保持默认 1 分钟;只有当你明确需要区分“小时级热度变化”(如突发新闻类缓存),且观察到 INFO memory 中 lfu_bypassed 显著升高时,才考虑下调,并同步调大 maxmemory-samples 至 10+ 提升采样稳定性。
多个线程同时访问同一个 key 时,衰减和计数更新可能交错发生。例如:
logc = 10,判断需衰减 → 执行 10 >> 1 = 5
logc = 10,也执行衰减 → 再次写入 5
6
6(覆盖了 T1 的结果)最终值仍是 6,但中间两次衰减只生效了一次。这种非确定性是 Redis LFU 在性能与精度之间做的主动取舍——它不保证单 key 的严格单调衰减,只保障整体淘汰倾向符合“低频优先”的统计规律。
真正难调的不是 lfu-decay-time 的数值,而是它和 lfu-log-factor 的协同效应:前者管“多久降一次”,后者管“每次降完还涨不涨得上去”。两者一起动,才会影响冷热边界的实际位置。