Redis-知识-过期时间设置及过期数据删除、内存淘汰策略
本文最后更新于:4 天前
⚡几种过期时间设置 api
-
EXPIRE
:表示将键 key 的生存时间设置为 ttl 秒。 -
PEXPIRE
:表示将键 key 的生存时间设置为 ttl 毫秒。 -
EXPIREAT
:表示将键 key 的生存时间设置为 timestamp 所指定的秒数时间戳。 -
PEXPIREAT
:表示将键 key 的生存时间设置为 timestamp 所指定的毫秒数时间戳。
注: 在 Redis 内部实现中,前面三个设置过期时间的命令最后都会转换成最后一个 PEXPIREAT 命令来完成。
当我们设置一个键的过期时间时,Redis 就会将该键带上过期时间存放到一个过期字典
中。
当我们查询一个键时,Redis 便首先检查该键是否存在过期字典中,如果存在,那就获取其过期时间。然后将过期时间和当前系统时间进行比对,比系统时间大,那就没有过期;反之判定该键过期。
⚡过期删除策略
⚡定时删除
在设置某个key 的过期时间同时,我们创建一个定时器,让定时器在该过期时间到来时,立即执行对其进行删除的操作。
优点:定时删除对内存是最友好的,能够保存内存的key一旦过期就能立即从内存中删除。
缺点:对CPU最不友好,在过期键比较多的时候,删除过期键会占用一部分 CPU 时间,对服务器的响应时间和吞吐量造成影响。
⚡惰性删除
设置该key 过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key。
优点:对 CPU友好,我们只会在使用该键时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查。
缺点:对内存不友好,如果一个键已经过期,但是一直没有使用,那么该键就会一直存在内存中,如果数据库中有很多这种使用不到的过期键,这些键便永远不会被删除,内存永远不会释放。从而造成内存泄漏。
⚡定期删除
每隔一段时间,我们就对一些key进行检查,删除里面过期的key。
优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键占用的内存。
缺点:难以确定删除操作执行的时长和频率。
如果执行的太频繁,定期删除策略变得和定时删除策略一样,对CPU不友好。
如果执行的太少,那又和惰性删除一样了,过期键占用的内存不会及时得到释放。
另外最重要的是,在获取某个键时,如果某个键的过期时间已经到了,但是还没执行定期删除,那么就会返回这个键的值,这是业务不能忍受的错误。
⚡Redis 使用的删除策略
Redis 的过期删除策略是:惰性删除和定期删除两种策略配合使用。
所有键读写命令执行之前都会调用 expireIfNeeded 函数对其进行检查,如果过期,则删除该键,然后执行键不存在的操作;未过期则不作操作,继续执行原有的命令。
检查函数以一定的频率运行,每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删除其中的过期键。
注意:并不是一次运行就检查所有的库,所有的键,而是随机检查一定数量的键。
⚡不同持久化方式和主从模式删除过期键流程
⚡RDB 模式
-
主服务器模式运行在载入RDB文件时,程序会检查文件中的键,只会加载未过期的,过期的会被忽略,所以RDB模式下过期键不会对主服务器产生影响。
-
从服务器运行载入RDB文件时,会载入所有键,包括过期和未过期。当主服务器进行数据同步的时候,从服务器的数据会被清空,所以RDB文件的过期键一般不会对从服务器产生影响。
⚡AOF 模式
AOF文件不会受过期键的影响。如果有过期键未被删除,会执行以下动作:
客户端请求过期键时:
-
从数据库中删除被访问的过期键;
-
追加一条DEL 命令到AOF文件;
-
向执行请求的客户端回复nil(空)
注:在执行AOF文件重写时,程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中。
⚡主从复制
-
主服务器删除过期键之后,向从服务器发送一条DEL指令,告知删除该过期键。
-
从服务器接收到 get 指令的时候不会对过期键进行处理,只会当做未过期键一样返回。(为了保持主从服务器数据的一致性)
-
从服务器只有接到主服务器发送的 DEL 指令后才会删除过期键。
⚡内存淘汰策略 (6种)
-
volatile-lru 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
-
volatile-ttl 从已设置过期时间的数据集中挑选将要过期的数据淘汰
-
volatile-random 从已设置过期时间的数据集中任意选择数据淘汰
-
allkeys-lru 从所有数据集中挑选最近最少使用的数据淘汰
-
allkeys-random 从所有数据集中任意选择数据进行淘汰
-
noeviction 禁止淘汰数据
⚡使用场景
-
如果不确定具体的业务特征, 那么 allkeys-lru 是一个很好的选择。因为设置 expire 会消耗额外的内存, 所以使用 allkeys-lru 策略, 可以更高效地利用内存, 因为这样就可以不再设置过期时间了。
-
如果分为热数据与冷数据(把冷数据清除掉,保证 redis 中是热点数据),推荐使用 allkeys-lru 策略。
-
如果需要循环读写所有的 key,或者各个 key 的访问频率差不多,可以使用 allkeys-random 策略,即读写所有元素的概率差不多。
-
假如要让 Redis 根据 TTL 来筛选需要删除的 key,请使用 volatile-ttl 策略。
-
volatile-lru 和 volatile-random 策略主要应用场景是: 既有缓存,又有持久化的 key。一般来说,像这类场景,应该使用两个单独的 Redis 实例。
本博客所有文章除特别声明外,均采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 。转载请注明出处!