Redis是基于内存进行高性能的读写操作。既然是基于内存的那么就一定会达到内存存储的上线。那redis是怎么清除数据以及保留数据呢?这都是由redis的过期策略以及内存的淘汰机制决定的
过期策略
Redis由三种不同的删除策略:定时删除、定期删除、惰性删除。前两种是主动删除策略,最后一种是惰性删除策略。redis本身默认的删除策略是:定期+惰性删除
定时删除:
在设置键的过期时间的同时,创建一个定时器,定时器在过期时间来临时,立即执行删除操作
优点:对内存是最友好的,通过定时器能够保证过期的键能够及时释放
缺点:对cpu不够友好,在过期键比较多的情况下,删除过期键可能会占用非常多的cpu时间,在内存不紧张,CPU比较紧张的情况下,影响服务器的吞吐量以及响应时间。
惰性删除
键过期不管,但是在每次从键空间获取数据时,检查键是否过期,若果过期删除键值
优点:cpu友好,惰性删除保证了删除操作只会发生在非做不可的操作上,保证cpu性能不能浪费在无效的操作上
缺点:内存不友好,如果一个键已经过期,然而这个键一直不会使用到,因此该键所占用的内存得不到释放
定期删除
每隔一段时间,程序对数据进行检查,删除里面的过期键。redis在设置过期时间的时候,会将key放入到单独的字典中,默认会100ms/per扫描一次,过期扫描不会扫描字典中的所有key,采用了贪心的策略。
1.从过期字典中随机20个key
2.删除这20个钟过期的key
3.如果key超过了1/4,重复步骤1
为什么是随机抽取呢?小伙伴可以再评论区留言说一下见解
redis中的配置 redis.conf
# The range is between 1 and 500, however a value over 100 is usually not
# a good idea. Most users should use the default of 10 and raise this up to
# 100 only in environments where very low latency is required.
hz 10 # 默认是1s/10次 可以更改这个值来设置 定期删除频率
内存淘汰策略
有了以上的过期策略说明后,为什么还需要淘汰策略呢?因为定期+惰性并不能保证所有的过期键能够精准的删除,还会存在key没有被删除掉的场景,所以需要内存的淘汰策略
# 内存淘汰策略
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key according to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
- noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
- allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
- volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
- allkeys-random: 回收随机的键使得新添加的数据有空间存放。
- volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
- volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
LRU
redis中缓存了一个24位时钟,我们要进行LRU那么我们会首先拿到当前的全局时钟,然后找到内部时钟与全局时钟距离最久的key进行淘汰(24)
redis的LRU算法并非完整的实现,通过对少量的keys进行采样,然后回收其中最好的key(redis为什么不使用真实的LRU,因为需要比较多的内存)。
redis 3.0算法改进为回收键的候选池。redis可以通过调整每次回收检查的采样数量,实现算法的调整 # maxmemory-samples 5。在redis 3中,设置样本数为10的时候能够很准确的淘汰掉最久没有使用的键,真实的LRU算法与近似的算法可以通过下面的图像对比:
近似LRU的好处:
1.性能:真实LRU需要对所有key排序,近似LRU只是随机采样N个,这样性能会有较大提高
2.内存占用:抽样可以减少内存的占用
LFU
Redis 4.0出现,使用频率来进行判断
LFU把原来的key对象的内部时钟的24位分成两部分,前16位还代表时钟,后8位代表一个计数器。16位的情况下如果还按照秒为单位就会导致不够用,所以一般这里以时钟为单位。而后8位表示当前key对象的访问频率,8位只能代表255,但是redis并没有采用线性上升的方式,而是通过一个复杂的公式,通过配置如下两个参数来调整数据的递增速度
欢迎关注作者公众号
来源:
http://www.redis.cn/topics/lru-cache.html
https://zhuanlan.zhihu.com/p/105587132
书籍:redis设计与实现