首页 > 图灵资讯 > 技术篇>正文

Redis 缓存满了怎么办?

2023-08-21 17:21:28

引言

Redis 缓存使用内存来保存数据。随着需要缓存的数据量的增加,有限的缓存空间将不可避免地被填充。在这个时候,我们该怎么办?接下来,本文将讨论缓存后的数据淘汰机制。

值得注意的是,在 Redis 中 过期策略 和 内存淘汰策略 是两个完全不同的概念。Redis 过期策略是指 Redis 使用哪种策略来删除过期的键值对;内存淘汰机制是指当 Redis 在运行内存超过设定的最大内存后,将使用什么策略来删除合格的键值对,以确保 Redis 高效运行。

Redis 最大运行内存

只有在 Redis 只有当运行内存达到一定的阀值时,才会触发内存淘汰机制。这个阀值是我们设置的最大运行内存,这个值在 Redis 可以在配置文件中找到,配置项是 maxmemory

内存淘汰执行流程如下图所示:

内存淘汰执行流程图

查询最大运行内存

我们可以使用命令 config get maxmemory 查看设置的最大运行内存,命令如下:

127.0.0.1:6379> config get maxmemory1) "maxmemory"2) "0"

我们发现这个值其实是 0,这是 64 当位操作系统默认值时 maxmemory 为 0 时间表示内存大小没有限制。

注意:32 默认最大内存值为位操作系统 3GB。

查看内存淘汰策略 Redis 内存淘汰策略

我们能用 config get maxmemory-policy 命令,查看当前情况 Redis 内存淘汰策略,命令如下:

127.0.0.1:6379> config get maxmemory-policy1) "maxmemory-policy"2) "noeviction"

可以看出此 Redis 使用的是 noeviction 内存淘汰机制的类型表明,当运行内存超过最大设置内存时,任何数据都不会被淘汰,但新操作会报告错误。

内存淘汰策略分类

早期版本的 Redis 有以下 6 淘汰策略:

  1. noeviction:不淘汰任何数据,当内存不足时,新操作会报错,Redis 默认内存淘汰策略;
  2. allkeys-lru:淘汰整个键值中最长未使用的键值;
  3. allkeys-random:随机淘汰任意键值;
  4. volatile-lru:淘汰所有设置过期时间的键值中最长未使用的键值;
  5. volatile-random:随机淘汰设置过期时间的任意键值;
  6. volatile-ttl:优先淘汰更早过期的键值。

在 Redis 4.0 版本又新增了 2 淘汰策略:

  1. volatile-lfu:淘汰所有设置过期时间的键值中最少使用的键值;
  2. allkeys-lfu:在整个键值中使用最少的键值被淘汰。

其中 allkeys-xxx 这意味着从所有键值中淘汰数据, volatile-xxx 数据从设置过期键的键值中淘汰。

修改 Redis 内存淘汰策略

有两种方法可以设置内存淘汰策略。这两种方法各有优缺点,需要用户权衡。

  • 方法一:通过“通过”config set maxmemory-policy 策略“命令设置”。其优点是设置后立即生效,无需重启 Redis 服务,缺点是重启 Redis 之后,设置将失效。
  • 方法二:通过修改 Redis 修改配置文件,设置“maxmemory-policy 战略”,其优点是重启 Redis 服务后配置不会丢失,缺点是必须重新启动 Redis 只有设置服务才能生效。
内存淘汰算法

从内存淘汰策略的分类可以看出,除了随机删除和不删除外,主要有两种淘汰算法:LRU 算法 和 LFU 算法。

LRU 算法

LRU 全称是 Least Recently Used 翻译是最近最少使用的一种常用的页面置换算法,选择最近最久没有使用的页面进行淘汰。

1. LRU 算法实现

LRU 算法需要基于链表结构,链表中的元素按照操作顺序从前到后排列,最新的操作键将移动到表头。当需要消除内存时,只需删除链表尾部的元素。

2. 近 LRU 算法

Redis 使用的是一种相似性 LRU 该算法旨在更好地节省内存,其实现方法是为现有的数据结构添加额外的字段,以记录该键值的最后一次访问时间,Redis 当内存被淘汰时,数据将通过随机采样被淘汰。它是随机采集的 5 个值(此值可配置),然后淘汰最长未使用的。

3. LRU 算法缺点

LRU 算法有一个缺点,比如一个很久没用过的键值。如果最近被访问一次,就不会被淘汰。即使是使用次数最少的缓存,也不会被淘汰,所以在 Redis 4.0 之后引入了 LFU 算法,我们一起来看看。

LFU 算法

LFU 全称是 Least Frequently Used 最不常用和最不常用的算法是根据总访问次数淘汰数据。它的核心思想是“如果数据在过去被访问过很多次,那么未来被访问的频率就会更高”。

LFU 与偶尔访问一次相比,数据不会被淘汰的问题得到了解决。 LRU 算法也更合理。

在 Redis 记录在每个对象的头中 LFU 源代码如下:

typedef struct redisObject {    unsigned type:4;    unsigned encoding:4;    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or                            * LFU data (least significant 8 bits frequency                            * and most significant 16 bits access time). */    int refcount;    void *ptr;} robj;

在 Redis 中 LFU 存储分为两部分,16 bit 的 ldt(last decrement time)和 8 bit 的 logc(logistic counter)。

  1. logc 用于存储访问频率,8 bit 能表示的最大整数值是 255.值越小,使用频率越低,越容易淘汰;
  2. ldt 用于存储最后一次 logc 更新时间。
总结

综上所述,我们知道,Redis 内存淘汰策略和过期回收策略是完全不同的概念,内存淘汰策略是解决方案 Redis 运行内存过大的问题,通过和 maxmemory 根据比较,决定是否淘汰数据 maxmemory-policy 决定使用哪种淘汰策略的参数 Redis 4.0 之后已经有 8 种 淘汰策略,默认策略是 noeviction 当内存超过时,任何键值都不会被淘汰,但新操作会报错。

上一篇 GC的前置工作,聊聊GC是如何快速枚举根节点的
下一篇 SpringBoot-1-Spring Boot实战:快速搭建你的第一个应用,以及了解原理

文章素材均来源于网络,如有侵权,请联系管理员删除。