【Redis】内存回收:内存淘汰策略
文章目录
- 【Redis】内存回收:内存淘汰策略
- 一、Redis内存回收-过期key处理
- 二、Redis内存回收-内存淘汰策略
一、Redis内存回收-过期key处理
如果你发现,平时在操作 Redis 时,并没有延迟很大的情况发生,但在某个时间点突然出现一波延时,其现象表现为:变慢的时间点很有规律,例如某个整点,或者每间隔多久就会发生一波延迟。如果是出现这种情况,那么你需要排查一下,业务代码中是否存在设置大量 key 集中过期的情况。
在学习Redis缓存的时候我们说过,可以通过expire命令给Redis的key设置TTL(存活时间):
可以发现,当key的TTL到期以后,再次访问name返回的是nil,说明这个key已经不存在了,对应的内存也得到释放。从而起到内存回收的目的。
Redis本身是一个典型的key-value内存存储数据库,因此所有的key、value都保存在之前学习过的Dict结构中。不过在其database结构体中,有两个Dict:一个用来记录key-value;另一个用来记录key-TTL。
Redis之所以性能强,最主要的原因就是基于内存存储。然而单节点的Redis其内存大小不宜过大,会影响持久化或主从同步性能。
当内存使用达到上限时,就无法存储更多数据了。为了解决这个问题,Redis提供了一些策略实现内存回收:
Redis主要有2种过期数据回收策略:
惰性删除
- 惰性删除指的是当我们查询key的时候才对key进行检测,如果已经达到过期时间,则删除。显然,他有⼀个缺点就是如果这些过期的key没有被访问,那么他就⼀直无法被删除,而且⼀直占用内存。
周期删除
- 顾名思义是通过一个定时任务,周期性的抽样部分过期的key,然后执行删除。执行周期有两种:
- Redis服务初始化函数initServer()中设置定时任务,按照server.hz的频率来执行过期key清理,模式为SLOW
- Redis的每个事件循环前会调用beforeSleep()函数,执行过期key清理,模式为FAST
- SLOW模式规则:
- 执行频率受server.hz影响,默认为10,即每秒执行10次,每个执行周期100ms。
- 执行清理耗时不超过一次执行周期的25%.默认slow模式耗时不超过25ms
- 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期
- 如果没达到时间上限(25ms)并且过期key比例大于10%,再进行一次抽样,否则结束
- FAST模式规则(过期key比例小于10%不执行 ):
- 执行频率受beforeSleep()调用频率影响,但两次FAST模式间隔不低于2ms
- 执行清理耗时不超过1ms
- 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期
如果没达到时间上限(1ms)并且过期key比例大于10%,再进行一次抽样,否则结束
二、Redis内存回收-内存淘汰策略
内存淘汰:就是当Redis内存使用达到设置的上限时,主动挑选部分key删除以释放更多内存的流程。
这个删除旧数据的逻辑也是需要消耗时间的,而具体耗时的长短,要取决于你配置的淘汰策略:
-
allkeys-lru
:不管 key 是否设置了过期,淘汰最近最少访问的 key -
volatile-lru
:只淘汰最近最少访问、并设置了过期时间的 key -
allkeys-random
:不管 key 是否设置了过期,随机淘汰 key -
volatile-random
:只随机淘汰设置了过期时间的 key -
allkeys-ttl
:不管 key 是否设置了过期,淘汰即将过期的 key -
noeviction
:不淘汰任何 key,实例内存达到 maxmeory 后,再写入新数据直接返回错误 -
allkeys-lfu
:不管 key 是否设置了过期,淘汰访问频率最低的 key(4.0+版本支持) -
volatile-lfu
:只淘汰访问频率最低、并设置了过期时间 key(4.0+版本支持)
比较容易混淆的有两个:
- LRU(Least Recently Used),最少最近使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
- LFU(Least Frequently Used),最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高。
Redis的数据都会被封装为RedisObject结构:
最后用一副图来描述当前的这个流程吧