给key设置一个过期时间,一旦超过过期时间,这个key就会被被删除,内存将被回收
相关的命令
查看key的过期时间
# 如果key存在过期时间,返回剩余生存时间(秒);如果key是永久的,返回-1;如果key不存在或者已过期,返回-2
# TTL单位是秒,PTTL单位是毫秒
127.0.0.1:6379> TTL KEY
127.0.0.1:6379> PTTL KEY
设置key的过期时间
# 设置一个key在当前时间"seconds"(秒)之后过期。返回1代表设置成功,返回0代表key不存在或者无法设置过期时间
# EXPIRE单位是秒,PEXPIRE单位是毫秒
# 语法:EXPIRE key seconds
127.0.0.1:6379> EXPIRE name 60
(integer) 1# 设置一个key在"timestamp"(时间戳(秒))之后过期。返回1代表设置成功,返回0代表key不存在或者无法设置过期时间
# EXPIREAT单位是秒,PEXPIREAT单位是毫秒
# 语法:EXPIREAT key "timestamp"
127.0.0.1:6379> EXPIREAT name 1586941008
(integer) 1
Redis 过期 Key 处理方式
在 Redis 当中,其选择的是策略 2 和策略 3 的综合使用。不过 Redis的定期删除只会扫描设置了过期时间的键,因为设置了过期时间的键 Redis 会单独存储,所以不会出现扫描所有键的情况。
惰性删除
不管键有没有过期都不主动删除,等到每次去获取键时再判断是否过期,如果过期就删除该键,否则返回键对应的值。这种策略对内存不够友好,可能会浪费很多内存
缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的数据占用了大量的内存)
定时删除
在设置 key 过期时间的同时,为其创建定时器,使定时器在过期时刻自动删除该 key,确保 key 按时失效,避免延迟删除。
缺点:定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重,因为每个定时器都会占用一定的 CPU 资源
定期删除
系统每隔一段时间就定期扫描一次,发现过期的键就进行删除
以下两种方式可以触发定期删除:
- 配置redis.conf 的hz选项,默认为10 (即1秒执行10次,100ms一次,值越大说明刷新频率越快,对Redis性能损耗也越大)
- 配置内存回收策略,当Redis消耗内存达到最大内存使用限制,就会自行对应的策略,来对过期key进行删除
同一时间大量Key过期会有什么影响?
Redis 是单线程的,收割的时间也会占用线程的处理时间,如果收割的太过于繁忙,以至于忙不过来?会不会导致线上读写指令出现卡顿?
Redi将每个设置了过期时间的Key放入到一个独立的字典中,会定时遍历这个字典来删除,默认会每秒进行十次过期扫描,过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略
- 从过期字典中随机 20 个 key;
- 删除这 20 个 key 中已经过期的 key;
- 如果过期的 key 比率超过 1/4,那就重复步骤 1
为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认不会超过 25ms
如果Redis 实例中所有的 key (几十万个)在同一时间过期会怎样?
Redis会持续扫描过期字典(循环),直到过期字典中的过期key变得稀疏,才会降低扫描次数,内存管理器需要频繁回收内存页,此时会产生一定的CPU消耗,必然会导致线上读写请求出现明显卡顿的现象,当客户端请求到来时(服务器如果正好进入过期扫描状态),请求将会至少等待25ms才会进行处理,如果客户端将超时时间设置的比较短(10ms),那么就会出现大量的连接因为超时而关闭,业务端就会出现很多异常,而且这时你还无法从Redis的slowlog中看到慢查询记录。
slave库的过期策略
从库不会进行过期扫描,从库对过期的处理是被动的,当master采用定期或惰性删除过期键时,会同步一个del操作到slave,这样从库也可以删除过期key,但是salve从不会自己处理过期key,只会应用master同步过来的del操作,也就是说即使slave中的键已经过期了,slave也不会自己处理过期的键,如果主库不同步DEL操作过来,那么从库并不会采用主动或惰性的方式去清理过期键
这样就会造成一个问题:slave是提供读服务的,如果客户端在slave上读取了一个过期的key,而且master没有及时地处理,那么客户端读取到的是旧的key
这个问题在Redis3.2以下会存在,但之后Redis进行了优化:如果客户端在slave读取到了过期的key,再发起读请求的时候,Redis会判断这个key是否过期,如果过期则返回nil,但是slave依旧不会对过期key进行任何处理,而是等待maser同步del操作
RDB对过期Key的处理
- 持久化数据到RDB文件:持久化之前会检查key是否过期,过期的key不进入RDB文件
- 从RDB文件恢复数据
(1)Redis 主库从 RDB 文件恢复数据时,会检查每个 key 是否已过期,过期的 key 不会被载入内存;
(2)主从全量同步时,从库会先清空本地数据,再加载主库发送的 RDB 文件,而主库生成的 RDB 文件中已不包含过期 key,因此从库最终也不会保留任何过期的 key。
AOF对过期Key的处理
- 持久化数据到AOF文件
(1)如果某个key过期,还没有被删除,该key是不会进入aof文件的,因为没有发生修改命令
(2)当key过期被删除后,就会向aof文件追加一条del命令(在将来的以aof文件恢复数据的时候该过期的键就会被删掉) - AOF重写:重写时,会先判断key是否过期,已过期的key不会重写到aof文件
总结:
如果给键设置了较大的过期时间且没有使用内存回收策略,原本的数据没过期不会被回收,又不断写入新的数据,这样会导致 Redis 消耗的内存不断增大