Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redis过期Key删除策略和内存淘汰策略

Redis过期Key删除策略和内存淘汰策略的实现

作者:Surpass余sheng军

当内存使用达到上限,就无法存储更多数据了,为了解决这个问题,Redis内部会有两套内存回收的策略,过期Key删除策略和内存淘汰策略,本文就来详细的介绍一下这两种方法,感兴趣的可以了解一下

Redis之所以性能强,最主要的原因就是基于内存存储,然而单节点的Redis其内存大小不宜过大,否则会影响持久化或主从同步的性能。

Redis内存满了,会发生什么?

我们可以通过修改redis.conf配置文件来设置Redis的最大内存,配置项为maxmemory:

# 格式:
# maxmemory <bytes>
# 例如:
maxmemory 1gb

当内存使用达到上限,就无法存储更多数据了,因此,为了解决这个问题,Redis内部会有两套内存回收的策略:

内存过期策略 - 过期key处理 - 过期删除策略

如何设置过期时间?

查看某个key剩余的存活时间:TTL  key 

# 写入一条数据
set num 123
# 设置20秒过期时间
expire num 20
# 写入一条数据并设置20s过期时间
set num EX 20

Redis是如何知道一个key是否过期呢?

过期字典存储在 redisDb 结构中,如下: 

来看下redisDb的底层源码:

typedef struct redisDb {
    dict dict;                 / The keyspace for this DB , 也就是存放KEY和VALUE的哈希表*/
    dict *expires;              /* 同样是哈希表,但保存的是设置了TTL的KEY,及其到期时间*/
    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, 0 ~ 15 /
    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;

每当我们对一个key设置了过期时间后,Redis会把该key带上过期时间存储到一个过期字典(expires dict)中,也就是说「过期字典」保存了数据库中所有 key 的过期时间。 

当我们查询一个 key 时,Redis 首先检查该 key 是否存在于过期字典中:

是不是TTL到期就立即删除了呢? 

TTL(Time To Live)的含义是存活时间。 

Redis的过期KEY删除策略有两种:

惰性删除

惰性删除策略的优缺点:

优点:

缺点:

周期删除 / 定期删除策略

Redis默认会每秒进行10次过期检查(此配置可以通过Redis的配置文件redis.conf进行配置,配置键为hz,它的默认值是hz 10),每次检查数据库并不是遍历过期字典中的所有key,而是从数据库中随机抽取一定数量的key进行过期检查:

可以看到,定期删除是一个循环的流程

Redis为了保证定期删除不会出现循环过度,导致线程卡死现象,为此增加了定期删除循环流程的时间上限,默认不会超过25ms,超出时间限制则退出。 

定期删除策略的优缺点

优点:

缺点:

可以看到,惰性删除策略和定期删除策略都有各自的优缺点,所以Redis选择「惰性删除+定期删除」这两种策略配和使用,以求在合理使用 CPU 时间和避免内存浪费之间取得平衡。 

如果过期键没有被访问,而定期删除又跟不上新键产生的速度,内存不就慢慢耗尽了吗? 

内存淘汰策略

内存淘汰:

内存淘汰时机

当内存达到阈值时执行内存淘汰,但问题是Redis什么时候会去判断内存是否达到阈值呢?

当Redis内存不足时会怎么做?

Redis 内存淘汰策略有哪些? 

Redis支持内存淘汰,配置参数maxmemory-policy决定了内存淘汰策略,这个参数一共有8个枚举值,也就是说Redis内存淘汰策略共有8种这八种策略大体分为「不进行数据淘汰」和「进行数据淘汰」两类策略:

1. 不进行数据淘汰的策略

2. 进行数据淘汰的策略

针对「进行数据淘汰」这一类策略,又可以细分为「在设置了过期时间的数据中进行淘汰」和「在所有数据范围内进行淘汰」这两类策略。 在设置了过期时间的数据中进行淘汰:

在所有数据范围内进行淘汰:

比较容易混淆的有两个算法:

Redis 4.0开始支持基于LFU算法的淘汰策略! 

Redis为什么新增了LFU淘汰策略?

为什么Redis 4.0有了LFU?

Redis怎么知道某个KEY的最后一次访问时间或者是访问频率呢? 

逻辑访问次数是如何计算的?

 显然LFU的基于访问频率的统计更符合我们的淘汰目标,因此官方推荐使用LFU算法。 

内存淘汰用到的是LRU算法吗?

当Redis作为缓存使用的时候,推荐使用allkeys-lru淘汰策略,该策略会将最近最久未使用的key淘汰,像这种key后期命中的概率也最低,所以将其淘汰。 

到此这篇关于Redis过期Key删除策略和内存淘汰策略的实现的文章就介绍到这了,更多相关Redis过期Key删除策略和内存淘汰策略内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文