Redis的过期和淘汰

259 阅读3分钟

过期回收策略

Redis的key到达过期时间就会被回收,可以想象如果同一时间太多key过期,那么这个回收任务会忙不过来,回收会占据线程的处理时间,如果回收太过于频繁,会导致线上读写卡顿。那么Redis是如何处理这个问题呢

过期的key的集合

Redis中所有设置了TTL的key,都会放入到一个专门的字典中,检测过期的策略有:

  • 定时遍历字典中的所有时间
  • 惰性删除(访问的时候,发现过期就删除)

前者是集中处理,后者是零散处理。

定时扫描策略

Redis默认每秒做10次过期扫描,过期扫描不遍历过期字典的所有key,而是使用了如下规则

1. 从过期字典中随机选20key

2. 删除20key中已过期的

3. 如果过期key比例超过1/4,那么重复第一步,否则结束

同时为了每次遍历不会出现死循环,限制了循环最多占用25ms。

可以想象,如果同一时间大量key同时过期(雪崩),上面这个循环会打满25ms,然后下一次循环的时候又占满25ms。由于1s进行10次回收,那么1s就会有250ms在进行回收工作。为了解决这个问题,通常的做法是TTL在指定的时候,需要增加一个随机数。

从库的过期策略

从库的过期策略是被动的过期,是由于主库发生的过期可以被动地同步到从库。


淘汰

内存使用量如果超过了物理内存限制,会和磁盘开始进行交换,这个是Redis系统不允许的,所以在内存使用量超过阈值时,Redis会启动淘汰机制。注意,如果使用了淘汰机制,大概率Redis是用于缓存目的

Redis有很多淘汰方案,可配置,有下面几种:

  • noeviciton不淘汰,默认策略,这样可以保证数据不丢失,但线上业务不可用
  • volatile-lru:对于设置了过期时间的key,使用lru算法
  • volatile-ttl:对设置了过期时间的,根据过期时间淘汰,离过期时间越近的先淘汰
  • volatile-random:对设置了过期时间的,随机淘汰
  • allkeys-lru:对所有key,使用lru算法淘汰
  • allkeys-random:对所有key,随机淘汰

LRU

基本原理是可以通过hashmap和一个双向链表实现一个LRU算法



  • hash存放的是key和value对应的链表节点
  • 链表中存放的是value
  • setkey会进入到链表的头,如果超过了限制,会将尾部去掉
  • 被查询的数据,会被提到链表的头

Redis的近似LRU算法

LRU会使用大量的内存,Redis中没有使用标准的LRU算法,而是采用了近似LRU算法(其实可以理解为一个策略),具体做法是

  • 随机采样5个key,淘汰掉最旧的 (这里需要看配置是淘汰策略是allkey还是volatile)
  • 如果淘汰后还是超过MaxMemeory,则继续采样淘汰