Hello,大家好。我是公众号 “八点半技术站” 的创作者 - Bruce.D。
今天是周二(2020-06-17),分享一句谚语 “读书有三到,心到口到眼到” 。分享给大家的是 「缓存服务 模块」- 理解Redis的内存回收机制和过期淘汰策略。
欢迎热爱 IT编程的各位精英,欢迎进入wechat技术群(底部有二维码)一起交流成长。
花几分钟时间去浏览 redis 技术干货,或许对你有用!!!
底部有本篇文章的思维导图 ,供大家收藏使用~~~
编辑
01
今天写这篇文章的灵感,来自之前一位好友投稿的面试题:redis 的过期策略有哪些?内存淘汰机制有哪些?我将工作中遇到的问题分析,整理成一篇文章提供大家学习,希望对大家有所帮助。
我们从一次广告数据问题说起:一个依赖定时器任务的生成接口数据,有时候会有,有时候没有。
然后我们分析应该是redis过期删除策略导致。
排查过程中,因为手动执行定时器,set数据没有报错,但是set后不生效。这就狠尴尬。
发现,set 没有报错,但是 set 完毕在查的情况下,发现没有数据。开始怀疑 redis 的过期策略(准确来说应该是 redis 的内存回收机制中的数据淘汰策略触发内存上限淘汰数据),导致新加入的的redis的数据都被丢弃了。
最终发现故障是因为配置问题,导致数据错误。(有时候也会因为内存满)
在这里我主要希望大家明白,我们遇到类似问题,如何有效证明正确性,以及什么情况下怀疑内存回收才是合理,所以内存回收机制的一系列问题,你也要知道了解。
02
Q:为什么需要内存回收?
A:第一种:在redis 中,set 指令可以指定 key 的过期时间,当过期时间达到以后,key 就会失效。
第二种:redis 是基于内存操作的,所有的数据都是保存在内存中,一台机器的内存是很宝贵的。
分析:根据以上这俩种,为了保证 redis 提供有效可靠的服务,redis 需要一种机制清理不常用的、无效的、多余的数据,失效后的数据需要及时清理,这就需要内存回收。
03
redis 的内存回收主要分为:过期删除策略 与 内存淘汰策略 俩部分。
过期删除策略:删除到达过期时间的 key 。(过期删除策略原理 - 结合文章,百度自行搜索)
第一种:定时删除
对于每一个设置了过期时间的 key 都会创建一个定时器,一旦达到过期时间都会删除。这种方式立即清除过期数据,对内存比较好,
但是有缺点是:占用了大量 CPU 的资源去处理过期数据,会影响 redis 的吞吐量 和 响应时间。
第二种:惰性删除
当访问一个 key 的时候,才会判断该 key 是否过期,如果过期就删除。该方式能最大限度节省 CPU 的资源。
但是对内存不太好,有一种比较极端的情况:出现大量的过期 key 没有被再次访问,因为不会被清除,导致占用了大量的内存。
第三种:定期删除
每隔一段时间,扫描redis 中过期key 的字典,并清除部分过期的key。这种方式是前俩种一种折中方法。
不同的情况下,调整定时扫描时间间隔,让CPU 与 内存达到最优。
内存淘汰策略:redis 内存淘汰策略是指达到maxmemory极限时,使用某种算法来决定来清理哪些数据,以保证新数据存入。(原理同上)
redis的内存淘汰机制分为:
(1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
(2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
(3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key。
(4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key。
(5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。
(6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除。
04
总结:看完这些,我们得知道一点,如何证明故障不是由于内存回收机制引起的?
根据上述分析,set 没有报错,但是不生效,那么就2种情况:
(1)设置过期时间过短
(2)内存超过最大限制,且设置的是noeviction或者allkeys-random。
因此,在遇到这种情况,首先看set的时候是否加了过期时间,且过期时间是否合理,如果过期时间较短,那么应该检查一下设计是否合理。
如果过期时间没问题,那就需要查看Redis的内存使用率,查看Redis的配置文件或者在Redis中使用info命令查看Redis的状态,maxmemory属性查看最大内存值。
如果是0,则没有限制,此时是通过total_system_memory限制,对比used_memory与Redis最大内存,查看内存使用率。
如果当前的内存使用率较大,那么就需要查看是否有配置最大内存,如果有且内存超了,那么就可以初步判定是内存回收机制导致key设置不成功,还需要查看内存淘汰算法是否noeviction或者allkeys-random.
如果是,则可以确认是redis的内存回收机制导致。
如果内存没有超,或者内存淘汰算法不是上面的两者,则还需要看看key是否已经过期,通过ttl查看key的存活时间。
如果运行了程序,set没有报错,则ttl应该马上更新,否则说明set失败,如果set失败了那么就应该查看操作的程序代码是否正确了。
全文思维导图:
编辑
恭喜你,又读完了一篇文章。
在这里,希望你看完的 每篇文章 都能对自己有所提升(哪怕是帮助你再次巩固记忆)。