问题出现的背景
当 Redis 内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换 (swap)。交换会让 Redis 的性能急剧下降,对于访问量比较频繁的 Redis 来说,这样龟速的存取效率基本上等于不可用。
在生产环境中我们是不允许 Redis 出现交换行为的,为了限制最大使用内存,Redis 提供了配置参数maxmemory
限制内存超出期望大小。
当实际内存超出maxmemory
,Redis 提供了几种可选策略 (axmemory-policy
来让用户自己决定该如何腾出新的空间以继续提供读写服务。
方式 | 解释 |
---|---|
noeviction | 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。 |
volatile-lru | 尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。 |
volatile-ttl | 根上面一样,除了淘汰的策略不是LRU,而是key的剩余寿命ttl的值,ttl越小越先被淘汰 |
volatile-random | 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。 |
allkeys-lru | 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。 |
allkeys-random | 跟上面一样,不过淘汰的策略是随机的 key。 |
volitale–xxx | volatile-xxx 策略只会针对带过期时间的 key 进行淘汰,allkeys-xxx 策略会对所有的 key 进行淘汰。如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时不必携带过期时间。如果你还想同时使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key 不会被 LRU 算法淘汰。 |
LRU算法
Redis使用的LRU算法
算法的底层数据结构
Redis使用的是一种近似LRU
算法,它根LRU
算法还不太一样,之所以不使用LRU算法,是因为需要消耗大量的额外内存,需要对现有的数据结构进行较大的改造。
LRU算法则很简单,在现有数据结构的基础上使用随机采样方法来淘汰元素,能达到和`LRU算法非常近似的效果,Redis为近似实现LRU算法,它给每个kley增加了一个额外的小字段,这个字段的长度是24个bit,也就是最后一次被访问的时间戳
何时执行,如何执行
区别于过期键的集中管理和懒惰处理,LRU的淘汰策略只有懒惰处理,当Redis执行操作时,发现内存超出 maxmemory,就会执行一次LRU淘汰算法,这个算法狠简单,就是
随机采样出5个key,然后淘汰掉久的key,如果淘汰后内存还是超出了
maxmemory,那么就继续随机采样淘汰,直到内存低于maxmemory