这篇文章主要介绍“redis的过期时间和过期删除机制原理”,在日常操作中,相信很多人在redis的过期时间和过期删除机制原理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”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"OK127.0.0.1:6379> expire message 60(integer) 1127.0.0.1:6379> ttl message(integer) 54127.0.0.1:6379> persist message(integer) 1127.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 shuxinOK127.0.0.1:6379> expire minping 60(integer) 1127.0.0.1:6379> ttl minping(integer) 57127.0.0.1:6379> ttl minping(integer) 27127.0.0.1:6379> pttl minping(integer) 23839127.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的过期时间和过期删除机制原理”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。