之前看到过一道面试题:Redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?笔者结合在工作上遇到的问题学习分析,希望看完这篇文章能对大家有所帮助。
从一次不可描述的故障说起
问题描述:一个依赖于定时器任务的生成的接口列表数据,时而有,时而没有。
怀疑是Redis过期删除策略
排查过程长,因为手动执行定时器,set数据没有报错,但是set数据之后不生效。
set没报错,但是set完再查的情况下没数据,开始怀疑Redis的过期删除策略(准确来说应该是Redis的内存回收机制中的数据淘汰策略触发内存上限淘汰数据。),导致新加入Redis的数据都被丢弃了。最终发现故障的原因是因为配置错了,导致数据写错地方,并不是Redis的内存回收机制引起。
通过这次故障后思考总结,如果下一次遇到类似的问题,在怀疑Redis的内存回收之后,如何有效地证明它的正确性?如何快速证明猜测的正确与否?以及什么情况下怀疑内存回收才是合理的呢?下一次如果再次遇到类似问题,就能够更快更准地定位问题的原因。另外,Redis的内存回收机制原理也需要掌握,明白是什么,为什么。
花了点时间查阅资料研究Redis的内存回收机制,并阅读了内存回收的实现代码,通过代码结合理论,给大家分享一下Redis的内存回收机制。
为什么需要内存回收?
1、在Redis中,set指令可以指定key的过期时间,当过期时间到达以后,key就失效了;
2、Redis是基于内存操作的,所有的数据都是保存在内存中,一台机器的内存是有限且很宝贵的。
基于以上两点,为了保证Redis能继续提供可靠的服务,Redis需要一种机制清理掉不常用的、无效的、多余的数据,失效后的数据需要及时清理,这就需要内存回收了。
Redis的内存回收机制
Redis的内存回收主要分为过期删除策略和内存淘汰策略两部分。
过期删除策略
删除达到过期时间的key。
1、定时删除
对于每一个设置了过期时间的key都会创建一个定时器,一旦到达过期时间就立即删除。该策略可以立即清除过期的数据,对内存较友好,但是缺点是占用了大量的CPU资源去处理过期的数据,会影响Redis的吞吐量和响应时间。
2、惰性删除
当访问一个key时,才判断该key是否过期,过期则删除。该策略能最大限度地节省CPU资源,但是对内存却十分不友好。有一种极端的情况是可能出现大量的过期key没有被再次访问,因此不会被清除,导致占用了大量的内存。
在计算机科学中,懒惰删除(英文:lazy deletion)指的是从一个散列表(也称哈希表)中删除元素的一种方法。在这个方法中,删除仅仅是指标记一个元素被删除,而不是整个清除它。被删除的位点在插入时被当作空元素,在搜索之时被当作已占据。
3、定期删除
每隔一段时间,扫描Redis中过期key字典,并清除部分过期的key。该策略是前两者的一个折中方案,还可以通过调整定时扫描的时间间隔和每次扫描的限定耗时,在不同情况下使得CPU和内存资源达到最优的平衡效果。
在Redis中,同时使用了定期删除和惰性删除。
过期删除策略原理
为了大家听起来不会觉得疑惑,在正式介绍过期删除策略原理之前,先给大家介绍一点可能会用到的相关Redis基础知识。
redisDb结构体定义
我们知道,Redis是一个键值对数据库,对于每一个redis数据库,redis使用一个redisDb的结构体来保存,它的结构如下:
<