Redis 中的过期元素是如何被处理的?「视频版」——面试突击 002 期

本文以面试问题「Redis 中的过期元素是如何被处理的?」为切入点,用视频加图文的方式和大家聊聊 Redis 过期元素被处理的相关知识点。

涉及的知识点

  1. 过期删除策略有哪些?
  2. 这些过期策略有哪些优缺点?
  3. Redis 使用的是什么过期策略?
  4. Redis 是如何优化和执行过期策略的?

视频答案

点击查看视频内容:https://www.bilibili.com/video/av88741972/

图文答案

常见的过期策略:

  • 定时删除
  • 惰性删除
  • 定期删除

1)定时删除

在设置键值过期时间时,创建一个定时事件,当过期时间到达时,由事件处理器自动执行键的删除操作。

① 优点

保证内存可以被尽快的释放

② 缺点

在 Redis 高负载的情况下或有大量过期键需要同时处理时,会造成 Redis 服务器卡顿,影响主业务执行。

2)惰性删除

不主动删除过期键,每次从数据库获取键值时判断是否过期,如果过期则删除键值,并返回 null。

① 优点

因为每次访问时,才会判断过期键,所以此策略只会使用很少的系统资源。

② 缺点

系统占用空间删除不及时,导致空间利用率降低,造成了一定的空间浪费。

③ 源码解析

惰性删除的源码位于 src/db.c 文件的 expireIfNeeded 方法中,源码如下:

int expireIfNeeded(redisDb *db, robj *key) {// 判断键是否过期if (!keyIsExpired(db,key)) return 0;if (server.masterhost != NULL) return 1;/* 删除过期键 */// 增加过期键个数server.stat_expiredkeys++;// 传播键过期的消息propagateExpire(db,key,server.lazyfree_lazy_expire);notifyKeyspaceEvent(NOTIFY_EXPIRED,"expired",key,db->id);// server.lazyfree_lazy_expire 为 1 表示异步删除(懒空间释放),反之同步删除return server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) :dbSyncDelete(db,key);
}
// 判断键是否过期
int keyIsExpired(redisDb *db, robj *key) {mstime_t when = getExpire(db,key);if (when < 0) return 0; /* No expire for this key *//* Don't expire anything while loading. It will be done later. */if (server.loading) return 0;mstime_t now = server.lua_caller ? server.lua_time_start : mstime();return now > when;
}
// 获取键的过期时间
long long getExpire(redisDb *db, robj *key) {dictEntry *de;/* No expire? return ASAP */if (dictSize(db->expires) == 0 ||(de = dictFind(db->expires,key->ptr)) == NULL) return -1;/* The entry was found in the expire dict, this means it should also* be present in the main dict (safety check). */serverAssertWithInfo(NULL,key,dictFind(db->dict,key->ptr) != NULL);return dictGetSignedIntegerVal(de);
}

所有对数据库的读写命令在执行之前,都会调用 expireIfNeeded 方法判断键值是否过期,过期则会从数据库中删除,反之则不做任何处理。

3)定期删除

每隔一段时间检查一次数据库,随机删除一些过期键。

Redis 默认每秒进行 10 次过期扫描,此配置可通过 Redis 的配置文件 redis.conf 进行配置,配置键为 hz 它的默认值是 hz 10

需要注意的是:Redis 每次扫描并不是遍历过期字典中的所有键,而是采用随机抽取判断并删除过期键的形式执行的。

定期删除的执行流程:

① 优点

通过限制删除操作的时长和频率,来减少删除操作对 Redis 主业务的影响,同时也能删除一部分过期的数据减少了过期键对空间的无效占用。

② 缺点

内存清理方面没有定时删除效果好,同时没有惰性删除使用的系统资源少。

③ 源码解析

定期删除的核心源码在 src/expire.c 文件下的 activeExpireCycle 方法中,源码如下:

void activeExpireCycle(int type) {static unsigned int current_db = 0; /* 上次定期删除遍历到的数据库ID */static int timelimit_exit = 0;      /* Time limit hit in previous call? */static long long last_fast_cycle = 0; /* 上一次执行快速定期删除的时间点 */int j, iteration = 0;int dbs_per_call = CRON_DBS_PER_CALL; // 每次定期删除,遍历的数据库的数量long long start = ustime(), timelimit, elapsed;if (clientsArePaused()) return;if (type == ACTIVE_EXPIRE_CYCLE_FAST) {if (!timelimit_exit) return;// ACTIVE_EXPIRE_CYCLE_FAST_DURATION 是快速定期删除的执行时长if (start < last_fast_cycle + ACTIVE_EXPIRE_CYCLE_FAST_DURATION*2) return;last_fast_cycle = start;}if (dbs_per_call > server.dbnum || timelimit_exit)dbs_per_call = server.dbnum;// 慢速定期删除的执行时长timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;timelimit_exit = 0;if (timelimit <= 0) timelimit = 1;if (type == ACTIVE_EXPIRE_CYCLE_FAST)timelimit = ACTIVE_EXPIRE_CYCLE_FAST_DURATION; /* 删除操作的执行时长 */long total_sampled = 0;long total_expired = 0;for (j = 0; j < dbs_per_call && timelimit_exit == 0; j++) {int expired;redisDb *db = server.db+(current_db % server.dbnum);current_db++;do {// .......expired = 0;ttl_sum = 0;ttl_samples = 0;// 每个数据库中检查的键的数量if (num > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP)num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP;// 从数据库中随机选取 num 个键进行检查while (num--) {dictEntry *de;long long ttl;if ((de = dictGetRandomKey(db->expires)) == NULL) break;ttl = dictGetSignedInteger// 过期检查,并对过期键进行删除if (activeExpireCycleTryExpire(db,de,now)) expired++;if (ttl > 0) {/* We want the average TTL of keys yet not expired. */ttl_sum += ttl;ttl_samples++;}total_sampled++;}total_expired += expired;if (ttl_samples) {long long avg_ttl = ttl_sum/ttl_samples;if (db->avg_ttl == 0) db->avg_ttl = avg_ttl;db->avg_ttl = (db->avg_ttl/50)*49 + (avg_ttl/50);}if ((iteration & 0xf) == 0) { /* check once every 16 iterations. */elapsed = ustime()-start;if (elapsed > timelimit) {timelimit_exit = 1;server.stat_expired_time_cap_reached_count++;break;}}/* 每次检查只删除 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP/4 个过期键 */} while (expired > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP/4);}// .......
}

activeExpireCycle 方法在规定的时间,分多次遍历各个数据库,从过期字典中随机检查一部分过期键的过期时间,删除其中的过期键。

这个函数有两种执行模式,一个是快速模式一个是慢速模式,体现是代码中的 timelimit 变量,这个变量是用来约束此函数的运行时间的。快速模式下 timelimit 的值是固定的,等于预定义常量 ACTIVE_EXPIRE_CYCLE_FAST_DURATION,慢速模式下,这个变量的值是通过 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100 计算的。

总结

本文讲了常见的过期删除策略:

  • 定时删除
  • 惰性删除
  • 定期删除

Redis 采用的是惰性删除 + 定期删除的组合策略,更多内容,详见视频部分。

关注下面二维码,订阅更多精彩内容。

Java中文社群公众号二维码

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

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

相关文章

Linux debian安装DBeaver连接MySQL8、导入和导出数据库详细教程

一、DBeaver简介 ​ DBeaver 是一个基于 Java 开发&#xff0c;免费开源的通用数据库管理和开发工具&#xff0c;使用非常友好&#xff0c;且遵循ASL 协议。由于 DBeaver 基于 Java 开发&#xff0c;可以运行在各种操作系统上&#xff0c;比如Windows、Linux、macOS 等操作系统…

使用 Redis 如何实现查询附近的人?「视频版」——面试突击 003 期

面试问题 Redis 如何实现查询附近的人&#xff1f; 涉及知识点 Redis 中如何操作位置信息&#xff1f;GEO 底层是如何实现的&#xff1f;如何在程序实现查询附近的人&#xff1f;在实际使用中需要注意哪些问题&#xff1f; 视频答案 视频地址&#xff1a;https://www.bili…

利用URL

2019独角兽企业重金招聘Python工程师标准>>> Problem You have a HTML document that contains relative URLs, which you need to resolve to absolute URLs. Solution Make sure you specify a base URI when parsing the document (which is implicit when loadi…

Win10安装DBeaver连接MySQL8、导入和导出数据库详细教程

一、DBeaver简介 ​ DBeaver 是一个基于 Java 开发&#xff0c;免费开源的通用数据库管理和开发工具&#xff0c;使用非常友好&#xff0c;且遵循ASL 协议。由于 DBeaver 基于 Java 开发&#xff0c;可以运行在各种操作系统上&#xff0c;比如Windows、Linux、macOS 等操作系统…

「视频版」当线程池溢出之后,程序会奔溃吗?面试突击 007 期

哈喽&#xff0c;大家好&#xff0c;我是老王&#xff0c;欢迎来到第 7 期的 Java 面试突击。本文的面试题是&#xff0c;当线程池的任务溢出之后&#xff0c;程序会奔溃吗&#xff1f;这个问题问的是关于线程池的任务数超过线程池的承载能力之后&#xff0c;会出现什么情况&am…

有人说:轻量级锁一定比重量级锁快!我忍不住笑了

世界上不止有黑白两色&#xff0c;黑与白之间还是灰色的地带。在成人的世界里&#xff0c;大多数人喜欢非黑即白的观点来看待一个问题&#xff0c;例如《十二公民》中那个刚开始所有人都认定的“一定是富二代杀S了自己的亲身父亲”&#xff0c;到最后大家理性分析和推测之后发现…

Python Django设计模式及模板层

一、Django的MTV模式 MTV代表Model - Template - View &#xff08;模型-模板-视图&#xff09;模式。 M模型层&#xff08;Model&#xff09;负责与数据交互。 T模板层&#xff08;Template&#xff09;负责呈现内容到浏览器。 V视图层&#xff08;View&#xff09;是核心&…

在Tomcat中配配置数据源汇总

为什么80%的码农都做不了架构师&#xff1f;>>> Tomcat本身不具备处理提供数据源的能力。借助于一些开源数据源实现&#xff0c;如&#xff1a;DBCP和C3P0等。 一、在http://commons.apache.org/可下载这些是Tomcat提供配置数据源所需的类库。 注意&#xff1a;Tom…

Linux debian安装、配置和使用PuTTY教程

PuTTY是一个小巧、好用、免费的跨平台的访问Linux服务器的终端工具。PuTTY工具可以使用Telnet、SSH、rlogin、纯TCP以及串行接口连接服务器&#xff0c;使用非常广泛。本文主要介绍Debian系统如何安装PuTTY和如何设置该工具的字体、颜色。从而实现个性化定制自己的PuTTY工具&am…

Linux Debian安装FileZilla文件远程传输工具

一、FileZilla简介 FileZilla是一个快速、免费、跨平台的FTP软件&#xff0c;实用多功能和界面直观的FTP客户端。FileZilla是Windows&#xff0c;Linux&#xff0c;MacOSX等跨平台的图形化FTP&#xff0c;SFTP和FTPS文件管理工具。通过大量直观的工具&#xff0c;FileZilla可以…

Linux Debian11使用国内源安装 Docker 环境

首先切换到root账户&#xff1a; su 一、Debian安装Docker 1.更新并安装一些必要系统工具。 sudo apt-get update sudo apt-get upgrade sudo apt-get install \apt-transport-https \software-properties-common \ca-certificates \curl \gnupg \lsb-release2.安装GPG证书…

计算机网络怎么寻址_计算机网络中的无类寻址

计算机网络怎么寻址To reduce the wastage of IP addresses in blocks we subnetting. But in Classless addressing wastage of IP addresses in a block is more reduced than Classful subnetting. In this variable length, blocks are used that belongs to no class. 为了…

Linux Debian常用下载工具Transmission和qbittorrent

1.Transmission Transmission是Linux Debian系统下的系统自带的一种BitTorrent客户端下载工具&#xff0c;下载速度比较快。在Linux系统可以替代windows上的迅雷下载工具。 2.qbittorrent 使用下面命令安装&#xff1a; sudo apt-get install qbittorrent获取更多资料&#x…

《 面试又翻车了》这次竟然和 Random 有关?

小强最近面试又翻车了&#xff0c;然而令他郁闷的是&#xff0c;这次竟然是栽到了自己经常在用的 Random 上......面试问题既然已经有了 Random 为什么还需要 ThreadLocalRandom&#xff1f;正文Random 是使用最广泛的随机数生成工具了&#xff0c;即使连 Math.random() 的底层…

Linux Debian11使用国内源安装Podman环境

一、Podman简介 Podman 是一个开源的容器运行时项目&#xff0c;可在大多数 Linux 平台上使用。Podman 提供与 Docker 非常相似的功能。正如前面提到的那样&#xff0c;它不需要在你的系统上运行任何守护进程&#xff0c;并且它也可以在没有 root 权限的情况下运行。 Podman 可…

二叉搜索树中第k大元素_二叉搜索树中第K个最小元素

二叉搜索树中第k大元素Problem statement: 问题陈述&#xff1a; Find the k-th smallest element in a given binary search tree (BST). 在给定的二进制搜索树(BST)中找到第k个最小的元素。 Example: 例&#xff1a; K4Kth smallest element in the above binary tree is:…

阿里巴巴Java开发手册建议设置HashMap的初始容量,但设置多少合适呢?

作者 l Hollis来源 l Hollis&#xff08;ID&#xff1a;hollischuang&#xff09;集合是Java开发日常开发中经常会使用到的&#xff0c;而作为一种典型的K-V结构的数据结构&#xff0c;HashMap对于Java开发者一定不陌生。关于HashMap&#xff0c;很多人都对他有一些基本的了解&…

面向.Net程序员的dump分析

背景 Dump文件是进程的内存镜像。可以把程序的执行状态通过调试器保存到dump文件中。在 Windows 系统上&#xff0c; dump 文件分为内核 dump 和用户态 dump 两种。前者一般用来分析内核相关的问题&#xff0c;比如驱动程序&#xff1b;后者一般用来分析用户态程序的问题。 一般…

Linux Debian利用Dockefile将Python的py文件项目代码打包为Docker Podman镜像

1.创建PyCharm工程 使用PyCharm创建testHelloWorld工程&#xff0c;如下图所示&#xff1a; 2.选择本项目下的Python解释器 通过File -> Setting…选择解释器为本工程下的Python解释器。 【备注&#xff1a;一定要将项目python环境依赖存至本项目下&#xff0c;默认依赖本…

Java14发布!Switch竟如此简单?Lombok也不需要了?来用Idea搭建Java14吧!​

Java 14 在 2020.3.17 日发布正式版了&#xff0c;但现在很多公司还在使用 Java 7 或 Java 8&#xff0c;每当看到 Java 又发布新版本心里就慌得一匹。不过此版本并不是 LTS (长期支持版) 版本&#xff0c;所以不要慌&#xff0c;我们先来了解一下好了&#xff0c;等 LTS 版本发…