Redis 过期键删除策略的实现示例

 更新时间:2024年03月19日 09:14:58   作者:lordky  
Redis的过期数据删除策略主要有三种,包括定时删除、惰性删除和定期删除,本文主要介绍了Redis 过期键删除策略的实现示例,具有一定的参考价值,感兴趣的可以了解一下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

(一)关于键的过期时间或生存时间

我们知道,Redis数据库是基于内存的,但是如果一些不用的键在内存中一直存在,那么久而久之,就有可能会发生oom的情况。所以,redis数据库提供了常用的EXPIRE命令或者PEXPIRE命令,用户可以使用这两个命令以秒或者毫秒为精度为数据库中的某个键设置生存时间。在经过指定的时间后,redis服务器就会自动删除生存时间为0的键。

可以设置键的生存时间的命令如下:

  • EXPIRE  <key>  <ttl>
    该命令用于将键Key的生存时间设置为ttl秒
  • PEXPIRE  <key>  <ttl>
    该命令用于将键Key的生存时间设置为ttl毫秒
  • EXPIREAT  <key>  <timstamp>
    该命令用于将键Key的生存时间设置为timstamp所指定的秒数时间戳
  • PEXPIREAT <key>  <timstamp>
    该命令用于将键Key的生存时间设置为timstamp所指定的毫秒数时间戳。

虽然有四种不同的命令用于指定过期时间,但是实际上,无论使用哪一种命令,最终都会转换为PEXPIREAT命令来执行

那么,redis是如何存储过期时间的呢?

typedef struct redisDb {
    dict *dict;                 /* The keyspace for this DB */
    dict *expires;              /* Timeout of keys with a timeout set */
    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
    dict *ready_keys;           /* Blocked keys that received a PUSH */
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
    int id;                     /* Database ID */
    long long avg_ttl;          /* Average TTL, just for stats */
    unsigned long expires_cursor; /* Cursor of the active expire cycle. */
    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;

我们可以通过以上源码看出,redisDb结构的expires这个字典保存了数据库中所有的过期时间,我们叫这个字典为过期字典。

每当我们为一个数据库的某一个键添加过期时间就会在该字典中添加一个键值对,键为这个需要添加过期时间的键,值为过期时间的时间戳。相反,如果删除一个键的过期时间,也会相应的操作这个字典,删除该键对应的过期时间键值对。如图所示:

在这里插入图片描述

(二)过期删除策略

我们知道了,redis数据库如何设置,如何存储过期时间。那么这现在的问题是,如果一个键过期了,那么什么时候被删除呢?

关于这个问题,可以实现的有一下三种方案(redis只采用了其中两种):

  • 定时删除
    设置键的过期时间的同时,创建一个定时器,让定时器在键过期时间来临时,立即执行对键的删除操作
  • 惰性删除
    放任过期不管,但是每次从键空间中获取值的时候,检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键
  • 定期删除
    每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键,至于要删除多少个过期键,以及要检查多少个数据库则由算法决定。

下面我们来瞅瞅这三种策略的优缺点:

1.定时删除

优点:

这种删除策略对于内存来说是友好的,因为这种删除方式可以保证过期的键尽可能快的被删除掉,并释放过期键所占用的内存

缺点:

1.这种删除策略对CPU时间不友好,在过期键比较多的情况下,删除过期键这一行为可能会占用相当一部分的CPU时间,在内存不紧张的但是CPU时间紧张的情况下,这无疑会对服务器的响应时间和吞吐量造成影响。

2.创建一个定时器需要用到redis服务器中的时间时间,而当前时间时间的实现方式为无序链表,查找一个事件的时间复杂度为O(N),所以说,如果采用这种策略,并不能高效的处理大量的时间事件。

2.惰性删除

优点

这种删除策略对于CPU来说是友好的,程序只会在取出键的时候才会对键进行过期检查,这样可以保证对键的删除操作仅限于当前处理的键,这个策略不会在删除其他过期的键上花费任何的时间

缺点

显而易见的,这种删除策略对于内存来说是十分不友好的。因为如果大量的过期键,长期不使用的情况下,就会造成大量的内存被无效的键占用。我们甚至可以将这中情况看作是内存泄露

3.定期删除

针对定期删除来说,这种策略实际上是定时删除和惰性删除这两种策略的折中和整合。定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行时长和频率来减少删除操作对CPU时间的影响。除此之外,通过定期删除过期键,定期删除策略有效的减少了因为过期键而带来的内存浪费。

当然,这种策略的难点就在于如何确定删除的时长和频率。比如,如果设定的删除太频繁或者执行删除的时间太长,就直接回退化为定时删除。如果删除的频率过低或者指定的时间太短,定期删除又会和惰性删除一样,造成内存浪费的情况。

(三)Redis采用的过期键删除策略

Redis数据库实际上采用了两种删除策略:定期删除和惰性删除。通过这两种删除策略的配合使用,服务器可以很好的在合理使用CPU时间和避免内存空间浪费之间取得平衡。

那么,Redis数据库是如何实现这两种删除策略的呢?

惰性删除策略的实现:

过期键的删除策略由expireIfNeeded函数实现,所有读写数据库的Redis命令都会在执行钱调用该函数进行检查。

int expireIfNeeded(redisDb *db, robj *key) {
    if (!keyIsExpired(db,key)) return 0;
    if (server.masterhost != NULL) return 1;
    /* Delete the key */
    server.stat_expiredkeys++;
    propagateExpire(db,key,server.lazyfree_lazy_expire);
    
    notifyKeyspaceEvent(NOTIFY_EXPIRED,
        "expired",key,db->id);
        
    int retval = server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) :
                                               dbSyncDelete(db,key);
    if (retval) signalModifiedKey(NULL,db,key);
    return retval;
}

我们可以看出,如果输入键已经过期,那么expireIfNeed函数将输入键从数据库删除。如果输入键没有过期,则不会做其他动作。所以,每个命令的实现函数都必须能同时处理键存在和不存在两种情况。

定期删除策略的实现

该策略由activeExpireCycle函数实现,每当服务器周期性的操作serverCron函数执行的时候,activeExpireCycle函数就会被调用,在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随你检查一部分的过期时间,并删除其中的过期键。具体代码实现由于太多,有感兴趣可以去看一下,redis6在expire.c中,redis3在redis.c中。

(四)关于AOF、RDB对过期键的处理

1.生成RDB文件

在执行SAVE或者BGSAVE命令创建一个新的RDB文件的时候,程序会对数据库中的过期键进行检查,过期的键不会被保存到新创建的RDB文件中

2.载入RDB文件

载入的时候分为两种情况

(1)服务器以主服务器运行

当服务器以主服务器运行的时候,会对文件中保存的键进行检查,未过期的键会被载入到数据库中,而过期的键则会被忽略,所以过期键对载入RDB文件的主服务器不会造成影响。

(2)服务器以从服务器运行

当服务器以从服务器运行的时候,会将文件中保存的所有键进行保存,不论是否过期。但是由于主从服务器进行数据同步的时候,从服务器的数据库就会被清空,所以一般来讲,过期键载入RDB文件的从高服务器也不会造成影响

3.AOF文件的写入

当数据库中某个键已经过期,但是它还没有被惰性删除或者定期删除,那么AOF文件不会因为这个过期键而产生任何影响。当过期键被惰性删除或者定期删除之后,程序会向AOF文件追加一条DEL命令进行显示的删除

4.AOF文件的重写:

重写的时候程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中

这里有一个有意思的东西,当服务器运行在主从复制模式下的时候,从服务器的过期键删除动作是由主服务器控制的

主服务器在删除一个过期键后,会显示的向所有从服务器发送一个DEL命令,命令从服务器删除这个键;

从服务器在执行客户端发送的命令的时候,即使遇到过期的键也不会将过期的键进行删除,是继续像处理未过期的键一样来处理过期键;

从服务器只有在接到主服务器发送来的DEL命令的时候才会删除过期键。

到此这篇关于Redis 过期键删除策略的实现示例的文章就介绍到这了,更多相关Redis 过期键删除内容请搜索程序员之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持程序员之家!

相关文章

  • Redis事务处理的使用操作方法

    Redis事务处理的使用操作方法

    Redis保证一个事务中的所有命令要么都执行,要么都不执行(原子性),如果客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令,下面通过本文给大家介绍Redis事务处理的使用操作,感兴趣的朋友一起看看吧
    2021-10-10
  • Redis之sql缓存的具体使用

    Redis之sql缓存的具体使用

    本文主要介绍了Redis之sql缓存的具体使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • 嵌入式Redis服务器在Spring Boot测试中的使用教程

    嵌入式Redis服务器在Spring Boot测试中的使用教程

    这篇文章主要介绍了嵌入式Redis服务器在Spring Boot测试中的使用,本文通过实例代码场景分析给大家介绍的非常详细,需要的朋友参考下吧
    2021-07-07
  • 详解Redis中的BigKey如何发现和处理

    详解Redis中的BigKey如何发现和处理

    这篇文章主要为大家详细介绍了Redis中的BigKey如何发现和处理,文中给大家详细讲解了BigKey危害和如何解决这些问题,文章通过代码示例和图文介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • Redis教程之代理ip池设计方法详解

    Redis教程之代理ip池设计方法详解

    这篇文章主要介绍了Redis实现代理ip池的设计方法,文中给出了详细的介绍与示例代码,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友们下面来一起看看吧。
    2017-01-01
  • Redis生成全局唯一ID的实现方法

    Redis生成全局唯一ID的实现方法

    全局唯一ID生成器是一种在分布式系统下用来生成全局唯一ID的工具,本文主要介绍了Redis生成全局唯一ID的实现方法,具有一定的参考价值,感兴趣的可以了解一下
    2022-06-06
  • Redis入门教程_动力节点Java学院整理

    Redis入门教程_动力节点Java学院整理

    Redis是一款开源的、高性能的键-值存储(key-value store)。下面通过本文大家分享Redis入门教程,感兴趣的朋友参考下吧
    2017-08-08
  • SpringBoot整合Mybatis-plus和Redis实现投票功能

    SpringBoot整合Mybatis-plus和Redis实现投票功能

    投票功能是一个非常常见的Web应用场景,这篇文章将为大家介绍一下如何将Redis和Mybatis-plus整合到SpringBoot中,实现投票功能,感兴趣的可以了解一下
    2023-05-05
  • Redis核心原理详细解说

    Redis核心原理详细解说

    这篇文章主要介绍了Redis核心原理详细解说,redis利用epoll实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器
    2022-07-07
  • 一文详细介绍Redis7持久化机制RDB和AOF

    一文详细介绍Redis7持久化机制RDB和AOF

    这篇文章主要给大家分享一下Redis的数据持久化方式,Reids是一个高性能的缓存中间件,它的高性能是因为它是基于内存的,我们知道直接操纵内存是比较快的,所以当机器发生宕机,那么数据就会完全丢失,所以本文详细介绍Redis7持久化机制RDB和AOF
    2023-07-07

最新评论

?


http://www.vxiaotou.com