Redis 的 key 的过期策略是怎么实现的【经典面试题】

news2024/11/17 7:33:47

前言

        在 Redis 中可以通过命令 expire 对指定的 key 值设置过期时间,在时间到了以后该键值对就会自动删除。

        一个 Redis 中可能会存在很多的 key ,而这些 key 中有很大的一部分都会有过期时间,那么 Redis 怎么知道哪些 key 已经到了过期时间需要删除,哪些 key 还没到过期时间呢?

        有读者可能会说,遍历不就得了,遍历 Redis 中所有的数据,就知道哪些数据已经到时间需要删除,哪些数据还没到时间。但这个方法显然是不行的,因为遍历一遍 Redis 中所有的数据非常的消耗时间和资源,而且还需要不停的遍历。

实现策略

        redis 整体的策略是:1.惰性删除  2.定期删除

惰性删除

        当一个 key 已经到过期时间时,暂时不删除该键值对,直到下次用户访问这个 key 值,才发现该 key 值已经过期,系统就顺便将该键值对删除,并且返回给用户 nil ,表示数据不存在。

定期删除

        规定一个定期删除数据的时间,比如每周删一次,并且删除过程中不是遍历 Rrdis 中所有的键值对,而是抽取一部分键值对,将其中过期的键值对进行删除,要保证定期删除的过程要足够快

        为什么对定期删除的速度有较高的要求呢?

        因为如果定期删除需要遍历 Redis 中所有的数据,将全部过期的键值对都找出来进行删除,那么在 Redis 中的数据很多的情况下,这个过程就会持续很久,而 Redis 是单线程的程序,此时在进行定期删除时,无法同时处理用户传来的请求,这就会导致阻塞,Redis 通常作为缓存,那么如果 Redis 出现了阻塞,就会导致大量的用户请求涌入数据库,很可能导致数据库直接挂掉,会造成很大的损失。

补充

        虽然有了上述的两种策略结合但整体的效果一般,仍然可能有许多过期的 key 值残留,没有被及时删除掉,redis 为了对上述进行补充,还用到了许多的内存淘汰策略

定时删除

        可能有某些文章会提到 Redis 使用了定时删除的策略,但这里明确的说,Redis 中并没有用到定时删除的策略,但定时删除也是可以实现 key 的过期策略的,而且也比较优秀,这里来简单介绍一下

        定时器:在指定的时间到达后,执行对应的任务

        假设在设置 key 的过期时间的同时,为该 key 创建一个定时器,让定时器在 key 的过期时间来临时将 key 删除

        优点:保证内存被尽快的释放

        缺点:如果过期的 key 很多,删除这些 key 就会消耗很多的 CPU 资源。定时器的创建很消耗时间和资源,若为每一个有过期时间的 key 都创建一个定时器,将会有大量的定时器产生,性能影响严重

        要想高效的通过定时删除实现 key 的过期策略,有两个比较优秀的方法

1.基于优先级队列/堆

        优先级队列也叫堆,分为大根堆和小根堆,堆顶的数据是最大/最小的。

        假设现在有许多的 key 都设置了过期时间,将这些 key 都添加到优先级队列中,指定优先级规则为 key 的过期时间最早的在堆顶,也就是以 key 的过期时间来建立小根堆

        由于在优先级队列中,堆顶的 key 是过期时间最早的,所以只要堆顶的 key 还没过期,其他的 key 也不会过期,此时定时器中只要分配一个线程,让这个线程去检查堆顶元素是否过期即可,此时线程不需要遍历所有的 key

        另外,线程检查堆顶元素是否过期也不能检查得太频繁,因为要是不停的去检查堆顶元素是否过期浪费了许多的 CPU 资源,好的做法是,根据当前时刻和堆顶元素的过期时间来设置一个等待时间,当等待时间到了以后,再唤醒线程

        但此时会出现一个问题,如果在线程等待的时候,有一个新的 key 值插入堆,并且过期时间比堆顶 key 的过期时间还早,那么线程要是还继续等待的话,堆顶的 key 已经过期很久了,所以当有新的 key 插入时,要唤醒线程,key 插入以后重新根据当前的时间和堆顶 key 的过期时间来设置线程的等待时间

2.基于时间轮来实现定时删除

        

        把时间划分成很多的小段,划分的粒度看具体的要求,每个小段上都挂着一个链表,每个链表表示一个要执行的任务,假设需要添加一个 key,这个 key 在 300 ms 后过期,那么这个 key 就会挂在 3 号链表上,如果 key 的过期时间很长,假设有 600 ms,那么就循环,挂在 1 号 链表上

        在时间轮上,有一个指针,从 1 号链表开始遍历,每走到一个链表,就把这个链表上的 key 检查一下,看有没有过期的,有过期的就删除,然后继续遍历。

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

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

相关文章

【C语言】InfiniBand驱动mlx4_register_interface函数

一、讲解 mlx4_register_interface函数是Mellanox InfiniBand驱动程序的一部分,这个函数的作用是注册一个新的接口(intf)到InfiniBand设备。这允许不同的子系统,如以太网或存储,能够在同一个硬件设备上注册它们各自需要的接口,在…

Vue3全家桶 - VueRouter - 【6】导航守卫

导航守卫 查看以下情形: 点击主页链接时,默认情况下可直接进入指定页面,如下图,但是问题是该跳转的界面是需要用户登录后方可访问的; 可设置导航守卫来检测用户是否登录,如果已登录,则进入后台…

解决 Webpack 中 ERROR in main Module not found: Error: Can‘t resolve ‘./src‘ 问题

出自 BV1MN411y7pw, P98 黑马AJAX-Node.js-Webpack教学视频中webpack部分,打包的时候出错 ERROR in main Module not found: Error: Cant resolve ./src in V:\Web\mycode\webpack\01_webpack_use resolve ./src in V:\Web\mycode\webpack\01_webpack_us…

Leetcode30-串联所有单词的子串[三种方法]

文章目录 30. 串联所有单词的子串(hard)方法一:暴力方法二:滑窗再次优化 小记-map的使用 30. 串联所有单词的子串(hard) 方法一:暴力 思路: map存每个单词出现的个数。枚举s串的每一…

haproxy-高性能负载均衡反向代理服务

目录 一、HAProxy(High Availability Proxy)概述 1、HAProxy的概念 2、HAProxy的主要特性 3、HAProxy的优缺点 4、Haproxy负载均衡策略 5、LVS、nginx、HAProxy的区别 二、安装HAProxy 1、yum安装 2、第三方rpm包安装 3、编译安装 3.1 解决 l…

深度学习模型部署(六)TensorRT工作流and入门demo

TensorRT工作流程 官方给出的步骤: 总结下来可以分为两大部分: 模型生成:将onnx经过一系列优化,生成tensorrt的engine模型 选择batchsize,选择精度precision,模型转换 模型推理:使用python或…

软考 系统架构设计师之回归及知识点回顾(6)

接前一篇文章:软考 系统架构设计师之回归及知识点回顾(5) 10. 边缘计算 边云协同 边缘计算与云计算各有所长,云计算擅长全局性、非实时、长周期的大数据处理与分析,能够在长周期维护、业务决策支撑等领域发挥优势&…

微信小程序问题定位——sourcemap文件

使用sourceMap在微信小程序中进行线上问题定位,主要可以通过以下步骤实现: 下载微信开发者工具首先,确保已经安装了微信开发者工具,这是进行小程序开发和调试的基础。登录微信公众平台并下载sourceMap文件:登录微信小…

Mysql中的MVCC

”真正学会,如你般自由~“ MVCC机制简介 MVCC(Multi-Version-Concurrency-Control)多版本并发控制,MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问;在编程中实现事务内存。 取自 MVCC存在被…

Editor.md-编辑器

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

[LeetCode][426]【学习日记】将二叉搜索树转化为排序的双向链表——前驱节点pre 和 当前节点cur 的使用

题目 426. 将二叉搜索树转化为排序的双向链表 将一个 二叉搜索树 就地转化为一个 已排序的双向循环链表 。 对于双向循环列表,你可以将左右孩子指针作为双向循环链表的前驱和后继指针,第一个节点的前驱是最后一个节点,最后一个节点的后继是第…

力扣--深度优先算法/回溯算法90.子集Ⅱ

思路分析&#xff1a; 成员变量&#xff1a; result: 用于存储最终的子集结果。path: 用于存储当前正在构建的子集。 DFS函数&#xff1a; dfs(vector<int>& nums, int start): 递归地生成子集。 从给定的start索引开始遍历数组。如果当前元素与前一个元素相同&#…

论文阅读FCN-Transformer Feature Fusion for PolypSegmentation

本文提出了一种名为Fully Convolutional Branch-TransFormer (FCBFormer)的图像分割框架。该架构旨在结合Transformer和全卷积网络&#xff08;FCN&#xff09;的优势&#xff0c;以提高结肠镜图像中息肉的检测和分类准确性。 1&#xff0c;框架结构&#xff1a; 模型采用双分…

Java项目:46 ssm005基于SSM框架的购物商城系统+jsp(含文档)

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 项目是单体ssm电商水果平台&#xff0c;包括前台商城平台及后台管理系统 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流…

linux中查看目录文件(ls)用法:

查看目录下的文件&#xff1a;ls&#xff08;list&#xff09; 作用 查看目录下的内容 格式 ls -参数 操作对象参数 参数功能-l以长格形式显示文件和目录的详细信息,ls命令默认只显示名称的短格式。-d显示指定目录本身的信息,而不显示目录下的各个文件和子目录的信息。-…

【三分钟学会Redis 客户端常用命令】redis数据库、对象、字符串、列表、集合、哈希、过期设置等

目录 1. 数据库&#xff1a;2. 键&#xff1a;3. 值&#xff1a;字符串&#xff1a;列表&#xff1a;哈希&#xff1a;集合&#xff1a;有序集合&#xff1a; 4. 键过期设置&#xff1a; 1. 数据库&#xff1a; 切换数据库命令&#xff1a;select index清空数据库&#xff08;…

链表与归并排序

一个C#链表实例 链表&#xff0c;主要是“链”每个类中&#xff0c;都包含一个指向后一个节点的指针 class ListNode{public string Name { get; set; }public ListNode Next;public ListNode(string name){this.Name name;this.Next null;}}基本练成链子&#xff0c;对于插…

CSS 02

1.复合选择器 &#xff08;1.1&#xff09;后代选择器 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&q…

[软件工具]yolo实例分割数据集转labelme的json格式

软件界面&#xff1a; YOLO实例分割数据集转LabelMe JSON格式软件是一款功能强大的数据转换工具&#xff0c;旨在将YOLO&#xff08;You Only Look Once&#xff09;实例分割数据集转换为LabelMe的JSON格式&#xff0c;以满足不同图像标注软件之间的数据共享需求。 该软件具有…

ChatGLM:基于ChatGLM-6B使用ptuning进行微调,实现类instruction的效果

由于业务需要&#xff0c;调研下怎么训练一个虚拟角色出来&#xff0c;所以找了一些文档参考&#xff0c;其中有一个基于ChatGLM-6B使用ptuning进行微调&#xff0c;实现类instruction的效果的现成的项目&#xff0c;给大家分享下。 一、介绍 由于ChatGLM-6B 不支持instructio…