Redis的过期key清除策略

Posted 刘Java

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis的过期key清除策略相关的知识,希望对你有一定的参考价值。

简单介绍了Redis如何设置key过期时间,以及Redis过期key删除策略。

1 Redis设置key过期时间

Redis支持为所有类型的数据设置过期时间,对于String类型,只需要使用setex命令或者set key value EX seconds命令:

127.0.0.1:6379> SETEX a 10 sss
OK
127.0.0.1:6379> TTL a
(integer) 8
127.0.0.1:6379> TTL a
(integer) 1
127.0.0.1:6379> TTL a
(integer) -2

对于某个key重新设置值,将会清除该key目前关联的过期时间。更常见的设置过期时间方式是依靠EXPIRE/PEXPIRE命令来设置或者更新过期时间为ttl秒/毫秒,依靠 EXPIREA/PEXPIREAT命令来设置或者更新过期时间为timestamp 所指定的 秒数/毫秒数时间戳。

实际上EXPIRE、PEXPIRE、EXPIREAT三个命令的底层都是使用PEXPIREAT命令来实现的,且底层的时间进度都是毫秒

PERSIST 命令则可以移除一个键的过期时间。

检查剩余时间需要使用TTL或者PTTL命令,非别返回秒和毫秒级别的剩余时间,它们都是通过计算键的过期时间和当前时间之间的差来实现的。

2 Redis过期key删除策略

在Redis中,内存的大小是有限的,所以为了防止内存饱和,需要实现某种键淘汰策略。主要有两种方法,一种是当Redis内存不足时所采用的内存释放策略。另一种是对过期key进行删除的策略,也可以在某种程度上释放内存。

Redis采用的默认内存释放策略是noeviction-不删除,达到最大内存时,如需更多内存(存入数据),则操作报错,内存释放策略我们之前就已经讲过了:Redis的内存淘汰策略;默认的过期key删除策略则是惰性删除+定期删除的方案;

常见的过期数据删除策略如下:

  1. 定时删除
    1. 在设置key的过期时间的同时,创建一个定时器,让定时器在key的过期时间来临时,立即执行对key的删除操作;
    2. 定时删除操作对于内存来说是友好的,内存不需要操作,而是通过使用定时器,可以保证尽快的将过期key删除,但是对于CPU来说不是友好的,如果过期key比较多的话,起的定时器也会比较多,每一个定时器会占用到CPU的资源;
  2. 惰性删除
    1. 不管key有没有过期都不主动删除,但是每次从键空间中获取键值时,都检查取得的key的过期时间,如果过期的话,返回null,然后删除key即可;
    2. 惰性操作对于CPU来说是友好的,过期key只有在程序读取时判断是否过期才删除掉,而且也只会删除这一个过期键,但是对于内存来说是不友好的,如果多个key都已经过期了,而这些key又恰好没有被访问,那么这部分的内存就都不会被释放出来;
  3. 定期删除
    1. 每隔一段时间,程序就对数据库进行一次检查,删除掉过期key;
    2. 定期删除是上面两种方案的折中方案,每隔一段时间来删除过期key,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响,除此之外,还有效的减少内存的浪费;但是该策略的难点在于间隔时长,这个需要根据自身业务情况来进行设置,并且可能由于扫描不及时,导致过期的key也被返回。

目前,Redis采用的是惰性删除+定期删除的方案。Redis 的定期扫描只会扫描设置了过期时间的键,Redis 通过一个单独的过期字典expires(可以看作是 hash 表)来保存设置了过期时间的数据过期的时间,所以不会出现扫描所有键的情况,即使如此,redis也是默认是每隔 100ms 就随机抽取过期字典中的 key,检查其是否过期,如果过期就删除。如果不定时随机抽查而是全部扫描,那么将可能有很长的时间导致服务对外不可用,这是无异于一场灾难。

由于是随机扫描,那么对于已经过期但没有被扫描到的key怎么办呢,没关系,还有惰性删除,在获取某个 key 的时候,Redis 会检查一下 ,这个 key 如果设置了过期时间那么是否过期了?如果过期了此时就会删除,返回null。

过期字典dict的key是一个指针,这个指针指向键空间中的某个key对象(也即是某个数据库键)。过期字典的值是一个long long类型的整数,这个整数保存了key所指向的数据库key的过期时间——一个毫秒精度的UNIX时间戳。在实际中,键空间的key和过期字典的key都指向同一个key对象,所以不会出现任何重复对象,也不会浪费任何空间。

typedef struct redisDb {
    dict *dict; //键空间,存放所有的key-value键值对
    dict *expires; //设置了过期时间的key到它的过期时间的键值对
} redisDb;

PERSIST命令在过期字典中查找给定的key,并解除key和值(过期时间)在过期字典中的关联。

相关文章:

  1. https://redis.io/topics/data-types
  2. https://redis.io/topics/data-types-intro

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

以上是关于Redis的过期key清除策略的主要内容,如果未能解决你的问题,请参考以下文章

Redis的过期策略和内存淘汰策略

Redis的过期策略和内存淘汰策略

分布式锁学习

Redis数据过期策略

关于Redis数据过期策略

Redis淘汰策略