Redis 内存回收机制详解
前言:这个问题其实相当重要,到底redis有没用到家,这个问题就可以看出来。比如你redis只能存5G数据,可是你写了10G,那会删5G的数据。怎么删的,这个问题思考过么?还有,你的数据已经设置了过期时间,但是时间到了,内存占用率还是比较高,有思考过原因么?
总结:redis是通过 过期策略及内存淘汰机制来回收内存的!
1、redis采用的是定期删除+惰性删除策略。
2、为什么不用定时删除策略?
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.
3、定期删除+惰性删除是如何工作的呢?
定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,
而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。 于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。
(1)上面提到的随机抽取的方式
1、随机测试100个设置了过期时间的key 2、删除所有发现的已过期的key 3、若删除的key超过25个则重复步骤1 说明:这是一个基于概率的简单算法,基本的假设是抽出的样本能够代表整个key空间,redis持续清理过期的数据直至将要过期的key的百分比降到了25%以下。 另外每隔100ms检测一次可以手动修改这频率,可以找关于 hz 选项的说明。 注意:当REDIS运行在主从模式时,只有主结点才会执行上述这两种过期删除策略,然后把删除操作”del key”同步到从结点。
4、采用定期删除+惰性删除就没其他问题了么?
不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。 在redis.conf中有一行配置:# maxmemory-policy volatile-lru 该配置就是配内存淘汰策略的,默认第一种 1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。-不淘汰 2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。 3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。 4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用 5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。 6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
7) Volatile-lfu:在设置了过期时间的键空间中,按照最小访问频率访问次数原则来淘汰数据,如果2个数据相等,则淘汰时间较早的数据,使用lfu算法删除(Redis4.0新提供的)
8)allkeys-lfu:在所有键值对中,按照最小访问频率访问次数原则来淘汰数据,如果2个数据相等,则淘汰时间较早的数据(Redis4.0新提供的)
总结与备忘
1、如果Redis中每天过期大量Key(比如几千万),那么必须得考虑过期Key的清理: 1)、增加Redis主动清理的频率(通过调大hz参数); 2)、手动清理过期Key,最简单的方法是进行scan操作,scan操作会触发第一种被动删除,scan操作时候别忘了加count; 2、dbsize命令返回的Key数量,包含了过期Key; 3、randomkey命令返回的Key,不包含过期Key; 4、scan命令返回的Key,包含过期Key; 5、keys对应的Key数量等同于dbsize; 6、info命令返回的# Keyspace:db6:keys=1034937352,expires=994731489,avg_ttl=507838502 1)、expires指的是设置了过期时间的Key数量; 2)、avg_ttl指设置了过期时间的Key的平均过期时间(单位:毫秒);