Redis 源码剖析与实战
蒋德钧
中科院计算所副研究员
17747 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 47 讲
Redis 源码剖析与实战
15
15
1.0x
00:00/00:00
登录|注册

16 | LFU算法和其他算法相比有优势吗?

你好,我是蒋德钧。
上节课我给你介绍了 Redis 对缓存淘汰策略 LRU 算法的近似实现。其实,Redis 在 4.0 版本后,还引入了 LFU 算法,也就是最不频繁使用(Least Frequently Used,LFU)算法。LFU 算法在进行数据淘汰时,会把最不频繁访问的数据淘汰掉。而 LRU 算法是把最近最少使用的数据淘汰掉,看起来也是淘汰不频繁访问的数据。那么,LFU 算法和 LRU 算法的区别到底有哪些呢?我们在实际场景中,需要使用 LFU 算法吗?
其实,如果只是从基本定义来看的话,我们是不太容易区分出这两个算法的。所以,今天这节课,我就带你从源码层面来学习了解下 LFU 算法的设计与实现。这样,你就能更好地掌握 LFU 算法的优势和适用场景,当你要为 Redis 缓存设置淘汰策略时,就可以作出合适的选择了。
好,那么在开始学习 LFU 算法的实现代码之前,我们还是先来看下 LFU 算法的基本原理,以此更好地支撑我们掌握代码的执行逻辑。

LFU 算法的基本原理

因为 LFU 算法是根据数据访问的频率来选择被淘汰数据的,所以 LFU 算法会记录每个数据的访问次数。当一个数据被再次访问时,就会增加该数据的访问次数。
不过,访问次数和访问频率还不能完全等同。访问频率是指在一定时间内的访问次数,也就是说,在计算访问频率时,我们不仅需要记录访问次数,还要记录这些访问是在多长时间内执行的。否则,如果只记录访问次数的话,就缺少了时间维度的信息,进而就无法按照频率来淘汰数据了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Redis 4.0引入了LFU算法作为一种缓存淘汰策略,与LRU算法相比,LFU算法根据数据的访问频率来选择被淘汰的数据。LFU算法记录每个数据的访问次数,并根据访问频率来淘汰数据,而不仅仅是记录访问次数。通过设置maxmemory和maxmemory-policy来启用LFU算法,其中maxmemory表示Redis使用的最大内存容量,而maxmemory-policy可以设置为allkeys-lfu或volatile-lfu,表示淘汰的键值对会分别从所有键值对或是设置了过期时间的键值对中筛选。LFU算法的实现包括键值对访问频率记录、初始化和更新,以及LFU算法淘汰数据。LFU算法的引入为Redis缓存设置淘汰策略提供了更多选择,能够更好地满足实际场景的需求。Redis在更新键值对访问频率时,先对访问次数进行衰减,然后按照一定概率增加访问次数,同时获取最新访问时间戳并更新到lru变量中。LFU算法的实现为Redis缓存设置淘汰策略提供了更多选择,能够更好地满足实际场景的需求。 在实现使用LFU算法淘汰数据时,Redis采用了和实现近似LRU算法相同的方法。Redis会使用一个全局数组EvictionPoolLRU,来保存待淘汰候选键值对集合。然后,在处理每个命令时,会调用freeMemoryIfNeededAndSafe函数和freeMemoryIfNeeded函数,来执行具体的数据淘汰流程。LFU算法在淘汰数据时,使用了不同的方法来计算每个待淘汰键值对的空闲时间。具体来说,LFU算法是用255减去键值对的访问次数来计算EvictionPoolLRU数组中每个元素的idle变量值的。LFU算法在待淘汰键值对集合中,是按照键值对的访问频率大小来排序和选择淘汰数据的,这也符合LFU算法本身的要求。LFU算法相比其他算法更容易把低频访问的冷数据尽早淘汰掉,适用于这种场景。 如果LFU_INIT_VAL设置为1,LFU算法会导致访问次数很容易就达到最大值,无法区分不同的访问频率,从而影响LFU算法的淘汰效果。 总的来说,LFU算法的引入为Redis缓存设置淘汰策略提供了更多选择,能够更好地满足实际场景的需求,而LFU算法的实现细节也为其他软件模块的设计提供了参考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Redis 源码剖析与实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(8)

  • 最新
  • 精选
  • Kaito
    1、LFU 是在 Redis 4.0 新增的淘汰策略,它涉及的巧妙之处在于,其复用了 redisObject 结构的 lru 字段,把这个字段「一分为二」,保存最后访问时间和访问次数 2、key 的访问次数不能只增不减,它需要根据时间间隔来做衰减,才能达到 LFU 的目的 3、每次在访问一个 key 时,会「懒惰」更新这个 key 的访问次数:先衰减访问次数,再更新访问次数 3、衰减访问次数,会根据时间间隔计算,间隔时间越久,衰减越厉害 4、因为 redisObject lru 字段宽度限制,这个访问次数是有上限的(8 bit 最大值 255),所以递增访问次数时,会根据「当前」访问次数和「概率」的方式做递增,访问次数越大,递增因子越大,递增概率越低 5、Redis 实现的 LFU 算法也是「近似」LFU,是在性能和内存方面平衡的结果 课后题:LFU 算法在初始化键值对的访问次数时,会将访问次数设置为 LFU_INIT_VAL,默认值是 5 次。如果 LFU_INIT_VAL 设置为 1,会发生什么情况? 如果开启了 LFU,那在写入一个新 key 时,需要初始化访问时间、访问次数(createObject 函数),如果访问次数初始值太小,那这些新 key 的访问次数,很有可能在短时间内就被「衰减」为 0,那就会面临马上被淘汰的风险。 新 key 初始访问次数 LFU_INIT_VAL = 5,就是为了避免一个 key 在创建后,不会面临被立即淘汰的情况发生。
    2021-08-31
    36
  • 曾轼麟
    回答老师的问题: LFU_INIT_VAL的初始值为5主要是避免,刚刚创建的对象被立马淘汰,而需要经历一个衰减的过程后才会被淘汰。 LFU算法和LRU算法的不同就是,存粹的LFU算法会累计历史的访问次数,然而在高QPS的情况下可能会出现以下几个问题: 1、运行横跨高峰期和低峰期,不同时期存储的数据不一致,可能会导致部分高峰期产生的数据不容易被淘汰,甚至可能永远淘汰不掉(因为在高峰获得一个较高的count值,在计算淘汰的时候仍然存在) 2、需要long乃至更大的值去存储count。对于高频访问的数据如果需要统计每一次的调用,可能需要使用更大的空间去存储,还需要考虑溢出的问题。 3、 可能存在,每次淘汰掉的几乎是刚刚创建的新数据。 为了解决这些问题,Redis实现了一个近似LFU算法,并做出了以下改进: 1、count有上限值255。(避免高频数据获得一个较大的count值,还能节省空间) 2、count值是会随着时间衰减。(不再访问的数据更加容易被淘汰,高16位记录上一次访问时间戳-分钟,低8位记录count) 3、刚刚创建的数据count值不为0。(避免刚刚创建的数据被淘汰) 4、count值累加是概率随机的。(避免高峰期数据都能一下就能累加到255,其中概率能人为调整)
    2021-09-07
    10
  • 可怜大灰狼
    uint8_t LFULogIncr(uint8_t counter) { if (counter == 255) return 255; double r = (double)rand()/RAND_MAX; double baseval = counter - LFU_INIT_VAL; if (baseval < 0) baseval = 0; double p = 1.0/(baseval*server.lfu_log_factor+1); if (r < p) counter++; return counter; } 通过源码可以发现:如果LFU_INIT_VAL太小,会导致baseval变大,从而导致p变小,导致counter加1比较困难。结果就是很容易导致刚set进去的数据,很快就会被淘汰。
    2021-08-31
    6
  • 风轻扬
    回答一下课后问题。如果LFU_INIT_VAL设置为1。会有两方面影响 1、数据访问次数的增加概率会变大,导致很多数据都会达到255这个值,最终导致不容易淘汰数据 2、新创建出来的数据,访问频率过小。很容易刚刚创建就被淘汰
    2023-11-14归属地:北京
  • 飞鱼
    提问:上一节中,哪里有说在实际淘汰数据的时候更新 redisObject对象中的 lru变量的值,只看到了 创建 和 访问更新 这2种情况会更新 lru变量值。
    2022-09-27归属地:北京
  • leetcode
    redis6.0以后server.c文件中都没有lookupKey函数了呀
    2022-01-11
    1
  • 或许
    第一张图里面,lookupKey函数是在db.c里面,老师这里是不是有问题啊?
    2021-11-30
  • Geek_197c21
    如果 LFU_INIT_VAL 设置为 1,那么容易一个key刚刚被set进去就被删除。 麻烦问下老师,如果lfu算法要替换成lru算法的话,那么怎么处理呢?将key都对 255-次数呢?或者啥都不管,继续运行呢
    2021-08-31
    2
收起评论
显示
设置
留言
8
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部