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 时间表示内存大小没有限制。
查看内存淘汰策略 Redis 内存淘汰策略注意:32 默认最大内存值为位操作系统 3GB。
我们能用 config get maxmemory-policy
命令,查看当前情况 Redis 内存淘汰策略,命令如下:
127.0.0.1:6379> config get maxmemory-policy1) "maxmemory-policy"2) "noeviction"
可以看出此 Redis 使用的是 noeviction 内存淘汰机制的类型表明,当运行内存超过最大设置内存时,任何数据都不会被淘汰,但新操作会报告错误。
内存淘汰策略分类早期版本的 Redis 有以下 6 淘汰策略:
- noeviction:不淘汰任何数据,当内存不足时,新操作会报错,Redis 默认内存淘汰策略;
- allkeys-lru:淘汰整个键值中最长未使用的键值;
- allkeys-random:随机淘汰任意键值;
- volatile-lru:淘汰所有设置过期时间的键值中最长未使用的键值;
- volatile-random:随机淘汰设置过期时间的任意键值;
- volatile-ttl:优先淘汰更早过期的键值。
在 Redis 4.0 版本又新增了 2 淘汰策略:
- volatile-lfu:淘汰所有设置过期时间的键值中最少使用的键值;
- allkeys-lfu:在整个键值中使用最少的键值被淘汰。
修改 Redis 内存淘汰策略其中
allkeys-xxx
这意味着从所有键值中淘汰数据,volatile-xxx
数据从设置过期键的键值中淘汰。
有两种方法可以设置内存淘汰策略。这两种方法各有优缺点,需要用户权衡。
- 方法一:通过“通过”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)。
- logc 用于存储访问频率,8 bit 能表示的最大整数值是 255.值越小,使用频率越低,越容易淘汰;
- ldt 用于存储最后一次 logc 更新时间。
综上所述,我们知道,Redis 内存淘汰策略和过期回收策略是完全不同的概念,内存淘汰策略是解决方案 Redis 运行内存过大的问题,通过和 maxmemory
根据比较,决定是否淘汰数据 maxmemory-policy
决定使用哪种淘汰策略的参数 Redis 4.0 之后已经有 8 种 淘汰策略,默认策略是 noeviction
当内存超过时,任何键值都不会被淘汰,但新操作会报错。