redis的过期时间和过期删除机制
一:设置过期时间
redis有四种命令可以用于设置键的生存时间和过期时间:
EXPIRE <KEY> <TTL> : 将键的生存时间设为 ttl 秒
PEXPIRE <KEY> <TTL> :将键的生存时间设为 ttl 毫秒
EXPIREAT <KEY> <timestamp> :将键的过期时间设为 timestamp 所指定的秒数时间戳
PEXPIREAT <KEY> <timestamp>: 将键的过期时间设为 timestamp 所指定的毫秒数时间戳.
二:保存过期时间
那么redis里面对这些key的过期时间和生存时间的信息是怎么保存的呢??
答:在数据库结构redisDb中的expires字典中保存了数据库中所有键的过期时间,我们称expire这个字典为过期字典。
(1)过期字典是一个指针,指向键空间的某个键对象。
(2)过期字典的值是一个longlong类型的整数,这个整数保存了键所指向的数据库键的过期时间–一个毫秒级的 UNIX 时间戳。
下图是一个带过期字典的数据库例子:

过期字典是存储在redisDb这个结构里的:
typedef struct redisDb {
...
dict *dict; //数据库键空间,保存着数据库中所有键值对
dict *expires // 过期字典,保存着键的过期时间
...
} redisDb;
从以上结构中可以看到expire字典(过期字典)和dict字典(数据库键空间,保存着数据库中所有键值对)是并列的,由此可见expire字典的重要性。
三:移除过期时间
PERSIST 命令可以移除一个键的过期时间:
127.0.0.1:6379> set message "hello"
OK
127.0.0.1:6379> expire message 60
(integer) 1
127.0.0.1:6379> ttl message
(integer) 54
127.0.0.1:6379> persist message
(integer) 1
127.0.0.1:6379> ttl message
(integer) -1
persist命令就是expire命令的反命令,这个函数在过期字典中查找给定的键,并从过期字典中移除。
比如在数据库当前状态(如上图所示),当给book这个key移除过期时间:
redis> persist book
(integer) 1
数据库将更新成如下状态:

可以从图中看到,当PERSIST book命令执行之后,过期字典中的 book 键消失了。
四:计算并返回剩余生存时间
ttl命令以秒为单位返回指定键的剩余生存时间。pttl以毫秒返回。两个命令都是通过计算当前时间和过期时间的差值得到剩余生存期的。
127.0.0.1:6379> set minping shuxin
OK
127.0.0.1:6379> expire minping 60
(integer) 1
127.0.0.1:6379> ttl minping
(integer) 57
127.0.0.1:6379> ttl minping
(integer) 27
127.0.0.1:6379> pttl minping
(integer) 23839
127.0.0.1:6379>
redis源码为:
void ttlCommand(redisClient *c) {
ttlGenericCommand(c, 0);
}
void pttlCommand(redisClient *c) {
ttlGenericCommand(c, 1);
}
void ttlGenericCommand(redisClient *c, int output_ms) {
long long expire, ttl = -1;
/* 如果键不存在,返回-2 */
if (lookupKeyRead(c->db,c->argv[1]) == NULL) {
addReplyLongLong(c,-2);
return;
}
/* 如果键存在*/
/*如果没有设置生存时间,返回 -1, 否则返回实际剩余时间 */
expire = getExpire(c->db,c->argv[1]);
if (expire != -1) {
/* 过期时间减去当前时间,就是键的剩余时间*/
ttl = expire-mstime();
if (ttl < 0) ttl = 0;
}
if (ttl == -1) {
addReplyLongLong(c,-1);
} else {
/*将毫秒转化为秒*/
addReplyLongLong(c,output_ms ? ttl : ((ttl+500)/1000));
}
}
五:过期键的删除策略
如果一个键是过期的,那它到了过期时间之后是不是马上就从内存中被被删除呢??如果不是,那过期后到底什么时候被删除呢??
其实有三种不同的删除策略:
(1):立即删除。在设置键的过期时间时,创建一个回调事件,当过期时间达到时,由时间处理器自动执行键的删除操作。
(2):惰性删除。键过期了就过期了,不管。每次从dict字典中按key取值时,先检查此key是否已经过期,如果过期了就删除它,并返回nil,如果没过期,就返回键值。
(3):定时删除。每隔一段时间,对expires字典进行检查,删除里面的过期键。
可以看到,第二种为被动删除,第一种和第三种为主动删除,且第一种实时性更高。下面对这三种删除策略进行具体分析。
立即删除
立即删除能保证内存中数据的最大新鲜度,因为它保证过期键值会在过期后马上被删除,其所占用的内存也会随之释放。但是立即删除对cpu是最不友好的。因为删除操作会占用cpu的时间,如果刚好碰上了cpu很忙的时候,比如正在做交集或排序等计算的时候,就会给cpu造成额外的压力。
而且目前redis事件处理器对时间事件的处理方式--无序链表,查找一个key的时间复杂度为O(n),所以并不适合用来处理大量的时间事件。
惰性删除
惰性删除是指,某个键值过期后,此键值不会马上被删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。所以惰性删除的缺点很明显:浪费内存。dict字典和expires字典都要保存这个键值的信息。
举个例子,对于一些按时间点来更新的数据,比如log日志,过期后在很长的一段时间内可能都得不到访问,这样在这段时间内就要拜拜浪费这么多内存来存log。这对于性能非常依赖于内存大小的redis来说,是比较致命的。
定时删除
从上面分析来看,立即删除会短时间内占用大量cpu,惰性删除会在一段时间内浪费内存,所以定时删除是一个折中的办法。
定时删除是:每隔一段时间执行一次删除操作,并通过限制删除操作执行的时长和频率,来减少删除操作对cpu的影响。另一方面定时删除也有效的减少了因惰性删除带来的内存浪费。
六:redis使用的策略
redis使用的过期键值删除策略是:惰性删除加上定期删除,两者配合使用。
转自:https://www.jianshu.com/p/9352d20fb2e0
redis的过期时间和过期删除机制的更多相关文章
- Mysql设置binlog过期时间并自动删除
问题: Mysql数据库由于业务原因,数据量增长迅速,binlog日志会增加较多,占用大部分磁盘空间. 解决方案: 出于节约空间考虑,可进行删除多余binary日志,并设置定期删除操作. .查看bin ...
- Redis 过期时间
http://www.redis.cn/commands/expire.html 附录: Redis 过期时间 Keys的过期时间 通常Redis keys创建时没有设置相关过期时间.他们会一直存在, ...
- redis文档翻译_key设置过期时间
Available since 1.0.0. 使用開始版本号1.01 Time complexity: O(1) 时间复杂度O(1) 出处:http://blog.csdn.net/colum ...
- redis入门指南(三)—— 事务、过期时间、SORT命令、消息通知与管道
写在前面 学习<redis入门指南>笔记,结合实践,只记录重要,明确,属于新知的相关内容. 事务 1.redis中的事务由一组命令的集合组成,要么都执行,要么都不执行,同时redis的事务 ...
- Redis 过期时间解析
文章参考:<Redis 设计与实现>黄建宏 设置过期时间 通过 EXPIRE 或者 PEXPIRE 命令,客户端可以以秒或毫秒精度为数据库中的某个键设置生存时间 TTL (Time To ...
- 实现JWT刷新机制以及让过期时间更精确
借助accessToken和refreshToken实现 accessToken控制刷新间隔,refreshToken控制最长过期时间 Min过期时间 = refreshToken过期时间 ...
- 针对永久不过期的key 批量设置过期时间
问题需求: redis内存暴增,后来发现有很多设置永久不过期. 解决:查找出来之后针对前缀批量设置过期时间 (过期时间与开发沟通 保证服务不受影响) 来源于网上杨一的代码 正好解决了我遇到的问题 在这 ...
- memcached的key,value,过期时间的限制
1. key值最大长度? memcached的key的最大长度是250个字符,是memcached服务端的限制. 如果您使用的客户端支持"key的前缀"或类似特性,那么key( ...
- C# 给PDF文档设置过期时间
我们可以给一些重要文档或者临时文件设置过期时间和过期信息提示来提醒读者或管理者文档的时效性,并及时对文档进行调整.更新等.下面,分享通过C#程序代码来给PDF文档设置过期时间的方法. 引入dll程序集 ...
随机推荐
- Excel通用类工具(二)
前言 上一篇中写到了用反射来处理类中的不用的属性,但是Excel的列名还得手动输入,这样还是比较麻烦的,今天这篇就利用自定义注解来解决手动传入列名的问题:其实很简单的,只需要在上一篇的基础上加一个类就 ...
- Node.js性能分析神器Easy-Monitor
摘要: 使用Easy-Monitor,可以准确定位Node.js应用的性能瓶颈,帮助我们优化代码性能. 当应用出现性能问题时,最大的问题在于:如何准确定位造成性能瓶颈的代码呢?对于Node.js开发者 ...
- WePY - 小程序敏捷开发实践丨掘金开发者大会
声明:内容转载他处,如有侵权,可协商下架 本主题虽然在其它地方讲了很多次,但还是有非常多新内容.因为很多东西正在做或者想要做.本次分享主要分为以下几个部分: WePY 的介绍 WePY 的用户 上面展 ...
- select&epoll
内核空间和用户空间 现在操作系统都是采用虚拟存储器,那么对 32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间)为 4G(2的32次方).也就是说一个进程的最大地址空间为 4G.操作系 ...
- 2018-08-14 中文代码之Spring Boot实现简单REST服务
最终目标详见: 参考MSDN,试搞.NET类库标识符的翻译版 · Issue #54 · program-in-chinese/overview 此文仅为技术探索+原型搭建的第一小步. 源码库: 演示 ...
- Nginx filebeat+logstash+Elasticsearch+kibana实现nginx日志图形化展示
filebeat+logstash+Elasticsearch+kibana实现nginx日志图形化展示 by:授客 QQ:1033553122 测试环境 Win7 64 CentOS-7- ...
- 原型链、闭包四种作用、继承、命名空间、枚举类型(day13)
原型链 JavaScript 对象是动态的属性“包”(指其自己的属性).JavaScript 对象有一个指向一个原型对象的链.当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型, ...
- ubuntu 安装PG10 更新packet 创建超级账号
ubuntu 安装PG10 更新packet 创建超级账号 安装pg10 我的环境是16.04 server版本 MAC和windows 建议使用安装包 直接官网下载 echo 'deb http:/ ...
- Using IntelliJ IDEA as the Vim Editor
转载自https://www.jetbrains.com/help/idea/using-intellij-idea-as-the-vim-editor.html This feature is on ...
- iOS开发创建UI的耗时操作处理
项目中有网络请求.读写操作等一系列耗时操作时,为了避免阻塞主线程,我们会把这些耗时操作放到子线程中去处理,当处理完成后,再回到主线程更新UI,这样就不会阻塞主线程.但是创建UI的时候一般都是在主线程中 ...