Redis内存淘汰策略

  为了防止 Redis 内存被越来越多的数据"撑爆",Redis 使用了惰性删除 + 定期删除的混合策略来删除过期数据,但这也并不能完全防止内存溢出。

  假设,Redis 的过期策略暂未触发(可能前 1s 刚定时删除完,可能并未访问到过期的数据),但此时内存中涌进一大批数据,直接将内存占满,此时如果不进行处理的话,又将出现 OOM。

  而针对上述情况,Redis 则会使用内存淘汰策略对符合条件的 key 进行删除,以此保障 Redis 的高效运行。

  也就是说,Redis 为了防止内存 OOM,它会使用"主动技能"根据过期策略对过期的数据进行删除,如果"主动技能"下存在漏网之鱼,当内存占满时会触发"被动技能",根据内存淘汰策略对符合条件的数据删除。通过这样主动、被动的方案对数据进行删除,有效保证了 Redis 内存的可用性。

一、Redis 内存淘汰策略有哪些?

Redis 内存淘汰策略共有八种,这八种策略大体分为「不进行数据淘汰」和「进行数据淘汰」两类策略。

1、不进行数据淘汰的策略

  • noeviction(Redis3.0之后,默认的内存淘汰策略):它表示当运行内存超过最大设置内存时,不淘汰任何数据,这时如果有新的数据写入,会报错通知禁止写入,不淘汰任何数据,但是如果没用数据写入的话,只是单纯的查询或者删除操作的话,还是可以正常工作。

2、进行数据淘汰的策略

针对「进行数据淘汰」这一类策略,又可以细分为「在设置了过期时间的数据中进行淘汰」和「在所有数据范围内进行淘汰」这两类策略。

(1)在设置了过期时间的数据中进行淘汰:

  • volatile-random:随机淘汰设置了过期时间的任意键值;
  • volatile-ttl:优先淘汰更早过期的键值。
  • volatile-lru(Redis3.0 之前,默认的内存淘汰策略):淘汰所有设置了过期时间的键值中,最久未使用的键值;
  • volatile-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰所有设置了过期时间的键值中,最少使用的键值;

(2)在所有数据范围内进行淘汰:

  • allkeys-random:随机淘汰任意键值;
  • allkeys-lru:淘汰整个键值中最久未使用的键值;
  • allkeys-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰整个键值中最少使用的键值。

二、如何选择内存淘汰策略

  不同场景下,Redis 的用途不同,对数据的要求也不同,因此实际在选择内存淘汰策略时要根据具体场景选择合适的策略。

  以下是腾讯针对Redis的淘汰策略设置给出的建议:

  • 当 Redis 作为缓存使用的时候,推荐使用 allkeys-lru 淘汰策略。该策略会将最近最少使用的 Key 淘汰。默认情况下,使用频率最低则后期命中的概率也最低,所以将其淘汰。
  • 当 Redis 作为半缓存半持久化使用时,可以使用 volatile-lru。但因为 Redis 本身不建议保存持久化数据,所以只作为备选方案。

三、LRU 算法和 LFU 算法有什么区别?

1、什么是 LRU 算法?

  LRU 全称是 Least Recently Used 翻译为最近最少使用,会选择淘汰最近最少使用的数据。

  传统 LRU 算法的实现是基于「链表」结构,链表中的元素按照操作顺序从前往后排列,最新操作的键会被移动到表头,当需要内存淘汰时,只需要删除链表尾部的元素即可,因为链表尾部的元素就代表最久未被使用的元素。

2、Redis 是如何实现 LRU 算法的?

  如果 Redis 按照传统的方式实现 LRU 算法,一方面,Redis 需要创建额外的链表来管理缓存数据,无疑会增大其内存开销;另一方面,当数据被访问时,需要把数据移动到链表头部,如果大量数据被访问,就会出现很多节点移动操作,这样会降低 Redis 的性能。

  因此,Redis 并未使用传统方式实现 LRU 算法,其实现方式是在 Redis 的对象结构体中添加一个额外的字段 lru,用于记录此数据的最后一次访问时间。

  当 Redis 进行内存淘汰时,会使用随机采样的方式来淘汰数据,它是随机取 5 个值(此值可配置),然后淘汰最久没有使用的那个。

  Redis 实现的 LRU 算法的优点:

  • 不用为所有的数据维护一个大链表,节省了空间占用;
  • 不用在每次数据访问时都移动链表项,提升了缓存的性能;

  但是 LRU 算法有一个问题,无法解决缓存污染问题,比如应用一次读取了大量的数据,而这些数据只会被读取这一次,那么这些数据会留存在 Redis 缓存中很长一段时间,造成缓存污染。

3、什么是 LFU 算法?

  LFU 全称是 Least Frequently Used 翻译为最近最不常用,LFU 算法是根据数据访问次数来淘汰数据的,它的核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。

  所以, LFU 算法会记录每个数据的访问次数。当一个数据被再次访问时,就会增加该数据的访问次数。这样就解决了偶尔被访问一次之后,数据留存在缓存中很长一段时间的问题,相比于 LRU 算法也更合理一些。

4、Redis 是如何实现 LFU 算法的?

  LFU 算法相比于 LRU 算法的实现,在 Redis 的对象结构体的 lru 字段中多记录了「数据的访问频次」的信息。

  通过比较「数据的访问频次」的大小,从而决定要删除哪个数据。它的值越小表示使用频率越低,越容易淘汰,反之,值越大表示使用频率越高,越不容易淘汰。

参考:

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值