Redis系列之过期策略、内存淘汰策略及LRU

82 阅读5分钟

Redis系列之过期策略、内存淘汰策略及LRU

正文

我们知道,Redis是一个基于内存的高性能Key-value数据库,所以经常被用作缓存。

但是,计算机的资源都是有限的,内存更是有限的,但数据可以是无限的。想象一下,当存储的数据超过Redis的内存以后怎么办?

所以,这时候我们就需要先聊聊Redis的过期策略。

三种过期策略

Redis中可以使用定期删除、惰性删除和定时删除三种过期策略。

定期删除

定期很好理解,就是设置一个定时任务,比如,每隔100ms就随机抽取部分设置了过期时间的key,检查是否过期,过期了就清楚掉。

注意上面的“部分”二字,你可千万别全部扫描一遍,那是极其危险和耗时的操作。

优点:通过限制删除操作的时长和频率,来减少删除操作对CPU的时间占用;

缺点:在内存方面不如定时删除,在CPU时间方面不如惰性删除;

难点:合理设置删除操作的执行时长和执行频率;

惰性删除

惰性删除,顾名思义,就是我懒,哎,就是玩,我就不主动删,等你来瞧我的时候,如果过期了,就删除掉,没过期,大家就接着玩。

优点:删除操作只会发生在从数据库中获取Key的时候,而且只会删除当前key,所以对CPU的占有比较少;

缺点:若大量的key在超出过期时间后,未被获取过,可能会发生内存泄漏;

定时删除

在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除。

不过,这个策略一般是没人愿意用的,聪明的小伙伴可以想想原因。

Redis采用的过期策略

Redis默认采用的是惰性删除+定期删除结合的过期策略;

惰性删除的流程很简单,我们着重聊一下定期删除的流程。

首先会遍历每个数据库(redis.conf中配置的database数量,默认16),然后检查当前库中的指定个数key(默认每个库检查20个key);

如果当前库中没有一个key设置过期时间,则直接执行下一个库的遍历;

如果当前库中有设置了过期时间的key,则随机获取一个,过期,则删除;

判断定期删除操作是否达到指定时长,若达到,则直接退出操作;

否则,继续;

这里多说一句:过期key对AOF和RDB持久化是没有任何影响的,因为在持久化之前会自动校验key是否过期的。

但是,如果是个菜鸟来搞的,忘记设置定期删除,后面业务也没有查询,这样,满满的越积越多,把Redis的内存撑满了怎么办?

OK,大神当然考虑到了,那就是内存淘汰机制。

内存淘汰机制

在Redis5.0中,大神一共提供了多达八种淘汰策略,真爱啊!下面我们就来看看有那些:

1)noeviction:这是默认的淘汰策略,当内存达到限制后,写请求会返回错误(DEL请求可以继续服务),读请求也可以继续进行,这样可以保证不丢失数据,但是会让线上的业务无法持续进行;

2)volatile-lru:在设置了过期时间的键中,优先回收最少使用的键,(LRU:Least Recently Used,最近最少使用);

3)volatile-lfu:在设置了过期时间的键中,优先清除使用频率最少的键(LFU:Least frequently used,最不经常使用);

4)volatile-ttl:在设置了过期时间的键中,优先删除剩余时间最少的键key(TTL:Time To Live);

5)volatile-random:在设置了过期时间的key中,随机删除key;

6)allkeys-lru:在全体key范围内,优先删除最近最少使用的key;

7)allkeys-lfu:在全体key范围内,优先删除使用频率最少的key;

8)allkeys-random:在全体key范围内,随机删除key;

至于使用那种淘汰策略,这个当然是没有定性要求的,只要结合自身业务场景灵活选用即可。

获取和设置内存淘汰策略的方法

获取当前内存淘汰策略

redis> config get maxmemory-policy

通过配置文件(redis.conf)设置内存淘汰策略

maxmemory-policy allkeys-lru

通过命令设置内存淘汰策略

redis> config set maxmemory-policy allkeys-lru

LRU

由于这个算法在很多大厂的面试中都被问道,而且有的小伙伴直接被要求手写这个算法,真是逆天了,所以,大家要提前掌握它。

LRU是操作系统里面用的很广的一个算法,功能是极其强大的。

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。

该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

在这里插入图片描述

核心思想是:如果一个数据在最近一段时间没有被用到,那么将来被使用到的可能性也很小,所以就可以被淘汰掉。

原理是:维护一个双向链表,key -> node,其中node保存链表前后节点关系及数据data。新插入的key时,放在头部,并检查是否超出总容量,如果超出则删除最后的key;访问key时,无论是查找还是更新,将该Key被调整到头部。

在这里插入图片描述

完整的LRU算法是很强大的,实现起来也是很困难的,所以,Redis作者便采用了一个近似算法:就是随机取出若干个key,然后按照访问时间排序后,淘汰掉最不经常使用的。