【征服redis6】Redis的内存淘汰详解

目录

1.redis的基本策略

2.Redis中的缓存淘汰策略

 3.Redis内存不足的情况

 4.几种淘汰策略的实现原理

5.项目实践与优化策略

5.1 配置案例

5.2 项目优化策略参考


数据库存储会将数据保存到磁盘中,而Redis的核心数据是在内存中的,而Redis本身主要用来做缓存,当 Redis 的内存达到最大限制时,会发生什么情况?redis 会怎么处理呢?

Redis性能很高,官方给的数据 读:110000次/s,写 81000次/s。但是长期使用,Key会不断增加,Redis作为缓存使用,物理内存也会满,内存与硬盘交换(swap)虚拟内存也会被占满,频繁的IO操作会导致性能急剧下降。

在使用Redis时,我们一般会为Redis的缓存空间设置一个大小,不会让数据无限制地放入Redis缓存中。可以使用下面命令来设定缓存的大小,比如设置为4GB:

既然 Redis 设置了缓存的容量大小,那缓存被写满就是不可避免的。当缓存被写满时,我们需要考虑下面两个问题:决定淘汰哪些数据,如何处理那些被淘汰的数据?

进而, 我们可以提出几个连环炮问题:

第一问:如果不处理,让redis的内存达到最大,会出现什么情况

第二问:如果必须淘汰掉一些过期数据,该淘汰谁?

第三问:一种淘汰策略够吗?还有哪些常见的策略?不同策略分别适合什么类型的业务?

第四问:淘汰策略该如何配置?是否会对系统性能产生影响?

事实上,面试也经常是这样,从简单问题开始,用连环炮的方式不断递递进,直到我们的知识盲区。

1.redis的基本策略

redis的过期策略可以概括为两种情况:定期删除 + 惰性删除

定期删除:redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载。

那为什么不用定时删除策略呢?
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略。 

惰性删除:定期删除可能导致很多过期的key 到了时间并没有被删除掉。这时就要使用到惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且过期了,是的话就删除。

定期删除 + 惰性删除存在的问题。如果某个key过期后,定期删除没删除成功,然后也没再次去请求key,也就是说惰性删除也没生效。这时,如果大量过期的key堆积在内存中,redis的内存会越来越高,导致redis的内存块耗尽。那么就应该采用内存淘汰机制。

2.Redis中的缓存淘汰策略

介绍缓存策略之前,我们先看几种常见的通用缓存处理算法:

1.最近最少使用(Least Recently Used, LRU):LRU 策略会根据键的最近使用时间来判断其热度。当内存空间不足时,会优先淘汰最久未使用的键,即最近最少被使用的键。

2.先进先出(First In, First Out, FIFO):FIFO 策略按照键的插入顺序来决定淘汰顺序。最先插入的键会被最先淘汰。

3.最少使用(Least Frequently Used, LFU):LFU 策略根据键被访问的频率来决定淘汰顺序。访问次数较少的键会被优先淘汰。

4.随机(Random):随机策略会随机选择要淘汰的键。

Redis提供了8种缓存淘汰策略,如下:

1、noeviction:不进行淘汰数据。一旦缓存被写满,再有写请求进来,Redis就不再提供服务,而是直接返回错误。Redis 用作缓存时,实际的数据集通常都是大于缓存容量的,总会有新的数据要写入缓存,这个策略本身不淘汰数据,也就不会腾出新的缓存空间,我们不把它用在 Redis 缓存中。
2、volatile-ttl:在设置了过期时间的键值对中,移除即将过期的键值对。
3、volatile-random:在设置了过期时间的键值对中,随机移除某个键值对。
4、volatile-lru:在设置了过期时间的键值对中,移除最近最少使用的键值对。
5、volatile-lfu:在设置了过期时间的键值对中,移除最近最不频繁使用的键值对
6、allkeys-random:在所有键值对中,随机移除某个key。
7、allkeys-lru:在所有的键值对中,移除最近最少使用的键值对。
8、allkeys-lfu:在所有的键值对中,移除最近最不频繁使用的键值对。

虽然看起来很多,但其实很简单。:

  1. noeviction就是不淘汰。
  2. volatile打头的就是从设置了过期时间的元素中移除一些 ,相对应的allkeys就是从全部键中选择。很明显前者速度快,但是不彻底,后者正好相反。
  3. 以lru为后缀的就是使用最近最少使用的策略,以lfu就是最近最不频繁的策略,random就是随机选。

通常情况下推荐优先使用 allkeys-lru 策略。这样可以充分利用 LRU 这一经典缓存算法的优势,把最近最常访问的数据留在缓存中,提升应用的访问性能。 如果你的业务数据中有明显的冷热数据区分,建议使用 allkeys-lru 策略。 如果业务应用中的数据访问频率相差不大,没有明显的冷热数据区分,建议使用 allkeys-random 策略,随机选择淘汰的数据就行。 如果没有设置过期时间的键值对,那么 volatile-lru,volatile-lfu,volatile-random 和 volatile-ttl 策略的行为, 和 noeviction 基本上一致。但是一般来说,allkeys-lruvolatile-lru是使用最广泛的策略。

 3.Redis内存不足的情况

Redis故障,个人经验不是很多,这里通过查阅整理了几种常见的redis内存不足的提示信息和原因解释,我们一起来看一下:

错误信息解释
OOM command not allowed when used memory Redis 的内存已经耗尽,无法执行当前命令。
Redis out of memoryRedis 已经耗尽了可用的内存,无法继续存储更多的数据。如果内存不足时,读数据也可能失败。
Max number of clients reached Redis 已经达到最大连接数限制,无法接受更多的客户端连接。
命令执行缓慢当 Redis 的内存接近饱和状态时,性能可能会下降。由于 Redis 需要进行内存淘汰操作来释放空间,这可能会导致命令执行的延迟增加。
内存淘汰,命中率下降为了腾出内存空间,Redis 会根据配置的内存淘汰策略清除一些键。这可能导致一些数据被删除,从而影响应用程序的行为,例如缓存命中率下降等。
连接失败当 Redis 内存不足以处理更多的客户端连接时,新的连接请求可能会被拒绝或延迟处理。这可能导致连接失败或长时间等待。

 4.几种淘汰策略的实现原理

在Redis的设计中,内存淘汰的实现原理与其数据结构和管理机制紧密关联,不同的内存淘汰策略有不同的实现方式。 一般来说,volatile-*策略适合大部分键值对都设置了过期时间的场景,而*lru策略则适合数据的重要性随时间逐渐降低的场景。当然,这些策略都不是定死的,可能需要根据实际情况进行调整和优化。

首先,当我们开启Redis的maxmemory策略并设置了相应的内存上限后,Redis就会在达到这个上限时触发数据淘汰操作。这个操作是如何进行的呢?它主要依赖于Redis的内存淘汰策略。

我们以allkeys-lru策略为例,这个策略的原理是什么呢?

LRU代表Least Recently Used,即最近最少使用。Redis为每个存储在内存中的key都维护了一个LRU标识,这个标识用于记录该key最后一次被访问的时间。当Redis需要淘汰数据时,它会从所有的key中挑选一部分key,检查它们的LRU标识,然后淘汰其中最少被访问的key。

这就好比我们收拾房间,当空间不足时,我们会选择几乎不用的东西进行淘汰,以便腾出空间。

同理,volatile-lru策略也是基于LRU原理,只不过它只会考虑那些设置了过期时间的key。

allkeys-random和volatile-random策略则是在所有key或者设置了过期时间的key中随机选择一个进行淘汰,就像是“闭眼摸象”。

volatile-ttl策略则是在设置了过期时间的key中找出生存时间(TTL)最短的进行淘汰,也就是“谁生命短,谁先走”。

我们再次描述一下每种策略的淘汰方式:

  1. volatile-ttl策略则是在设置了过期时间的key中找出生存时间(TTL)最短的进行淘汰,也就是“谁生命短,谁先走”。
  2. noeviction:实现原理十分简单,就是当内存达到上限时,对于所有的写操作都返回错误。
  3. allkeys-lru:它的实现基于Redis的数据结构和LRU(Least Recently Used,最近最少使用)策略。在Redis中,每个键值对都有一个LRU字段,表示这个键值对上一次被访问的时间。当内存达到上限时,Redis会观察一部分键值对的LRU字段,选择其中LRU值最小(即最久未被访问)的键值对进行淘汰。
  4. volatile-lru:与allkeys-lru类似,只不过它只对设置了过期时间的键值对进行观察和淘汰。
  5. allkeys-random:每当需要淘汰数据时,Redis随机选取一部分键值对,然后从中随机淘汰一个。这种方式的优点是简单且开销较小,缺点是淘汰的数据可能是重要的数据。
  6. volatile-random:与allkeys-random类似,只是它只对设置了过期时间的键值对进行随机淘汰。
  7. volatile-ttl:这个策略的实现也依赖Redis的数据结构。每个设置了过期时间的键值对都有一个ttl(time to live,生存时间)字段。当内存达到上限时,Redis会观察一部分设置了过期时间的键值对的ttl字段,选择其中ttl值最小(即最快过期)的键值对进行淘汰。

Redis中的LRU算法并没有严格按照常规的LRU算法的方式实现,而是基于LRU算法的思想做了自己的优化。我们知道,实现LRU算法时,需要将所有的数据按照访问时间距离当前时间的长短排序放到一个双向链表中,基于这个链表实现数据的淘汰。但Redis中存储的数据量是非常庞大的,如果要基于常规的LRU算法,就需要把所有的key全部放到这个双向链表中,这样就会导致这个链表非常非常大,不止需要提供更多的内存来存放这个链表结构,而且操作这么庞大的链表的性能也是比较差的。

所以,Redis中的LRU算法是这样实现的:首先定义一个淘汰池,这个淘汰池是一个数组(大小为16),然后触发淘汰时会根据配置的淘汰策略,先从符合条件的key中随机采样选出5(可在配置文件中配置)个key,然后将这5个key按照空闲时间排序后放到淘汰池中,每次采样之后更新这个淘汰池,让这个淘汰池里保留的总是那些随机采样出的key中空闲时间最长的那部分key。需要删除key时,只需将淘汰池中空闲时间最长的key删掉即可。

为了方便理解它的思想放上一张图:原始地址
 

5.项目实践与优化策略

5.1 配置案例

当你配置 Redis 的淘汰策略时,你可以通过编辑 Redis 配置文件来实现。
。可以根据需要将 maxmemory-policy 设置为你选择的淘汰策略,例如 allkeys-lru、volatile-lfu 等。同时,你还可以使用 maxmemory 配置项来设置 Redis 的最大内存限制。rdbcompression 用于启用在内存中存储数据时的压缩,它减少了数据占用的内存空间。其次,rdbcompression 用于在进行 RDB 快照持久化时启用压缩,以减小生成的 RDB 文件的大小。

# 当达到最大内存限制时,Redis 的淘汰策略
# 可选值:noeviction(禁止淘汰), allkeys-lru(LRU算法), allkeys-lfu(LFU算法), allkeys-random(随机淘汰),
#        volatile-lru(LRU算法,仅针对设置了过期时间的键), volatile-lfu(LFU算法,仅针对设置了过期时间的键),
#        volatile-random(随机淘汰,仅针对设置了过期时间的键)
# 默认值:noeviction
maxmemory-policy noeviction# Redis 的最大内存限制(以字节为单位)。
# 当达到最大内存限制时,Redis 将根据淘汰策略进行键的淘汰。
# 默认值:0(无限制)
maxmemory 102400# 启用压缩存储
# 开启压缩存储可以减少存储数据所占用的内存空间,但会增加 CPU 负载。
# 默认值:no
rdbcompression yes# 保存 RDB 文件时启用压缩
# 当进行 RDB 快照持久化时,启用压缩可以减少 RDB 文件的大小。
# 默认值:no
rdbcompression yes

5.2 项目优化策略参考

在项目中,我们可以参考如下原则来优化:

定时删除(TTL):可以为 Redis 中的键设置过期时间(Time To Live,TTL),让键在一定时间后自动过期并被删除。这样可以确保过期的键及时被清除,释放内存空间。

延迟删除(Lazy Expire):延迟删除是一种优化手段,当键过期时并不立即删除,而是在访问该键时才进行删除操作。这可以减少删除操作的开销,并在实际需要时进行键的清除。

内存碎片整理(Memory Defragmentation):在 Redis 中,当删除一些键后,可能会导致内存出现碎片化。这些碎片化的内存空间无法被有效利用。内存碎片整理是一种优化手段,通过重新分配内存来整理碎片化的内存空间,以提高内存的利用率。

压缩存储(Memory Compression):Redis 4.0 版本引入了内存压缩(Memory Compression)功能,使用 LRU 算法对键进行压缩,以减少内存使用。压缩存储可以在某些场景下显著降低内存占用。

内存分配器优化:Redis 使用的内存分配器可以影响其性能和内存管理。选择适合的内存分配器,如 jemalloc,可以提高 Redis 的性能和内存利用率。
 

redis缓存在使用的时候还会存在很多问题,其中最常见的,也是面试经常考的就是:击穿, 穿透, 雪崩, 污染四个问题。这几个概念是什么意思 ,以及如何解决在这里有比较好的解释了,我们就不细说了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/240897.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java SECS管理系统 将逐步推出 SECS 客户端(Passive) 管理系统 SECS快速开发平台 springboot secs开发平台

SECS管理系统 这是一套SECS客户端(Passive),可以直接连接PLC设备,支持Modbus、三菱MC、欧姆龙Fine、OPC-UA、西门子S7设备等通信。 企业已经有了EAP软件,但是设备没有SECS通信功能,这时候可以使用这套框架,直接连接设备&#xff…

数据守护盾牌:敏感数据扫描与脱敏,让安全合规无忧

前言 在信息时代,数据已经成为企业和组织的核心资产,其价值与日俱增。然而,随着数据使用的普及和复杂度的提升,数据安全与合规问题也变得越来越突出。敏感数据的保护显得尤为重要,因为这些数据一旦泄露或被不当使用&a…

npm超详细安装(包括配置环境变量)!!!npm安装教程(node.js安装教程)

安装node.js:(建议选择相对低一点的版本,相对稳定)​下载完成直接点击next即可(安装过程中会直接添加path的系统变量,变量值是自己的安装路径,可自行选择,比如:D:\software\)​安装完成:winR打开电脑控制台&#xff0c…

css实现动态水波纹效果

效果如下: 外层容器 (shop_wrap): 设置外边距 (padding) 提供一些间距和边距 圆形容器 (TheCircle): 使用相对定位 (position: relative),宽度和高度均为 180px,形成一个圆形按钮圆角半径 (border-radius) 设置为 50%&…

IP 地址如何进行动态分配?

由于 IP 地址资源的有限性,大部分用户上网都是使用动态 IP 地址,而不是静态 IP 地址。动态 IP 地址指的是在需要的时候才进行 IP 地址分配的方式,而静态 IP 地址是固定分配一个 IP 地址,每次都用这一个地址。因此,IP 地…

TikTok电商加快闭环,独享IP为运营带来哪些好处?

近日有消息称TikTok电商在加快闭环,以后商家可能无法继续在TikTok上为其他电商平台或独立站引流了。如今“TikTok Shop Shopping Center”平台正在构建,将各种购物渠道整合为一体,这可能是一种趋势,意味着TikTok逐渐从社交应用转型…

华清远见作业第二十七天——网络编程(第二天)

思维导图&#xff1a; 在虚拟机实现客户端控制机械臂 代码&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <a.h> #define SER_PORT 8888 //服务端口 #d…

搭建知识付费小程序平台:如何避免被坑,选择最佳方案?

随着知识经济的兴起&#xff0c;知识付费已经成为一种趋势。越来越多的人开始将自己的知识和技能进行变现&#xff0c;而知识付费小程序平台则成为了一个重要的渠道。然而&#xff0c;市面上的知识付费小程序平台琳琅满目&#xff0c;其中不乏一些不良平台&#xff0c;让老实人…

MetaGPT学习笔记 - task1task2

章节&#xff1a;task1&task2 一.github地址&#xff1a;github.com/geekan/MetaGPT 二.MetaGPT: 多智能体框架​ 使 GPT 以软件公司的形式工作&#xff0c;协作处理更复杂的任务 MetaGPT输入一句话的老板需求&#xff0c;输出用户故事 / 竞品分析 / 需求 / 数据结构 / A…

【PyTorch】PyTorch之Tensors索引切片篇

文章目录 前言一、ARGWHERE二、CAT、CONCAT、CONCATENATE三、CHUNK四、GATHER五、MOVEDIM和MOVEAXIS六、PERMUTE七、RESHAPE八、SELECT九、SPLIT十、SQUEEZE十一、T十二、TAKE十三、TILE十四、TRANSPOSE十五、UNBIND十六、UNSQUEEZE十七、WHERE 前言 介绍常用的PyTorch之Tenso…

【计算机网络】【新加坡南洋理工大学】【Computer Control Network】【广域网和局域网简介】【中英对照(自译)】

一、说明 仅供学习使用。 二、广域网&#xff08;WAN&#xff09;和局域网&#xff08;LAN&#xff09;简介

【学习心得】Git深入学习

若您还未安装Git或是只想简单使用&#xff0c;可以先看看我的文章“Git快速上手”【学习心得】Git快速上手http://t.csdnimg.cn/gsaGj 一、深入学习Git必须熟悉两个概念 &#xff08;1&#xff09;【四个区】Git本地有三个区&#xff0c;远程仓库也可以看出成一个区域 工作区…

【论文阅读】Deep Graph Contrastive Representation Learning

目录 0、基本信息1、研究动机2、创新点3、方法论3.1、整体框架及算法流程3.2、Corruption函数的具体实现3.2.1、删除边&#xff08;RE&#xff09;3.2.2、特征掩盖&#xff08;MF&#xff09; 3.3、[编码器](https://blog.csdn.net/qq_44426403/article/details/135443921)的设…

CSS实现的 Loading 效果

方式一、纯CSS实现 代码&#xff1a;根据需要复制 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>CSS Animation Library for Developers and Ninjas</title><style>/* ---------------…

.net core 6 使用注解自动注入实例,无需构造注入 autowrite4net

像java使用autowrite一样使用 1、前提先注册到ioc容器当中 builder.Services.AddScoped 2、nuget引入AutoWrite4Net 3、启用 //启用自动注入 app.UseAutoWrite(); 4、在类上使用注解 [StartAutoWrite] public class NacosController : ControllerBase 5、实例上使用注解 …

【Redis】AOF 源码

在上篇, 我们已经从使用 / 机制 / AOF 过程中涉及的辅助功能等方面简单了解了 Redis AOF。 这篇将从源码的形式, 进行深入的了解。 1 Redis 整个 AOF 主要功能 Redis 的 AOF 功能概括起来就 2 个功能 AOF 同步: 将客户端发送的变更命令, 保存到 AOF 文件中AOF 重写: 随着 Red…

新能源汽车智慧充电桩方案:基于视频监控的可视化智能监管平台

一、方案概述 TSINGSEE青犀&触角云新能源汽车智慧充电桩方案围绕互联网、物联网、车联网、人工智能、视频技术、大数据、4G/5G等技术&#xff0c;结合云计算、移动支付等&#xff0c;实现充电停车一体化、充电桩与站点管理等功能&#xff0c;达到充电设备与站点的有效监控…

橘子学K8S04之重新认识Docker容器

我们之前分别从 Linux Namespace 的隔离能力、Linux Cgroups 的限制能力&#xff0c;以及基于 rootfs 的文件系统三个角度来理解了一下关于容器的核心实现原理。 这里一定注意说的是Linux环境&#xff0c;因为Linux Docker (namespaces cgroups rootfs) ! Docker on Mac (bas…

Dockerfile镜像实战

目录 一 构建SSH镜像 1.开启ip转发功能 2. 准备工作目录 3.修改配置文件 5.启动容器并修改root密码 二 构建Systemctl镜像 1. 准备工作目录 ​编辑2.修改配置文件 3.生成镜像 4.启动容器&#xff0c;并挂载宿主机目录挂载到容器中&#xff0c;进行初始化 5.进入容器 三…

npm install 无反应 npm run serve 无反应

说明情况&#xff1a;其实最开始我就是发现我跟着黑马的苍穹外卖的前端day2的环境搭建做的时候&#xff0c;到这一步出现了问题&#xff0c;无论我怎么 npm install 和 npm run serve 都没有像黑马一样有很多东西进行加载&#xff0c;因此我换了一种方法 1.在这个文件夹下cmd …