Redis的过期策略以及内存淘汰机制

目录

    • 一、过期策略
      • 1.1、定时删除
        • 1.1.1、过期
        • 1.1.2、过期的 key 集合
        • 1.1.3、定时扫描策略
        • 1.1.4、 Redis 中所有的 key 在同一时间过期了,会出现怎样的结果
        • 1.1.5、从库的过期策略
      • 1.2、惰性删除
      • 1.3、定时删除和惰性删除的总结
    • 二、缓存淘汰算法
      • 2.1、缓存淘汰算法概述
        • 2.1.1、概述
        • 2.1.2、maxmemory
      • 2.2、缓存淘汰算法机制
        • 2.2.1、Noeviction
        • 2.2.2、volatile-Iru
        • 2.2.3、volatile-ttl
        • 2.2.4、volatile-random
        • 2.2.5、allkeys-lru
        • 2.2.6、allkeys-random
      • 2.3、缓存淘汰算法总结
      • 2.4、LRU 算法概述
      • 2.5、近似 LRU 算法概述

一、过期策略

1.1、定时删除

1.1.1、过期

  • Redis 所有的数据结构都可以设置过期时间,时间一到,就会自动删除。但是会不会因为同一时间太多的key 过期,以至于忙不过来。同时因为Redis 是单线程的,删除的时间也会占用线程的处理时间,如果删除的大过于繁忙,会不会导致线上读写指令出现卡顿。

1.1.2、过期的 key 集合

  • redis 会将每个设置了过期时间的key 放入到一个独立的字典中,以后会定时遍历这个字典来删除到期的 key。除了定时遍历之外,它还会使用惰性策略来删除过期的 key,所谓惰性策略就是在客户端访问这个 key 的时候,redis 对 key 的过期时间进行检查,如果过期了就立即删除。定时删除是集中处理,惰性删除是零散处理。

1.1.3、定时扫描策略

  • Redis 默认会每秒进行十次过期扫描,过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。
    (1)、从过期字典中随机 20 个 key;
    (2)、删除这 20 个 key 中已经过期的 key;
    (3)、 如果过期的 key 比率超过 1/4,那就重复步骤(1);

1.1.4、 Redis 中所有的 key 在同一时间过期了,会出现怎样的结果

  • Redis 会持续扫描过期字典(循环多次),直到过期字典中过期的key 变得稀疏,才会停止(循环次数明显下降)。这就会导致线上读写请求出现明显的卡顿现象。导致这种卡顿的另外一种原因是内存管理器需要频繁回收内存页,这也会产生一定的 CPU 消耗
  • 所以业务开发人员一定要注意过期时间,如果有大批量的 key 过期,要给过期时间设置一个随机范围,而不能全部在同一时间过期。

1.1.5、从库的过期策略

  • 从库不会进行过期扫描,从库对过期的处理是被动的。主库在 key 到期时,会在 AOF 文件里增加一条 del 指令,同步到所有的从库,从库通过执行这条 del 指今来删除过期的 key
  • 因为指令同步是异步进行的,所以主库过期的key 的 del 指令没有及时同步到从库的话,会出现主从数据的不一致,主库没有的数据在从库里还存在,比如上-节的集群环境分布式锁的算法漏洞就是因为这个同步延迟产生的。

1.2、惰性删除

  • 所谓惰性策略就是在客户端访问这个kev的时候,redis对key的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西
  • 定期删除可能会导致很多过期kev到了时间并没有被删除。所以就有了惰性删除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那个 key,才会被redis给删除掉。这就是所谓的惰性删除,即当你主动去查过期的key时,如果发现key过期了,就立即进行删除,不返回任何东西

1.3、定时删除和惰性删除的总结

  • 定期删除是集中处理,惰性删除是零散处理。

二、缓存淘汰算法

2.1、缓存淘汰算法概述

2.1.1、概述

  • 当 Redis 内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换(swap)。交换会让 Redis 的性能急剧下降,对于访问量比较频繁的 Redis 来说,这样龟速的存取效率基本上等于不可用。

2.1.2、maxmemory

  • 在生产环境中我们是不允许 Redis 出现交换行为的,为了限制最大使用内存,Redis 提供了配置参数maxmemory 来限制内存超出期望大小。
  • 当实际内存超出 maxmemory 时,Redis 提供了几种可选策略(maxmemory-policy) 来让用户自己决定该如何腾出新的空间以继续提供读写服务。
    在这里插入图片描述
    在这里插入图片描述

2.2、缓存淘汰算法机制

2.2.1、Noeviction

  • noeviction 不会继续服务写请求,(DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略.

2.2.2、volatile-Iru

  • volatile-lru 尝试淘汰设置了过期时间的key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。

2.2.3、volatile-ttl

  • voatie-ttl 跟上面一样,除了淘汰的策略不是 LRU,而是key 的剩余寿命ttl的值,ttl 越小越优先被淘汰

2.2.4、volatile-random

  • volatile-random 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。

2.2.5、allkeys-lru

  • allkeys-lru 区别于volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。

2.2.6、allkeys-random

  • allkeys-random跟上面一样,不过淘汰的策略是随机的 key。

2.3、缓存淘汰算法总结

  • volatile-xxx 策略只会针对带过期时间的key 进行淘汰。
  • allkeys-xxx 策略会对所有的 key 进行淘汰。
  • 如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时不必携带过期时间。
  • 如果你还想同时使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key 不会被LRU 算法淘汰。

2.4、LRU 算法概述

  • 实现 LRU 算法除了需要key/value 字典外,还需要附加一个链表,链表中的元素按照一定的顺序进行排列。当空间满的时候,会踢掉链表尾部的元素。当字典的某个元素被访问时,它在链表中的位置会被移动到表头。所以销表的元素排列顺序就是元素最近被访问的时间顺序。
  • 位于链表尾部的元素就是不被重用的元素,所以会被踢掉。位于表头的元素就是最近刚刚被人用过的元素,所以暂时不会被踢。

2.5、近似 LRU 算法概述

  • Redis 使用的是一种近似 LRU 算法,它跟 LRU 算法还不太一样。之所以不使用 LRU 算法,是因为需要消耗大量的额外的内存,需要对现有的数据结构进行较大的改造。
  • 近似LRU 算法则很简单,在现有数据结构的基础上使用随机采样法来淘汰元素,能达到和 LRU 算法非常近似的效果。Redis 为实现近似LRU 算法,它给每个 key 增加了一个额外的小字段,这个字段的长度是 24 个 bit,也就是最后一次被访问的时间戳。
  • 当 Redis 执行写操作时,发现内存超出maxmemory,就会执行一次 LRU 淘汰算法。这个算法也很简单,就是随机采样出 5可以配置maxmemory-samples) 个 key,然后淘汰掉最旧的 key,如果淘汰后内存还是超出maxmemory,那就继续随机采样淘汰,直到内存低于 maxmemory 为止。

你可能感兴趣的:(redis,redis)