Redis中的过期键删除策略
Posted 十木禾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis中的过期键删除策略相关的知识,希望对你有一定的参考价值。
我们知道在Redis
数据库中,我们可以为相应的键设置过期时间
那么在相应键的过期时间到了,我们要通过什么方法来回收相应的键呢?
对于上面的问题,我们有以下三种不同的删除策略
定时删除:在设置键过期时间的同时,创建一个定时器,让定时器在过期时间来临的时候,立即删除相应的键。
惰性删除:我们先不管当前键是否过期,在使用的时候检查一下当前键是否已经过期,如果过期就立即删除当前键。
定期删除:系统每隔一定的时间对数据库做一次检查,删除里面的过期键。
注:以上的三种删除策略里面,第一和第三种被称为主动删除策略,第二种被称为被动删除策略。
定时删除
定时删除对于内存是最友好的,通过使用定时器,可以保证过期的键会尽可能快的被删除,并释放其占用的内存。
但是在过期键比较多的情况下,删除过期键可能会占用占用相当一部分的CPU(如果这个时候内存并不是很紧张但是有大量的命令在请求CPU处理),所以说这种策略是对CPU不友好的。
除此之外,创建定时器需要用到Redis
服务器中的时间事件,而当前时间事件的实现方式是无序链表,创建一个事件的时间复杂度为
O(n)
—— 并不能高效的处理大量时间时间。
因此,要让服务器创建大量的定时器从而时间定时删除策略,当前来说还并不现实。(引用自《Redis设计与实现》)
惰性删除
惰性删除对于CPU是最友好的,其只在当前键的时候才会做其过期检查,这可以保证删除过期键的操作只会在非做不可得情况下才会进行,从而使CPU不会在删除其他无关紧要的键上面浪费时间。
非常明显,这种策略对于内存是不友好的。
同时还可能会造成内存泄漏——比如有的键可能永远也不会再使用了,这样子就永远存在内存中不会被释放。而Redis
服务器又是非常依赖内存的,所以这是一个非常不好的结果。
定期删除
上面的两种策咯都有明显的缺点
定时删除:可能会占用大量的CPU时间,影响服务器的响应时间和吞吐量
惰性删除:可能会浪费大量的内存,导致内存泄漏
而定期操作是前面两种策略的一个折中
通过每隔一定的时间删除过期键,并通过限制删除操作的时长和频率来减少对CPU影响(相对定时删除)
定期删除不会导致有的键因为很长时间才会使用或者永不使用(但是已经过期)而带来的内存浪费甚至内存泄漏问题
定期删除策略需要考虑的问题有两个:删除操作执行的时长,删除操作执行的频率
所以说,如果采取定期删除策略的话就需要根据当前项目的情况,合理的设置删除操作的时长和频率,从而使系统的性能达到最优。
那么在Redis
数据库中使用的是哪种删除策略呢?—— 惰性删除和定期删除
惰性删除策略的实现
在Redis
的源码中是使用db.c/expireIfNeed()
函数实现的
/**
* 检查 key 是否已经过期,如果是的话,将它从数据库中删除。
*
* 返回 0 表示键没有过期时间,或者键未过期。
*
* 返回 1 表示键已经因为过期而被删除了。
*/
int expireIfNeeded(redisDb *db, robj *key)
/* 取出键的过期时间 */
mstime_t when = getExpire(db,key);
mstime_t now;
/* 如果没有过期时间 */
if (when < 0) return 0;
/* 服务器loading的时候暂时先不工作 */
if (server.loading) return 0;
/* 获取当前时间*/
now = server.lua_caller ? server.lua_time_start : mstime();
/* 如果当前的是从(Slave)机
* 0 if we think the key should be still valid,
* 1 if we think the key is expired at this time.
* */
if (server.masterhost != NULL) return now > when;
/* 如果未过期,返回 0 */
if (now <= when) return 0;
/* 删除键 */
server.stat_expiredkeys++;
propagateExpire(db,key,server.lazyfree_lazy_expire);
notifyKeyspaceEvent(NOTIFY_EXPIRED,
"expired",key,db->id);
return server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) :
dbSyncDelete(db,key);
命令调用expireIfNeeded()
的过程如图所示
定期删除策略的实现
过期键的定期删除策略由expire.c/activeExpireCycle()
函数实现,每当服务器周期性操作server.c/serverCron
函数执行时,activeExpireCycle()
函数就会被调用,在短时间内,分多次便利服务器中的数据库,从数据库的expires
字典中随机检查一部分键的过期时间,并删除其中的过期键。
以上是关于Redis中的过期键删除策略的主要内容,如果未能解决你的问题,请参考以下文章