文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

详细聊聊Redis的过期策略

2024-04-02 19:55

关注

保存过期时间

Redis可以为每个key设置过期时间,会将每个设置了过期时间的key放入一个独立的字典中。

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

定期删除

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

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

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

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

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

Redis的过期策略

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

惰性删除策略的实现

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

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

image.png

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

image.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过期,要给过期时间设置一个随机范围,而不能全部在同一时间过期。

参考:

《Redis的设计与实现》

《Redis深度历险》

总结

到此这篇关于Redis过期策略的文章就介绍到这了,更多相关Redis过期策略内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯