专栏首页决胜机器学习《Redis设计与实现》读书笔记(十二) ——Redis键的生存时间与过期时间

《Redis设计与实现》读书笔记(十二) ——Redis键的生存时间与过期时间

《Redis设计与实现》读书笔记(十二) ——Redis键的生存时间与过期时间

(原创内容,转载请注明来源,谢谢)

1、设置方式

在redis客户端,可以通过expire命令设置某个键的以秒为单位的生存时间(TTL),也可以用pexpire设置以毫秒为单位的时间。setex命令可以在对字符串对象设置值的时候,同时设置过期时间,但是其只针对字符串对象可以使用。在经过指定时间后,服务器会自动删除生存时间为0的键值对。

在客户端,还可以通过expireat或pexpireat命令,设置数据库键的过期时间。这个时间是一个unix时间戳,当时间到达该时间时,redis会删除该键。

另外,可以用ttl或pttl命令,查看键的剩余生存时间。如果键不存在数据库,会返回-2;键没有过期时间,返回-1;如果键有过期时间,则用过期时间的unix毫秒时间戳,减去当前时间的unix毫秒时间戳。

2、设置过期时间原理

redis有四个命令设置过期时间,但是实际上,expire、pexpire、expireat三个命令都是通过pexpireat命令实现的。

首先,expire命令可以转化成pexpire命令,只需要将设置的值乘以1000。

接着pexpire命令可以转化成pexpireat命令,只需要把当前时间的unix毫秒时间戳加上过期时间的unix毫秒时间戳即可。

另外,expireat命令可以转化成pexpireat命令,只需要将设置的值乘以1000。

如下图所示:

3、保存过期时间

redisDb结构的expire字典,保存了数据库的所有键的过期时间,因此也称这个属性为过期字典。

过期字典的键是一个指针,指向键空间的某个对象,也就是数据库的某个键;过期字典的值是一个long类型的整数,这个整数保存了键所指向的数据库的键的过期时间,是一个毫秒精度的unix时间戳。

带过期字典的数据库如下图所示:

上图中,键出现了两次,但是实际上只会出现一次,过期时间中的键都是指针,指向地址而已。上图那么画仅为了便于展示。

因此,pexpireat命令实际上是给redisDb结构的expires字典,添加一个键值对,键是指向要设置过期时间的键对象的指针,值是long类型的unix毫秒时间戳表示过期时间。

4、移除过期时间

redis客户端执行persist命令,可以将某个key移除过期时间。移除后,再用ttl命令查询,会得到-1的结果,即-1表示的是没有设定过期时间。

而具体实现上,也就是将expires指向key的指针以及其值的内存空间收回即可。redis在用ttl命令查询expires字典,查不到时,就返回-1,表示没有设置过期时间。

5、过期键的删除方式

redis判定键是否过期,即从expires字典,去判断当前时间是否大于字典里的时间,如果大于则表示键过期,否则没有过期。

对于删除过期的键,redis有三种策略,包括定时删除、懒惰删除、定期删除三种,1、3属于主动删除,2属于被动删除。

具体分析如下:

1)定时删除

也就是过期即删除,这种策略会在设定键的过期时间的时候,同时设定一个定时器,定时器的时间一到,马上将对应的键值对删除。

优点:定时删除是最节约内存的方式,保证每个键一到过期时间马上删除。

缺点:删除键需要时间,如果内存紧张的情况下,还要执行删除,会降低效率。此外,定时删除,需要创建大量的定时器,并且定时器在redis中是采用无需链表,查询定时器的时间复杂度是O(N),因此耗时较多。

2)懒惰删除

即放任过期时间不管,但是每次客户端操作数据库的键的时候,都会判断键是否过期,如果过期则删除键,并返回空给客户端;否则直接将相应结果返回客户端。

优点:懒惰删除是对时间上最友好的,不检查键,也不用定时器。

缺点:缺点也很明显,如果大量键已经过期,并且长期没有客户端访问这些键,那么这些键以及其值都会长期占用内存,不释放空间,可以看成内存泄漏。

3)定期删除

即每隔一段时间,redis会键的过期时间,如果过期则删除。至于检查几个键,几个数据库,可以由算法策略决定。

定期删除可以看做定时删除和懒惰删除的折中的方式,每隔一段时间进行一部分的删除,通过限制删除执行的时长和频率来降低对cpu的影响,又避免一些键长期不被删除的风险。

其难点在于定期的策略,即删除频率和删除数量的设定。

6、过期删除的实现

redis实际上是采用上述的懒惰删除和定期删除的方式,对过期键进行删除,没有采用定时删除的方式。

1)懒惰删除

懒惰删除在redis是通过db.c文件的expireIfNeeded函数实现。客户端对每个键的访问,都会先调用此函数。如果键过期,则删除键,否则不动作。这个函数就像一个过滤器,在真正命令执行之前,过滤调过期的键,避免客户端接触到过期的键。

get命令对键的操作如下图,其他命令类似:

2)定期删除

定期删除在redis是通过redis.c文件的activeExpireCycle函数实现。每当redis服务器周期性执行redis.c文件的severCron函数,就会调用到activeExpireCycle函数。该函数会在规定时间内,分多次遍历各个数据库,从redis数据库redisDb结构的expires字典属性中,随机检查一部分键,并删除过期的键。

activeExpireCycle函数工作方式总结如下:

每次函数运行,都从一定量的数据库中,找出一定量的键,进行检查,并删除过期的键;有一个全局变量current_db,会记录activeExpireCycle函数的检查进度,下一次执行时会顺着当前的current_db检查下一个db,检查到最后一个db时这个值会重新变成0。

——written by linhxx 2017.09.03

本文分享自微信公众号 - 决胜机器学习(phpthinker),作者:linhxx

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-09-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 《Redis设计与实现》读书笔记(十三) ——Redis数据库其他内容与总结

    《Redis设计与实现》读书笔记(十三) ——Redis数据库其他内容与总结 (原创内容,转载请注明来源,谢谢) 一、RDB、AOF、复制对过期键的处理 1、R...

    用户1327360
  • Redis专题(十二) ——Redis特殊情况处理机制

    Redis专题(十二) ——Redis特殊情况处理机制 (原创内容,转载请注明来源,谢谢) 一、内存淘汰 当redis的内存不足时,需要采取内存淘汰的方法,...

    用户1327360
  • PHP面向对象核心(二)——继承、多态、接口

    PHP面向对象核心(二) (原创内容,转载请注明来源,谢谢) 三、继承与多态 3.1 继承 1、继承是类级别的复用,关键词为extends;多态是方法级别的复用...

    用户1327360
  • Redis 的过期策略是如何实现的?

    可见在 redisDb 结构的 expire 字典(过期字典)保存了所有键的过期时间

    每天晒白牙
  • 面试官:说说Redis的过期键删除策略吧!(高频)

    对于Redis服务器来说,内存资源非常宝贵,如果一些过期键一直不被删除,就会造成资源浪费,因此我们需要考虑一个问题:如果一个键过期了,它什么时候会被删除呢?

    趣学程序-shaofeer
  • 【吊打面试】Redis的过期策略和内存淘汰策略不要搞混淆

    Redis是key-value数据库,在程序中可以设置Redis中缓存的key的过期时间。Redis的过期策略就是指当Redis中缓存的key过期了以后,Red...

    java乐园
  • JavaScript学习(三)

    JavaScript中的所有事物都是对象,如:字符串、数值、数值、函数等,每个对象带有属性和方法。

    Cloud-Cloudys
  • Python内置函数详解【翻译自pyth

    翻译源 来自:https://docs.python.org/3/library/functions.html 

    py3study
  • Linux基金会企业开源指南系列之二 -- 开始创建开源项目(中)

    本文拥有创作共用授权之相同方式共享授权4.0版国际许可协议(Creative Commons Attribution ShareAlike 4.0 Intern...

    开源社
  • 推荐一个GitHub上的Java电商项目(附源码地址)

    此项目是一套完整的小商场系统,主要包括商场后台系统、前端管理页面,管理后台系统。是不是很完善呀。作者对于项目有着详细的介绍,从技术栈到系统的搭建。

    用户5224393

扫码关注云+社区

领取腾讯云代金券