浅谈Redis中LFU算法源码解析

 更新时间:2025年04月10日 09:53:30   作者:百里自来卷  
Redis的LFU淘汰算法主要用于 maxmemory-policy 设置为allkeys-lfu或volatile-lfu时,以最少使用频率的键进行淘汰,本文主要介绍了浅谈Redis中LFU算法源码解析,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧

Redis 的 LFU(Least Frequently Used,最不经常使用)淘汰算法主要用于 maxmemory-policy 设置为 allkeys-lfu 或 volatile-lfu 时,以最少使用频率的键进行淘汰。其核心实现涉及到 访问频率计数 和 时间衰减机制,源码主要集中在 src/server.c 和 src/evict.c 文件中。

1. LFU 计数存储

Redis 采用 8-bit 的 LRU 字段 来存储访问频率计数,存储在 robj 结构体的 lru 字段中:

struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:LRU_BITS; // 用于 LRU/LFU 计算
    int refcount;
    void *ptr;
};

其中 lru 变量的 8-bit 空间被拆分:

  • 前 6-bit(counter):用于存储访问计数,最大值 63。
  • 后 2-bit(clock):用于时间衰减计算。

2. 访问计数的计算

LFU 计数在每次访问键时都会递增,但递增方式不是简单 +1,而是使用 对数增长 方式,避免某些键因高访问量而垄断:

unsigned long LFUDecrAndReturn(robj *o) {
    unsigned long counter = LFUGetCounter(o);
    if (counter == 0) return 0;
    if (rand() % (counter + 1) == 0) counter--;
    LFUSetCounter(o, counter);
    return counter;
}

计数增长时:

int LFUIncrAndReturn(robj *o) {
    unsigned long counter = LFUGetCounter(o);
    if (counter < 63) {
        if (rand() % (counter + 1) == 0) counter++;
    }
    LFUSetCounter(o, counter);
    return counter;
}

这意味着:

  • 初始时计数增长较快 (1 → 2 → 3…)
  • 计数越高,增长概率越低(符合 对数曲线)
  • 这样可以防止某些高访问量键长期存活。

3. LFU 访问频率的衰减

由于有些数据可能短期内访问频繁,但长期不再被访问,因此 Redis 采用了 时间衰减机制:

每 1 分钟 递减一次访问计数。

使用 2-bit 记录最近访问的时间 lfu_clock,每隔 60s 触发 衰减:

#define LFU_INIT_VAL 5 // 初始访问计数
unsigned long LFUDecrAndReturn(robj *o) {
    unsigned long counter = LFUGetCounter(o);
    if (counter == 0) return 0;
    if (rand() % (counter + 1) == 0) counter--;
    LFUSetCounter(o, counter);
    return counter;
}

该方法会按照一定概率减少计数,确保 近期访问过的键不会轻易被淘汰,而 长时间未访问的键会逐步淘汰。

4. 淘汰策略

当 maxmemory 超出时,Redis 需要淘汰一部分数据,LFU 主要执行:

遍历数据,找到访问计数最小的键。

采用 volatile-lfu 或 allkeys-lfu 进行数据删除:

evictionPoolPopulate(dict *sample_dict) {
    // 从字典中随机采样 N 个键
    for (i = 0; i < EVPOOL_SIZE; i++) {
        lfu = LFUGetCounter(entry);
        if (lfu < min_lfu) {
            min_lfu = lfu;
            min_entry = entry;
        }
    }
    // 淘汰访问次数最少的
    dictDelete(sample_dict, min_entry);
}

采用 近似随机采样,而不是遍历所有键,提高效率。

5. 关键总结

  • 存储方式:使用 robj.lru 变量的 8-bit 空间存储访问计数和时间信息。
  • 访问计数增长:采用对数增长策略,防止单个键因访问量过大而占用内存。
  • 时间衰减:每分钟对访问频率计数进行衰减,确保长期未访问的键被淘汰。
  • 淘汰策略:采样多个键,找到访问计数最少的键进行删除。

Redis 的 LFU 机制相比 LRU 更适用于热点数据访问场景,避免了某些短期流行的键占用大量缓存,同时也能让真正的 高频访问数据 存活更久。

到此这篇关于浅谈Redis中LFU算法源码解析的文章就介绍到这了,更多相关Redis LFU算法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot 集成Redis 过程

    SpringBoot 集成Redis 过程

    redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。本文给大家介绍SpringBoot 集成Redis 过程,感兴趣的朋友一起看看吧
    2021-06-06
  • 手把手教你使用redis实现排行榜功能

    手把手教你使用redis实现排行榜功能

    使用Redis中有序集合的特性来实现排行榜是又好又快的选择,一般排行榜都是有实效性的,比如“用户积分榜”,下面这篇文章主要给大家介绍了关于使用redis实现排行榜功能的相关资料,需要的朋友可以参考下
    2023-04-04
  • 浅谈redis在项目中的应用

    浅谈redis在项目中的应用

    下面小编就为大家带来一篇浅谈redis在项目中的应用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • Redis中不同持久化方式的差异对比

    Redis中不同持久化方式的差异对比

    大家应该都知道,Redis持久化方式主要有两种:RDB(Redis DataBase)和AOF(Append-only file),但是他们各自存储了什么内容?有什么差异呢?今天我来给大家做个小试验,需要的朋友可以参考下
    2024-03-03
  • Redis缓存空间优化实践详解

    Redis缓存空间优化实践详解

    缓存Redis,是我们最常用的服务,其适用场景广泛,被大量应用到各业务场景中。也正因如此,缓存成为了重要的硬件成本来源,我们有必要从空间上做一些优化,降低成本的同时也会提高性能,本文通过代码示例介绍了redis如何优化缓存空间,需要的朋友可以参考一下
    2023-04-04
  • Redis中的3种特殊数据结构详解

    Redis中的3种特殊数据结构详解

    在本文中,我们对三种特殊的数据类型进行了介绍,它们分别是geospatial(地理空间数据类型)、HyperLogLogs和Bitmaps(位图),这些数据类型在不同的领域和应用中发挥着重要作用,并且具有各自独特的特性和用途,对Redis特殊数据结构相关知识感兴趣的朋友一起看看吧
    2024-02-02
  • Redis 使用跳表实现有序集合的方法

    Redis 使用跳表实现有序集合的方法

    Redis有序集合底层为什么使用跳表而非其他数据结构如平衡树、红黑树或B+树的原因在于其特殊的设计和应用场景,跳表提供了与平衡树类似的效率,同时实现更简单,调试和修改也更加容易,感兴趣的朋友一起看看吧
    2024-09-09
  • redis的list数据类型相关命令介绍及使用

    redis的list数据类型相关命令介绍及使用

    本文主要介绍了redis的list数据类型相关命令介绍及使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • odoo中使用redis实现缓存的步骤

    odoo中使用redis实现缓存的步骤

    这篇文章主要介绍了odoo中使用redis实现缓存的步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • Redis缓存降级的四种策略

    Redis缓存降级的四种策略

    在高并发系统架构中,Redis作为核心缓存组件扮演着至关重要的角色,它不仅能够显著提升系统响应速度,还能有效减轻数据库压力,然而,当Redis服务出现故障、性能下降或连接超时时,如果没有适当的降级机制,可能导致系统雪崩,所以本文给大家介绍了Redis缓存降级的四种策略
    2025-04-04

最新评论