Redis的淘汰算法
一、过期策略
定时删除
在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。
- 优点:对内存非常友好(删的很快)
- 缺点:对CPU时间非常不友好(定时器消耗资源)
惰性删除
放任过期键不管,每次获取键时,检查该键是否过期,过期就删,没有过期就返回键。
- 优点:对CPU时间非常友好
- 缺点:对内存非常不友好(会存在很多过期的键)
定期删除
每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响,同时,通过定期删除过期键,也有效地减少了因为过期键而带来的内存浪费。
Redis 默认会每秒进行十次过期扫描(100ms一次),过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。
- 从过期字典中随机 20 个 key;
- 删除这 20 个 key 中已经过期的 key;
- 如果过期的 key 比率超过 1/4,那就重复步骤 1;
每次执行时,依次换库,保证每个库被遍历到。
二、对过期键的处理
RDB对过期键的处理
创建的时候对数据库中的键进行检查,已过期的键不会被保存到新创建的RDB文件中。
载入的时候:
- 主服务器模式:只载入没过期的键。
- 从服务器模式:所有都载入。
AOF对过期键的处理
1. AOF文件写入
如果数据库中的某个键已经过期,并且服务器开启了AOF持久化功能,当过期键被惰性删除或者定期删除后,程序会向AOF文件追加一条DEL命令,显式记录该键已被删除。
举个例子,如果客户端执行命令GET message访问已经过期的message键,那么服务器将执行以下3个动作:
- 从数据库中删除message键
- 追加一条DEL message命令到AOF文件
- 向执行GET message命令的客户端返回空回复
2. AOF文件重写
在执行AOF文件重写时,程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中。
复制功能对过期键的处理
在主从复制模式下,从服务器的过期键删除动作由主服务器控制:
- 主服务器在删除一个过期键后,会显式地向所有从服务器发送一个DEL命令,告知从服务器删除这个过期键。
- 从服务器在执行客户端发送的读命令时,即使发现该键已过期也不会删除该键,照常返回该键的值。
- 从服务器只有接收到主服务器发送的DEL命令后,才会删除过期键。
三、内存淘汰机制
redis 内存淘汰机制有以下几个:
- noeviction(默认策略):对于写请求不再提供服务,直接返回错误(DEL请求和部分特殊请求除外)
- allkeys-lru:从所有key中使用LRU算法进行淘汰
- volatile-lru:从设置了过期时间的key中使用LRU算法进行淘汰
- allkeys-random:从所有key中随机淘汰数据
- volatile-random:从设置了过期时间的key中随机淘汰
- volatile-ttl:在设置了过期时间的key中,根据key的过期时间进行淘汰,越早过期的越优先被淘汰
当使用volatile-lru、volatile-random、volatile-ttl这三种策略时,如果没有key可以被淘汰,则和noeviction一样返回错误
LRU
LRU(Least Recently Used),即最近最少使用。核心:如果一个数据在最近一段时间没有被用到,那么将来被使用到的可能性也很小,所以就可以被淘汰掉。
常规的LRU需要维护一个队列,新增插队尾,超过阈值则淘汰头,并删除掉HashMap中对应的节点。
访问和修改则移动到队尾。
近似LRU
但是Redis的LRU并不维护队列,只是根据配置的策略要么从所有的key中随机选择N个(N可以配置)要么从所有的设置了过期时间的key中选出N个键,然后再从这N个键中选出最久没有使用的一个key进行淘汰。
为什么要使用近似LRU?
1、性能问题,由于近似LRU算法只是最多随机采样N个key并对其进行排序,如果精准需要对所有key进行排序,这样近似LRU性能更高
2、内存占用问题,redis对内存要求很高,会尽量降低内存使用率,如果是抽样排序可以有效降低内存的占用
3、实际效果基本相等,如果请求符合长尾法则,那么真实LRU与Redis LRU之间表现基本无差异
4、在近似情况下提供可自配置的取样率来提升精准度,例如通过 CONFIG SET maxmemory-samples <count> 指令可以设置取样数,取样数越高越精准,如果你的CPU和内存有足够,可以提高取样数看命中率来探测最佳的采样比例。
LFU
LFU(Least Frequently Used),核心思想:根据key的最近被访问的频率进行淘汰。
LFU算法能更好的表示一个key被访问的热度。
假如你使用的是LRU算法,一个key很久没有被访问到,只刚刚是偶尔被访问了一次,那么它就被认为是热点数据,不会被淘汰,而有些key将来是很有可能被访问到的则被淘汰了。
A~~A~~A~~A~~A~~A~~A~~A~~A~~A~~~|
B~~~~~B~~~~~B~~~~~B~~~~~~~~~~~~B|
如果使用LFU算法则不会出现这种情况,因为使用一次并不会使一个key成为热点数据。
LFU一共有两种策略:
- volatile-lfu:在设置了过期时间的key中使用LFU算法淘汰key
- allkeys-lfu:在所有的key中使用LFU算法淘汰数据

浙公网安备 33010602011771号