📫作者简介:小明java问道之路,专注于研究 Java/ Liunx内核/ C++及汇编/计算机底层原理/源码,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。
📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。
🏆 CSDN博客专家/后端领域优质创作者/内容合伙人、InfoQ签约作者、阿里云专家/签约博主、51CTO专家 🏆
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~
本文目录
本文导读
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的三种过期策略以及其中原理和源码,二是讲解内存淘汰策略的八种方式和其原理。
转载:https://blog.csdn.net/FMC_WBL/article/details/128378414