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

news2024/11/25 16:37:17

目录

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.coloradmin.cn/o/1393666.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

契约测试?生产者?消费者?一文帮你理清楚

契约测试?生产者?消费者?一文帮你理清楚 契约测试什么是契约? 先从测试金字塔讲起什么是锲约测试?但它们也有一些令人痛苦的缺点。:通常具有与 e2e 集成测试相反的属性: 那么,什么是…

删除文件怎么找回?恢复文件,3个实用方法!

“我经常会在操作电脑时误删重要的文件,有什么方法可以恢复删除的文件吗?希望大家给我推荐几个有效的操作方法!” 在日常生活和工作中,我们经常会遇到误删文件的情况,这时如何快速有效地恢复这些文件就显得尤为重要。删…

Eclipse搭建python环境

一、下载eclipse eclipse官网下载参考链接 二、 下载PyDev ​PyDev 三、安装和配置pyDev 下载完PyDev,解压之后是下面两个文件夹,我下载的版本是PyDev 7.7 ,然后拷到eclipse对应的目录下就可以 四、然后新建一个python程序 1.新建一个项目 ​​…

S/MIME电子邮件证书申请指南

近年来,邮件安全问题日益突出,电子邮件成为诈骗、勒索软件攻击的重灾区。恶意邮件的占比屡创新高,邮件泄密事件更是比比皆是。在如此严峻的网络安全形势下,使用S/MIME电子邮件证书进行邮件收发是当今最佳的邮件安全解决方案之一。…

设计模式的学习笔记

设计模式的学习笔记 一. 设计模式相关内容介绍 1 设计模式概述 1.1 软件设计模式的产生背景 设计模式最初并不是出现在软件设计中,而是被用于建筑领域的设计中。 1977 年美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任 Christopher Alexander 在…

SD-WAN网络建设:设备、服务与综合解决方案

随着数字化转型的推进,企业对于网络性能和连接的需求日益增加,而SD-WAN(软件定义广域网)作为一项创新的网络解决方案,成为提升效率和灵活性的关键工具。然而,构建一个完善的SD-WAN网络并非仅仅关乎设备的采…

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

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

(2023版)斯坦福CS231n学习笔记:DL与CV教程 (4) | 神经网络与反向传播

前言 📚 笔记专栏:斯坦福CS231N:面向视觉识别的卷积神经网络(23)🔗 课程链接:https://www.bilibili.com/video/BV1xV411R7i5💻 CS231n: 深度学习计算机视觉(2017&#xf…

storm统计服务开启zookeeper、kafka 、Storm(sasl认证)

部署storm统计服务开启zookeeper、kafka 、Storm(sasl认证) 当前测试验证结果: 单独配置zookeeper 支持acl 设置用户和密码,在storm不修改代码情况下和kafka支持当kafka 开启ACL时,storm 和ccod模块不清楚配置用户和密…

提升UI设计水平的关键技能,轻松打造专业形象!

UI关注软件图形界面,包括按钮、布局、动画、过渡、微交互等。简而言之,UI关于界面的外观。 UI设计包括以下界面: -用户图形界面(GUI):GUI设计用户与系统控制工具之间的视觉交互。计算机桌面是一种GUI。 -语音控制界面(VUI):VUI设计用户与系…

网站SEO优化方案

1,去各类搜索引擎里面,注册你的站点 解决方案:注册地址:https://seo.chinaz.com/chinaz.com 2,网站地址使用 https 会增加搜索排名 解决方案:https:www.xxx.com 3,官网每个页面的 meta 里面&a…

小明和完美序列——map

由完美序列的定义可以知道,序列中每个数字的个数,要么是等于它本身,要么就是一个没有。 如果一个数字出现的次数比它本身大,我们就选择删掉多出的, 这样肯定比完全删除是更优的,只有在当一个数字出现的次数…

宏集干货丨探索物联网HMI的端口转发和NAT功能

来源:宏集科技 工业物联网 宏集干货丨探索物联网HMI的端口转发和NAT功能 原文链接:https://mp.weixin.qq.com/s/zF2OqkiGnIME6sov55cGTQ 欢迎关注虹科,为您提供最新资讯! #工业自动化 #工业物联网 #HMI 前 言 端口转发和NAT功…

数据结构和算法的部分例题(力扣)

1.数组 1.1 合并一个数组的两个有序区间 public class MargTwo {public static void main(String[] args) {int[] arr1{1,5,6,2,4,10,11};int[] arr2new int[arr1.length];marg2(arr1,0,2,3,6,arr2);}private static void marg2(int[]arr1,int iStar,int iEnd,int jStar,int j…

百度搜索Push个性化:新的突破

作者 | 通用搜索产品研发组 导读 本文简单介绍了百度搜索Push个性化的发展过程,揭示了面临的困境和挑战:如何筛选优质物料、如何对用户精准推荐等。我们实施了一系列策略方法进行突破,提出核心的解决思路和切实可行的落地方案。提升了搜索DAU…

OceanBase集群部署

我认为学习一个中间件比较好的方式是,先了解它的架构和运行原理,然后动手部署一遍,加深对它的了解,再使用它,最后进行总结和分享 本篇介绍OceanBase部署前提条件和集群部署 1.使用开源免费的社区版,企业版…

配置redis挂载

1. 暂停和删除redis 2.创建文件夹 /usr/local/software/redis/6379/conf/ /usr/local/software/redis/6379/data/ 把redis-conf文件上传到conf文件夹中 3.配置网络 docker network create --driver bridge --subnet172.18.12.0/16 --gateway172.18.1.1 wn_docker_net 4.运…

vue的简单认识

vue是一套前段框架,免除了原生JavaScript中的dom的繁杂操作,简化书写。 vue基于MVVM(Model-View-ViewModel)思想,实现数据的双向绑定,将编程的重点放在数据上。 简单说就是,我们会把操作数据库…

k8s---ingress对外服务(七层)

ingress 概念 k8s的对外服务,ingress service作用现在两个方面: 1、集群内部:不断跟踪的变化,更新endpoint中的pod对象,基于pod的ip地址不断变化的一种服务发现机制。 2、集群外部:类似于负载均衡器&a…

一文了解Servlet

文章目录 1、什么是Servlet2、Servlet快速入门3、Servlet生命周期4、Servlet体系结构5、urlPatern配置6、XML编写Servlet 1、什么是Servlet Servlet是Java提供的一门动态web资源开发技术Servlet是JavaEE规范之一,其实就是一个接口,将来我们需要定义Serv…