Redis 内存淘汰策略有哪些?过期数据如何删除?

Redis 在面试中出现的概率非常大,毕竟后端项目如果用到分布式缓存的话,一般用的都是 Redis。目前,还没有出现一个能够取代 Redis 的分布式缓存解决方案。

这篇文章中,我会分享几道 Redis 内存管理相关的问题,都很常见。不论是面试还是项目中用到 Redis,都能有帮助。

下面几篇是之前分享的 Redis 相关的文章,没看过的朋友可以抽空看看:

  • 这 7 道 Redis 基础问题,很常见!!

  • 如何发现 Redis 热 Key,有哪些解决方案?

  • Redis 大 key 有什么危害?如何排查和处理?

  • Redis 除了缓存还能做什么?可以做消息队列吗?

  • 本地缓存和分布式缓存有什么区别?如何选择?

  • 宕机了,Redis 如何避免数据丢失?

  • Redis 如何使用批量操作提高效率?

Redis 给缓存数据设置过期时间有啥用?

一般情况下,我们设置保存的缓存数据的时候都会设置一个过期时间。为什么呢?

因为内存是有限的,如果缓存中的所有数据都是一直保存的话,分分钟直接 Out of memory。

Redis 自带了给缓存数据设置过期时间的功能,比如:

127.0.0.1:6379> expire key 60 # 数据在 60s 后过期
(integer) 1
127.0.0.1:6379> setex key 60 value # 数据在 60s 后过期 (setex:[set] + [ex]pire)
OK
127.0.0.1:6379> ttl key # 查看数据还有多久过期
(integer) 56

注意:Redis 中除了字符串类型有自己独有设置过期时间的命令 setex 外,其他方法都需要依靠 expire 命令来设置过期时间 。另外, persist 命令可以移除一个键的过期时间。

过期时间除了有助于缓解内存的消耗,还有什么其他用么?

很多时候,我们的业务场景就是需要某个数据只在某一时间段内存在,比如我们的短信验证码可能只在 1 分钟内有效,用户登录的 Token 可能只在 1 天内有效。

如果使用传统的数据库来处理的话,一般都是自己判断过期,这样更麻烦并且性能要差很多。

Redis 是如何判断数据是否过期的呢?

Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。

Redis 内存淘汰策略有哪些?过期数据如何删除?_第1张图片

redis过期字典

过期字典是存储在 redisDb 这个结构里的:

typedef struct redisDb {
    ...

    dict *dict;     //数据库键空间,保存着数据库中所有键值对
    dict *expires   // 过期字典,保存着键的过期时间
    ...
} redisDb;

过期的数据的删除策略了解么?

如果假设你设置了一批 key 只能存活 1 分钟,那么 1 分钟后,Redis 是怎么对这批 key 进行删除的呢?

常用的过期数据的删除策略就两个(重要!自己造缓存轮子的时候需要格外考虑的东西):

  1. 惰性删除:只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。

  2. 定期删除:每隔一段时间抽取一批 key 执行删除过期 key 操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。

定期删除对内存更加友好,惰性删除对 CPU 更加友好。两者各有千秋,所以 Redis 采用的是 定期删除+惰性/懒汉式删除 。

但是,仅仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致大量过期 key 堆积在内存里,然后就 Out of memory 了。

怎么解决这个问题呢?答案就是:Redis 内存淘汰机制。

Redis 内存淘汰机制了解么?

相关问题:MySQL 里有 2000w 数据,Redis 中只存 20w 的数据,如何保证 Redis 中的数据都是热点数据?

Redis 提供 6 种数据淘汰策略:

  1. volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。

  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰。

  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。

  4. allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。

  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。

  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

4.0 版本后增加以下两种:

  1. volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰。

  2. allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key。

你可能感兴趣的:(分布式,Redis,数据库,redis,数据库,缓存)