0

0

一文聊聊Redis中的过期策略

青灯夜游

青灯夜游

发布时间:2022-01-07 19:05:07

|

2255人浏览过

|

来源于掘金社区

转载

本篇文章带大家介绍一下redis中的过期策略,看看惰性删除策略、定期删除策略的实现方法,希望对大家有所帮助!

一文聊聊Redis中的过期策略

保存过期时间

Redis可以为每个key设置过期时间,会将每个设置了过期时间的key放入一个独立的字典中。【相关推荐:Redis视频教程

typedef struct redisDb { 
int id; //id是数据库序号,为0-15(默认Redis有16个数据库) 
long avg_ttl; //存储的数据库对象的平均ttl(time to live),用于统计 
dict *dict; //存储数据库所有的key-value 
dict *expires; //存储key的过期时间 
dict *blocking_keys;//blpop 存储阻塞key和客户端对象 
dict *ready_keys;//阻塞后push 响应阻塞客户端 存储阻塞后push的key和客户端对象 dict *watched_keys;//存储watch监控的的key和客户端对象 
} redisDb;

dict 用来维护一个 Redis 数据库中包含的所有 Key-Value 键值对,expires则用于维护一个 Redis 数据库中设置了失效时间的键(即key与失效时间的映射)。注意这里的失效时间是用毫秒的时间戳表示的,比如2022-01-02 22:45:02过期则value为1641134702000

当我们使用expire命令设置一个key的失效时间时,Redis 首先到 dict 这个字典表中查找要设置的key是否存在,如果存在就将这个key和失效时间添加到 expires 这个字典表。

当我们使用setex命令向系统插入数据时,Redis 首先将 Key 和 Value 添加到 dict 这个字典表中,然后将 Key 和失效时间添加到 expires 这个字典表中。注意setex只能用于字符串

简单地总结来说就是,设置了失效时间的key和具体的失效时间全部都维护在 expires 这个字典表中。

设置过期时间

expire的使用

expire命令的使用方法如下: expire key ttl(单位秒)

127.0.0.1:6379> expire name 2 #2秒失效 
(integer) 1 
127.0.0.1:6379> get name 
(nil) 
127.0.0.1:6379> set name zhangfei 
OK 
127.0.0.1:6379> ttl name #永久有效 
(integer) -1 
127.0.0.1:6379> expire name 30 #30秒失效 
(integer) 1 
127.0.0.1:6379> ttl name #还有24秒失效 
(integer) 24 
127.0.0.1:6379> ttl name #失效 
(integer) -2

Redis有四个不同的命令可以用于设置键的生存时间(键可以生存多久)或过期时间(键什么时候会被删除):

expire 命令用于将键key的生存时间设置为ttl

pexpire 命令用于将键key的生存时间设置为ttl毫秒

expireat 命令用于将键key的过期时间设置为timestamp所指定的数时间戳

pexpireat 命令用于将键key的过期时间设置为timestamp所指定的毫秒数时间戳

注意expire、pexpire、expireat最终实现都是通过pexpireat实现的,也就是说无论客户端执行哪个命令,都会Redis都会转换成pexpireat命令执行。所以expires字典中存的时间是用毫秒时间戳表示的键的过期时间。

过期策略

如果一个键过期了,那什么时候被删除呢?

有三种过期策略

  • 定时删除:在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。(创建定时器删除
  • 惰性删除:放任键的过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。(使用的时候删除
  • 定期删除:每隔一段时间,程序就对数据库进行一次检查,删除里面过期的键。至于要删除多少过期键,以及要检查多少个数据库,则有算法决定。(定期扫描删除

定时删除

  • 优点

1、对内存最友好:通过使用定时器,可以保证过期的键会尽可能快地被删除,释放所占内存

  • 缺点

1、对cpu最不友好:在过期键比较多的情况下,删除过期键这一行为可能会占用相当一部分cpu的时间,对服务器的响应时间和吞吐量造成影响。

惰性删除

  • 优点

1、对cpu最友好:只有在取出键的时候才会对过期键进行检查,即不需要cpu定期扫描,也不需要创建大量的定时器。

  • 缺点

1、对内存最不友好:如果一个键已经过期,但是后面不会被访问到的话,那么就一直保留在数据库中。如果这样的键过多,无疑会占用很大的内存。

定期删除

定期删除是上面的定时删除和惰性删除的一中折中方案。

eoeAndroid特刊第二期 Android图像处理篇 pdf版
eoeAndroid特刊第二期 Android图像处理篇 pdf版

eoeAndroid特刊第二期:Android图像处理篇 pdf,eoeAndroid策划的第二篇专题,主要整理和翻译在Android中进行图像处理的一些资源和文章,通过本专题内容的学习,您可以掌握如何在Android上对图片编程,主要包括但不限于如下方向的内容:   • Android中支持的图片格式介绍;   • Android中图片库介绍   • 图片的显示(本地的,网络的);   • 图片的格式转换;   •

下载
  • 优点

1、定期删除每隔一段时间执行一次过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对cpu时间的影响。

2、通过删除过期键,能有效的减少因为过期键而带来的内存浪费

  • 缺点 难以确定删除操作执行的时长和频率

1、如果删除操作执行得太频繁,或者执行的时间太长,定期删除策略就会退化成定时删除,以至于占用太多cpu的执行时间。

2、如果删除操作执行的时间太少,或执行时间太短,定期删除策略又会和惰性删除一样,出现内存浪费。

Redis的过期策略

Redis使用是惰性删除定期删除两种策略:通过配好使用这两种策略,服务器可以很好地在合理使用cpu时间和避免浪费内存空间之间取得平衡。

惰性删除策略的实现

过期键的惰性删除删除策略由db.c/expireIfNeeded函数实现,所有读写数据库的Redis命令在执行之前都会调用expireIfNeed函数对输入键进行检查:

  • 如果键已经过期,那么expireIfNeeded函数将键删除
  • 如果键未过期,那么expireIfNeeded函数不做操作

命令调用expireIfNeeded函数过程如下图

1.png

另外因为每个被访问的键都可能被删除,所以每个命令都必须能同时处理键存在以及不存在的情况。 下图表示get命令的执行过程

2.png

定期删除策略的实现

过期键的定期删除策略由redis.c/activeExpireCycle函数实现,每当Redis的服务器周期性操作redis.c/serverCron函数执行时,activeExpireCycle函数就会被调用,它在规定时间内,分多次遍历服务器中各个数据库。

Redis 默认每秒进行 10 次过期扫描,过期扫描不会遍历过期字典中所有的 key, 而是采用了一种简单的贪心策略,步骤如下。

(1)从过期字典中随机选出 20个 key。

(2)删除这 20 个 key 中已经过期的 key。

(3)如果过期的 key的比例超过 1/4,那就重复步骤 (1)。 同时,为了保证过期扫描不会出现循环过度,导致结程卡死的现象,算法还增加了扫描时间的上限,默认不会超过 25ms。

假设一个大型的 Redis 实例中所有的 key 在同一时间过期了,会出现怎样的结果呢?

消耗cpu

Redis 会持续扫描过期字典(循环多次),直到过期字典中过期的key变得稀疏,才会停止(循环次数明显下降)。

导致请求卡顿或超时

当客户端请求到来时,服务器如果正好进入过期扫描状态,客户端的请求将会等待至少 25ms 后才会进行处理,如果客户端将超时时间设置得比较短,比如 10ms,那么就会出现大量的连接因为超时而关闭 ,业务端就会出现很多异常

所以一定要注意过期时间,如果有大批量的key过期,要给过期时间设置一个随机范围,而不能全部在同一时间过期。

更多编程相关知识,请访问:编程入门!!

相关专题

更多
js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

248

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

205

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1435

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

609

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

547

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

539

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

158

2025.07.29

c++字符串相关教程
c++字符串相关教程

本专题整合了c++字符串相关教程,阅读专题下面的文章了解更多详细内容。

77

2025.08.07

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 6.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号