当前位置: 首页 > article >正文

Redis的过期删除策略和内存淘汰策略

🤔

  • 过期删除和内存淘汰乍一看很像,都是做删除操作的,这么分有什么意思?

  • 首先,设置过期时间我们很熟悉,过期时间到了,我么的键就会被删除掉,这就是我们常认识的过期删除,但是实际上的过期删除真的是这样吗?

1 过期删除策略

实际上,一般过期之后的键不是立刻删除的,一般过期键的清除策略有三种,分别是定时删除定期删除惰性删除

1.1 定时删除

定时删除时在设置键的过期时间的同时,创建一个定时器,让定时器在键过期时间来临时,立即执行对键的删除操作

定时删除看起来和我们原来想象的一样,这样对内存来说也确实比较友好,但是对CPU不友好,如果某个时间段比较多的key过期的话,可能会影响命令处理性能。

1.2 惰性删除

所谓惰性就是不要那么勤快,随时都盯着,用的时候发现不对再去删就行了,具体就是使用的时候发现key过期了,此时再进行删除。这个策略的思路是对应用而言,只要不访问,过不过期对于业务而言都无所谓,但是这样也是有代价的,就是,如果某些key一直不来访问,那么本该过期的key,就变成常驻的key了,这种策略对CPU友好,对内存不友好

1.3 定期删除

定期删除就是每隔一段时间,程序就对数据库进行一次检查,每次删除一部分过期键。

定时删除实际实现起来非常不容易,主要如果出现了一场,可能会有key遗漏,以及如果程序重启,原来的定时器就随之重启消失了,那就需要在启动时对过期的键进行进行一些操作,可能是重建定时器,这些都是额外的工作,而且会引入多余的复杂度。

从实际的功能而言,其实并不需要那么实时,所以惰性删除是可以考虑的,但是出于应删尽删的考虑,要保证最终没有漏网之鱼,那有没有这样的策略呢?

有的有的,兄弟有的,加上定期删除作为兜底就可以了。所以Redis过期键采用的删除策略是惰性删除+定期删除二者结合的方式进行,这样就可以以一定CPU消耗换取对内存的友好

1.3.1 定期删除需要关注的两个问题:

  1. 定期删除的频率

    1. 这取决于Redis周期任务的执行频率,周期任务里面会做关闭客户端,删除过期key的一系列任务,可以用INFO查看周期任务频率

  2. 每次删除的数量

    1. 随机选取20个key判断是否过期,同时检查过期key数量占比,如果>25%,则再抽20个重复上述流程,这里是一个循环的过程。

    2. Redis为了保证定期删除不会出现循环过度导致线程卡死现象,为此增加了定期删除循环流程的时间上限,默认不过超过25ms。

前面我们说到,过期删除和内存淘汰的区别是什么,都是做删除操作的?

我们先看它们解决的问题分别是什么?过期删除策略解决的是:过期的key怎么删除?内存淘汰策略解决的是:内存满了怎么办?

由此我们就可以推断出,它们在触发条件目标上,存在区别。

过期删除策略内存淘汰策略
触发条件键的过期时间到达(TTL到期)内存使用达到 maxmemory 限制
目标清理明确声明不再需要的数据腾出内存空间以维持服务可用性

2 内存淘汰策略

🤔 我们刚说到,内存淘汰策略是解决内存满了怎么办?Redis可以存多少数据?什么时候算满?

  • 在32位操作系统中,使用maxmemory来设置最大运行内存,默认值是3G,因为32位的机器最大只支持4GB的内存,而系统本身就需要一定的内存资源来支持运行,默认3G相对合理。

  • 在64位操作系统中,maxmemory的默认值是0,表示没有内存大小限制,也可以主动配置maxmemory

  • 当Redis存储超过这个配置值,则触发内存淘汰,所以说,内存满了其实就是达到设置的maxmemory值了

2.1 有哪些内存淘汰策略?

2.1.1 不进行数据淘汰的策略

noeviction(Redis3.0之后,默认的内存淘汰策略):它表示当运行内存超过最大设置内存时,不淘汰任何数据,这时如果有新的数据写入,会报错通知禁止写入,不淘汰任何数据但是如果没用数据写入的话,只是单纯的查询或者删除操作的话,还是可以正常工作。

2.1.2 进行数据淘汰的策略

2.1.2.1 在设置了过期时间的数据中进行淘汰
  1. volatile-random:随机淘汰设置了过期时间的任意键值

  2. volatile-ttl:优先淘汰更早过期的键值

  3. volatile-lru(Redis3.0之前,默认的内存淘汰策略):淘汰所有设置了过期时间的键值中,最久未使用的键值

  4. volatile-lfu(Redis4.0后新增的内存淘汰策略):淘汰了所有设置过期时间的键值中,最少使用的键值。

2.1.2.2 在所有数据范围内进行淘汰
  • allkeys-random:随机淘汰任意键值

  • allkeys-lru:淘汰整个键值中最久未使用的键值

  • allkeys-lfu(Redis4.0后新增的内存淘汰策略):淘汰整个键值中最少使用的键值

2.1.3 内存淘汰算法LRU

🤔 什么是LRU算法?

LRU全称是Least Recently Used,翻译为最近最少使用,会选择淘汰最近最少使用的数据。

传统LRU算法的实现是基于“链表”结构,链表中的元素按照操作顺序从前往后排列,最新操作的键会被移动到表头,当需要内存淘汰时,只需要删除链表尾部的元素即可,因为链表尾部的元素就代表最久未被使用的元素

Redis并没有使用这样的方式实现LRU算法,因为传统的LRU算法存在两个问题:

  • 需要用链表管理所有的缓存数据,这会带来额外的空间开销

  • 当用数据被访问时,需要在链表上把该数据移动到头端,如果有大量数据被访问,就会带来很多链表移动操作,会很耗时,进而会降低Redis缓存性能

Redis是如何实现LRU算法的?

  • Redis实现的是一种近似LRU算法,目的是为了更好的节约内存,它的实现方式是在Redis的对象结构体中添加一个额外的字段lru,用于记录此数据的最后一次访问时间

  • 当Redis进行内存淘汰时,会使用随机采样的方式来淘汰数据,它是随机取5个值(这个值可以进行配置),然后淘汰最久没有使用的哪个

  • Redis实现LRU算法的优点:

    • 不用为所有的数据维护一个大链表,节约了空间占用

    • 不用在每次数据访问时都移动链表项,提升了缓存的性能

  • 但是LRU算法有一个问题:无法解决缓存污染问题:

    • 当应用一次性加载大量仅访问一次的数据时:

      • 这些数据的“最后一次访问时间”非常新,会挤占缓存空间

      • 即使他们是“一次性”的,LRU也会认为它们“最近被使用过”,而淘汰真正有价值但最后一次访问较早的热点数据

      • 即短期批量操作干扰长期热点数据的保留

就像你学习了一天,刚刚打开手机看了一眼,你的家长回家,说,怎么就知道玩手机,不学习

补充:Redis的对象结构体

Redis中的key和value都被封装成redisObject结构体,key的类型只能是字符串类型,而value的类型可以是任意的Redis数据类型。

typedef struct redisObject {unsigned type:4;          // 对象类型(如字符串、哈希等)unsigned encoding:4;     // 对象编码(底层实现方式)unsigned lru:LRU_BITS;   // LRU时间戳 或 LFU计数器(内存淘汰策略相关)24bitint refcount;            // 引用计数器(内存回收)void *ptr;               // 指向实际数据的指针
} robj;

🤔 如何解决缓存污染的问题呢?

Redis4.0之后引入了LFU算法来解决这个问题。

2.1.4 内存淘汰算法LFU

LFU全称是Least Frequently Used翻译为最近最不常用,LFU是根据数据访问次数来淘汰数据的,它的核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。

所以LFU算法会记录每个数据的访问次数。当一个数据被再次访问时,就会增加该数据的访问次数。这样就解决了偶尔被访问一次之后,数据留存在缓存中很长一段时间的问题

Redis是如何实现LFU算法的?

  • LFU算法相比于LRU算法的实现,多记录了数据的访问频次的信息。

  • LRU和LFU并不会同时开启,基于这个情况,加上节约内存的考虑,Redis在LFU策略下复用lru字段,用它来表示LFU的信息

  • 将24bits的lru字段分成两段来存储,高16bit存储ldt(Last Decrement Time),低8bit存储logc(Logitstic Counter)

    • ldt是用来记录key的访问时间戳

    • logc是用来记录key的访问频次,它的值越小表示使用的频率越低,越容易淘汰,每个新加入的key的logc初始值为5

    • 注:logc并不是单纯的访问次数,而是访问频次(访问频率),因为logc会随时间推移而衰减。

      • 如果上一次访问时间很久,那么访问频次就会衰减,比如一个key,它原来的logc是255,夸张一点,一年没访问了,不该衰减吗

Redis访问key时,logc的变化:

  1. 先按照上次访问距离当前时长,来对logc进行衰减

  2. 然后,再按照一定概率增加logc的值

redis.conf提供了两个配置项,用于调整LFU算法从而控制logc的增长和衰减:

  • lfu-decay-time用于调整logc的衰减速度,它是一个以分钟为单位的数值,默认值为1,lfu-decay-time值越大,衰减越慢

  • lfu-log-factor用于调整logc的增长速度,lfu-log-factor值越大,logc增长越慢

相关文章:

Redis的过期删除策略和内存淘汰策略

🤔 过期删除和内存淘汰乍一看很像,都是做删除操作的,这么分有什么意思? 首先,设置过期时间我们很熟悉,过期时间到了,我么的键就会被删除掉,这就是我们常认识的过期删除,…...

MySQL:数据库设计

目录 一、范式 二、第一范式 二、第二范式 三、第三范式 四、设计 (1)一对一关系 (2)一对多关系 (3)多对多关系 一、范式 数据库的范式是一种规则(规范),如果我们…...

Android Kotlin AIDL 完整实现与优化指南

本文将详细介绍如何在Android中使用Kotlin实现AIDL(Android Interface Definition Language),并提供多种优化方案。 一、基础实现 1. 创建AIDL文件 在src/main/aidl/com/example/myapplication/目录下创建: IMyAidlInterface.…...

synchronized关键字的实现

Java对象结构 synchronized锁升级过程 为了优化synchronized锁的效率,在JDK6中,HotSpot虚拟机开发团队提出了锁升级的概念,包括偏向锁、轻量级锁、重量级锁等,锁升级指的就是“无锁 --> 偏向锁 --> 轻量级锁 --> 重量级…...

Ubuntu K8s集群安全加固方案

Ubuntu K8s集群安全加固方案 在Ubuntu系统上部署Kubernetes集群时,若服务器拥有外网IP,需采取多层次安全防护措施以确保集群安全。本方案通过系统防火墙配置、TLS通信启用、网络策略实施和RBAC权限控制四个核心层面,构建安全的Kubernetes环境…...

如何在spark里搭建local模式

在Spark里搭建local模式较为简单,下面详细介绍在不同环境下搭建local模式的步骤。 ### 环境准备 - **Java**: Spark是基于Java虚拟机(JVM)运行的,所以要安装Java 8及以上版本。 - **Spark**: 可从[Apache…...

opencv 图像的旋转

图像的旋转 1 单点旋转2. 图片旋转(cv2.getRotationMatrix2D)3. 插值方法3.1 最近邻插值(cv2.INTER_NEAREST)3.2 双线性插值(cv2.INTER_LINEAR)3.3 像素区域插值(cv2.INTER_AREA)3.4 双三次插值(cv2.INTER_CUBIC&#…...

【DNS】BIND 9的配置

该文档围绕BIND 9的配置与区域文件展开,介绍了BIND 9配置文件及区域文件的相关知识,以及权威名称服务器、解析器的相关内容,还阐述了负载均衡和区域文件的详细知识,具体如下: 基础配置文件: named.conf&am…...

Spring Boot常用注解详解:实例与核心概念

Spring Boot常用注解详解:实例与核心概念 前言 Spring Boot作为Java领域最受欢迎的快速开发框架,其核心特性之一是通过注解(Annotation)简化配置,提高开发效率。注解驱动开发模式让开发者告别繁琐的XML配置&#xff…...

【多线程】线程互斥 互斥量操作 守卫锁 重入与线程安全

文章目录 Ⅰ. 线程互斥概念Ⅱ. 互斥锁的概念Ⅲ. 互斥锁的接口一、互斥锁的定义二、初始化互斥锁三、销毁互斥锁四、互斥量的加锁和解锁① 加锁接口② 解锁接口五、改进买票系统💥注意事项Ⅳ. 互斥锁的实现原理一、问题引入二、复习知识三、实现原理Ⅴ. 封装锁对象 &&…...

[原创](现代Delphi 12指南):[macOS 64bit App开发]:如何使用NSString类型字符串?

[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…...

Python协程详解:从基础到实战

协程是Python中实现并发编程的重要方式之一,它比线程更轻量级,能够高效处理I/O密集型任务。本文将全面介绍协程的概念、原理、实现方式以及与线程、进程的对比,包含完整的效率对比代码和详细说明,帮助Python开发者深入理解并掌握协…...

学习笔记(C++篇)--- Day 4

目录 1.赋值运算符重载 1.1 运算符重载 1.2 赋值运算符重载 1.3 日期类实现 1.赋值运算符重载 1.1 运算符重载 ①当运算符被用于类类型的对象时,C语言允许我们通过通过运算符重载的形式指定新的含义。C规定类类型对象使用运算符时,必须转换成调用对…...

空闲列表:回收和再利用

空闲列表:回收和再利用 手动与自动内存管理 手动管理:程序员需要明确地分配和释放内存。自动管理:例如使用垃圾收集器(GC),它能够自动检测并回收未使用的对象,不需要程序员干预。 对于某些数据结构如B树,…...

504 nginx解决方案

当遇到 504 Gateway Time-out 错误时,通常是因为 Nginx 作为反向代理等待后端服务(如 PHP-FPM、Java 应用等)响应的时间超过了预设的超时阈值。以下是详细的解决方案,结合知识库中的信息整理而成: 一、核心原因分析 后…...

【消息队列RocketMQ】五、RocketMQ 实战应用与生态拓展

本篇文章主要将结合前面几篇文章的基础讲解,来演示RocketMQ的实际场景中的应用。 一、RocketMQ 实战应用场景​ 1.1 电商系统中的应用​ 在电商系统中,RocketMQ 承担着重要角色。以双十一大促活动为例,短时间内会产生海量的订单请求、库存…...

volatile怎么保证可见性和有序性?(个人理解)

volatile怎么保证可见性和有序性? volatile变量会在字段修饰符中显示ACC_VOLATILE。通过插入内存屏障指令,禁止指令重排序。不管前面与后面任何指令,都不能与内存屏障指令进行重排,保证前后的指令按顺序执行 。同时保证数据修改的…...

计算机组成与体系结构:直接内存映射(Direct Memory Mapping)

目录 CPU地址怎么找到真实的数据? 内存映射的基本单位和结构 1. Pages(页)——虚拟地址空间的基本单位 2. Frames(页框)——物理内存空间的基本单位 3. Blocks(块)——主存和缓存之间的数据…...

RAGFlow:构建高效检索增强生成流程的技术解析

引言 在当今信息爆炸的时代,如何从海量数据中快速准确地获取所需信息并生成高质量内容已成为人工智能领域的重要挑战。检索增强生成(Retrieval-Augmented Generation, RAG)技术应运而生,它将信息检索与大型语言模型(L…...

STM32提高篇: 蓝牙通讯

STM32提高篇: 蓝牙通讯 一.蓝牙通讯介绍1.蓝牙技术类型 二.蓝牙协议栈1.蓝牙芯片架构2.BLE低功耗蓝牙协议栈框架 三.ESP32-C3中的蓝牙功能1.广播2.扫描3.通讯 四.发送和接收 一.蓝牙通讯介绍 蓝牙,是一种利用低功率无线电,支持设备短距离通信的无线电技…...

SpringMVC处理请求映射路径和接收参数

目录 springmvc处理请求映射路径 案例:访问 OrderController类的pirntUser方法报错:java.lang.IllegalStateException:映射不明确 核心错误信息 springmvc接收参数 一 ,常见的字符串和数字类型的参数接收方式 1.1 请求路径的…...

高质量学术引言如何妙用ChatGPT?如何写提示词

目录 1、引言究竟是什么? 2、引言如何构建?? 在学术写作领域,巧妙利用人工智能来构建文章的引言和理论框架是一个尚待探索的领域。小编在这篇文章中探讨一种独特的方法,即利用 ChatGPT 作为工具来构建引言和理论框架…...

【程序员 NLP 入门】词嵌入 - 上下文中的窗口大小是什么意思? (★小白必会版★)

🌟 嗨,你好,我是 青松 ! 🌈 希望用我的经验,让“程序猿”的AI学习之路走的更容易些,若我的经验能为你前行的道路增添一丝轻松,我将倍感荣幸!共勉~ 【程序员 NLP 入门】词…...

从物理到预测:数据驱动的深度学习的结构化探索及AI推理

在当今科学探索的时代,理解的前沿不再仅仅存在于我们书写的方程式中,也存在于我们收集的数据和构建的模型中。在物理学和机器学习的交汇处,一个快速发展的领域正在兴起,它不仅观察宇宙,更是在学习宇宙。 AI推理 我们…...

各种各样的bug合集

一、连不上数据库db 1.可能是密码一大包东西不对; 2.可能是里面某个port和数据库不一样(针对于修改了数据库但是连不上的情况); 3.可能是git代码没拉对,再拉一下代码。❤ 二、没有这个包 可能是可以#注释掉。❤ …...

大模型AI的“双刃剑“:数据安全与可靠性挑战与破局之道

在数字经济蓬勃发展的浪潮中,数据要素已然成为驱动经济社会创新发展的核心引擎。从智能制造到智慧城市,从电子商务到金融科技,数据要素的深度融合与广泛应用,正以前所未有的力量重塑着产业格局与经济形态。 然而,随着…...

如何使用 CompletableFuture、Function 和 Optional 优雅地处理异步编程?

当异步遇上函数式编程,代码变得更优雅 在日常开发中,很多时候我们需要处理异步任务、函数转换和空值检查。传统的回调方式和空值判断常常让代码看起来繁琐而难以维护。幸运的是,Java 提供了 CompletableFuture、Function 和 Optional&#x…...

基于大模型的结肠癌全病程预测与诊疗方案研究

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 二、结肠癌概述 2.1 流行病学特征 2.2 发病机制与危险因素 2.3 临床症状与诊断方法 三、大模型技术原理与应用现状 3.1 大模型的基本原理 3.2 在医疗领域的应用情况 3.3 在结肠癌预测中的潜力分析 四、术前…...

操作系统概述与安装

主流操作系统概述 信创平台概述 虚拟机软件介绍与安装 windows server 安装 centos7 安装 银河麒麟V10 安装 一:主流服务器操作系统 (1)Windows Server 发展历程: 1993年推出第一代 WindowsNT(企业级内核&am…...

算法设计与分析(基础)

问题列表 一、 算法的定义与特征,算法设计的基本步骤二、 算法分析的目的是什么?如何评价算法,如何度量算法的复杂性?三、 递归算法、分治法、贪婪法、动态规划法、回溯法的基本思想方法。四、 同一个问题,如TSP&#…...