Redis过期删除策略和内存淘汰策略剖析

本文目录

本文目录

本文导读

一、Redis 过期策略

1、三种过期策略 

1.1、定时删除

1.2、定期删除

1.3、惰性删除

2、Redis的过期策略

2.1、Redis 过期删除策略(惰性删除和定期删除)

2.2、惰性删除原理解析

2.3、如何判断 Key 是否过期

2.4、定期删除原理解析

二、内存淘汰策略

1、Redis 内存淘汰策略有哪些

2、八种Redis 内存淘汰策略

3、Redis中的LRU 算法和 LFU 算法

 

 

本文导读

Redis的过期删除策略和内存淘汰策略,很容易混淆。本文分两个模块,一讲解Redis的三种过期策略以及其中原理和源码,二是讲解内存淘汰策略的八种方式和其原理。

一、Redis 过期策略

1、三种过期策略 

众所周知,Redis是一个 key-value 的键值数据库。我们可以设置缓存在Redis中的 key 的过期时间。Redis的过期策略是指当缓存在Redis中的 key 过期时,Redis将要如何处理。

过期策略通常有以下三种:定时删除、惰性删除、定期删除

1.1、定时删除

定时删除:

设置了过期时间的 key 创建一个计时器,过期后将立即清除。此策略可以立即清除过期数据,并且对内存友好;然而,它将占用大连的CPU资源来处理过期数据,从而影响缓存的响应时间和吞吐量(时间换空间)

优点:

可以保证过期 key 会被尽快删除,也就是内存可以被尽快地释放,定时删除对内存是最友好的。

缺点:

在过期 key 比较多的情况下,删除过期 key 可能会占用相当一部分 CPU 时间,在内存不紧张但 CPU 时间紧张的情况下,将 CPU 时间用于删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响。所以,定时删除策略对 CPU 不友好。

1.2、定期删除

定期删除:

定期扫描特定数量数据库的过期字典中特定数据的 Key(随机检查、集中检查),并清除过期 Key。该策略是一种定时过期和延迟过期的方案,通过调整计划扫描的时间间隔和每次扫描的有限时间消耗,CPU和内存可以在不同的情况下得到最佳平衡(过期字典存储设置了过期时间的所有 Key 的过期时间数据,其中 key 是指向键空间中某个Key 的指针,value是 Key 的UNIX时间戳表示的过期时间,精度为毫秒,键空间指的是保存在Redis集群中的所有Key)。 

优点:

通过限制删除操作的持续时间和频率,可以减少删除操作对CPU的影响。同时,可以删除一些过期数据,以减少过期 Key 的无效空间占用。

缺点:

内存清理不如常规删除有效,并且在没有延迟删除的情况下使用更少的系统资源。很难确定执行删除操作的时间和频率。如果执行过于频繁,则常规删除策略与常规删除策略相同,这对CPU不友好;如果执行太少,则与延迟删除相同。过期 Key 占用的内存将无法及时释放。

1.3、惰性删除

惰性删除:

当访问 Key 时,将判断该 Key 是否已过期。如果过期,它将被清除。这种策略可以最大限度地节省CPU资源,但它非常消耗内存,而且许多过期数据仍在内存中。在极端情况下,大量过期 Key  可能无法再次访问,因此不会被清除并占用大量内存。(空间换时间) 

优点:

由于每次访问 Key 时都会检查其是否过期,因此此策略仅使用少数系统资源。因此,延迟删除策略对CPU时间最为友好。

缺点:

如果某个 Key 已过期且该 Key 仍在数据库中,则只要该过期 Key 未被访问,该过期 Key 所占用的内存就不会被释放,从而导致一定的内存空间浪费。因此,延迟删除策略对内存不友好。

2、Redis的过期策略

2.1、Redis 过期删除策略(惰性删除和定期删除)

Redis中同时使用了惰性过期和定期过期两种过期策略。

目的是为了在合理使用 CPU 时间和避免内存浪费之间取得平衡。

2.2、惰性删除原理解析

Redis的延迟删除策略由 db.c 文件中 expireIfNeeded 函数的实现。

int expireIfNeeded(redisDb *db, robj *key) {
    // 判断 key 是否过期
    if (!keyIsExpired(db,key)) return 0;
    ....
    /* 删除过期键 */
    ....
    // 如果 server.lazyfree_lazy_expire 为 1 表示异步删除,反之同步删除;
    return server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) : dbSyncDelete(db,key);
}

在访问或修改 Key 之前,Redis将调用expireIfNeeded函数来检查 Key 是否过期:如果过期,请删除 Key。至于选择异步删除还是同步删除, lazyfree_lazy_expire 参数配置决策,然后返回空客户端;如果未过期,则不进行任何处理,然后将正常的键值对返回给客户端;

2.3、如何判断 Key 是否过期

每当我们为 Key 设置过期时间时,Redis都会将 Key 与过期时间一起存储在过期字典中,也就是说,过期字典存储数据库中所有 Key 的过期时间。

字典实际上是一个哈希表。哈希表的最大优点是它允许我们以O(1)的时间复杂度搜索。当我们查询 Key 时,Redis首先检查该 Key 是否存在于过期字典中,如果没有,则正常读取键值;如果存在,将获取 Key 的过期时间,并与当前系统时间进行比较。如果大于系统时间, Key 将不会过期,否则将确定 Key 已过期。 

// 过期字典存储在 redisDb 结构中
typedef struct redisDb {
    dict *dict;    // 数据库键空间,存放着所有的键值对
    dict *expires; // 键的过期时间
    ....
} redisDb;

2.4、定期删除原理解析

定期从数据库中“随机”抽取一定数量的 Key 进行检查,并删除过期的 Key 。这种随机性可以理解为,在Redis中,默认情况下,数据库每秒钟检查一次过期10次。此配置可以通过Redis的配置文件Redis Conf完成。配置Key为hz。其默认值为hz 10。

特别强调的是,每次检查数据库时,并不是遍历过期字典中的所有键,而是从数据库中随机选择一定数量的键进行过期检查。

随机抽查的数量定期删除在expire.c 文件下的 activeExpireCycle 函数中,随机检查的数量由 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 定义。它是用代码编写的,值为20。
也就是说,在每一轮抽查中,将随机选择20个 Key 来确定数据库是否过期。

// 定期删除的流程(伪代码)
do {
    expired = 0; // 已过期的数量
    num = 20;    // 随机抽取的数量
    while (num--) {
        // 1. 从过期字典中随机抽取 1 个 key
        // 2. 判断该 key 是否过期,如果已过期则进行删除,同时对 expired++
    }
    // 超过时间限制则退出
    if (timelimit_exit) return;

  // 如果本轮检查的已过期 key 的数量,超过 25%,则继续随机抽查,否则退出本轮检查
} while (expired > 20/4); 

二、内存淘汰策略

1、Redis 内存淘汰策略有哪些

当Redis的运行内存超过Redis设置的最大内存时,将使用内存消除策略删除符合条件的密钥,以确保Redis的高效运行。

Redis使用内存存储数据。在执行每个命令之前,它调用 freeMemoryIfNeeded()  方法来检查内存是否足够。

如果内存不满足新添加数据的最低存储要求,Redis需要临时删除一些数据,以清理当前指令的存储空间。清理数据的策略也称为驱逐算法。

注意:消除数据的过程不能100%清除足够的可用内存空间。如果不成功,它将被重复。完成所有数据尝试后,如果无法满足内存清理要求,将显示错误消息。

当新数据进入redis时,如果内存不足怎么办?

1、最大可用内存:占用的物理内存的比例。默认值为0,表示没有限制。它是根据生产环境中的要求设置的,通常在50%以上。(maxmemory )

2、选择每次要删除的数据数量:选择数据时,它不会扫描整个数据库,这会导致严重的性能消耗并降低读写性能。因此,采用随机获取数据的方法作为要检测的删除数据。(maxmemory-samples)

3、删除策略:达到最大内存后,删除所选数据的策略(maxmemory-policy)会影响过时的相关配置

2、八种Redis 内存淘汰策略

1、无数据消除策略

noeviction(Redis3.0之后,默认的内存淘汰策略) :禁止驱逐数据(Redis 4.0中的默认策略),这将导致内存不足Redis驱逐策略错误。这意味着当运行内存超过最大设置内存时,不会消除任何数据,但不会提供任何服务,并且会直接返回错误。

2、进行数据淘汰的策略

对于“数据消除”策略,可以细分为两种类型:“在设置了过期时间的数据中消除”和“在所有数据范围中消除”。

消除设置了过期时间的数据:

volatile-random:可选地选择数据消除以检测整个数据库数据(所有数据集server.db[i].dice);
volatile-ttl:选择将过期的数据。
volatile-lru(Redis3.0 之前,默认的内存淘汰策略):消除所有设置了过期时间的键值,并选择最近最少使用的数据;
volatile-lfu(Redis 4.0 后新增的内存淘汰策略)消除所有设置了过期时间的键值,并选择最近使用最少的数据;

所有数据:

allkeys-random:选择任何数据以消除和放弃数据驱逐;
allkeys-lru:从整个键值中选择最近最少使用的数据;
allkeys-lfu(Redis 4.0 后新增的内存淘汰策略):消除整个键值中最近使用最少的数据。

3、Redis中的LRU 算法和 LFU 算法

参考:《从零开始的DS生活 轻松从0基础写出链表LRU算法

Redis的过期删除策略和内存淘汰策略,很容易混淆。本文分两个模块,一讲解Redis的三种过期策略以及其中原理和源码,二是讲解内存淘汰策略的八种方式和其原理。

 

ZZ:https://blog.csdn.net/FMC_WBL/article/details/128378414

 

posted @ 2023-09-05 14:16  琅琊甲乙木  阅读(51)  评论(0编辑  收藏  举报