Redis缓存过期与内存淘汰
- Redis中有个设置时间过期的功能,即对存储在redis 数据库中的值可以设置一个过期时间,到了过期时间,key会被删除
- 如果内存空间满了,再往Redis里面插入数据,就会触发缓存淘汰机制
缓存过期策略
作为一个缓存数据库,这是非常实用的。我们set key的时候,都可以给一个expire_time, 就是过期时间,通过过期时间我们可以指定这个key可以存活的时间。
那么,到了过期时间后,这些key是怎么被删除的呢?
- 缓存过期是在 Key 超过 expire_time 后,从内存中删除,减少内存空间的占用
- 不同策略的定义、优点和缺点都是不同的。Redis 的过期策略主要有三种实现方式:
定时删除:
对于每一个有过期时间的 Key,创建一个定时器,到过期时间后立即删除;
- 优点:保存内存可以尽快释放,减少过期 Key 对内存空间的占用;
- 缺点:占用大量的 CPU 资源去处理定时器,影响缓存的吞吐量,这和 Redis 设计追求性能的设定不符,所以一般不会采用这种策略。
惰性删除:
过期的 Key 不做处理,只有当访问这个 Key 时才会判断是否过期,过期则删除; - 优点:删除操作只有在访存的时候才可能执行,对 CPU 的占用做到了最小。
- 缺点:如果内存中大量的 Key 均过期,且一段时间内没有被访问,会占用大量内存。
定期删除:
每隔一段时间(默认100ms)全量扫描设置了过期时间的 Key,如果失效则从内存中删除,否则不做处理; - 优点:通过限制定时的频率,来减少对 CPU 的占用和对内存的占用;
- 缺点:作为一种折中的方案,在内存友好方面,不如定时删除策略;在 CPU 友好方面,不如惰性删除。使用时的表现非常依赖配置的定期频率。
内存淘汰机制
但是仅仅通过设置过期时间还是有问题的。如果定期删除漏掉了很多过期key,然后你也
没及时去查,也就没走惰性删除,此时会有大量过期key堆积在内存里,导致redis内存耗
尽了
redis内存淘汰机制就横空出世了,缓存过期策略和内存淘汰机制是非常容易混淆的两个概念,两者的目的是不同的。 - 缓存过期策略:针对过期 Key ,从内存中移除的方式。
- 内存淘汰机制:针对 Redis 内存不足时,业务还在继续往 Redis 追加内容,如何处理已有的内容。
八种淘汰策略
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key;
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key;
- volatile-lfu:当内存不足以容纳新写入数据时,在过期密集的键中,使用 LFU 算法进行删除 key;
- allkeys-lfu:当内存不足以容纳新写入数据时,对所有的 key 执行 LFU 算法筛选过期;
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期的键中,随机删除一个 key;
- allkeys-random:当内存不足以容纳新写入数据时,随机删除一个或者多个 key;
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除;
- noeviction:当内存不足以容纳新写入数据时,新写入操作直接报错,无法写入。
上述算法按照特性可以分为几类:LRU/LFU 算法、随机删除算法、优先淘汰历史数据算法、报错处理算法。目前主流是使用 LRU 算法
- Redis 用作持久化数据库,不配置缓存过期时间,采用 allkeys-lru ;
- Redis 作为缓存数据库,配置了 Key 过期时间,采用 volatile-lru 算法。
LRU算法
LRU(Least Recently Used,最近最少使用算法)是最常见的缓存淘汰算法,核心思想是 “如果数据最近被访问过,那么将来被访问的可能性也更高”。
算法思想
- 新数据直接插入到链表头部;
- 每当缓存命中(即缓存数据被访问),则将被命中的数据移到链表头部;
- 当链表满的时候,将链表尾部的数据丢弃。
总结,越靠近链表头部的数据越是不容易被淘汰,越靠近链表尾部的数据越是容易淘汰。