我说技术程序员

Redis之key过期定时器实现

2016-05-22  本文已影响3286人  yongsean

用Redis时,有用到EXPIRE、PEXPIRE、SETEX之类命令去设置key的过期时间。从2.8版开始还可以去做简单的定时器服务。
原先也没太具体去了解Redis的过期实现方式,但心中总觉得有块石头没放下,于是乎开3.0的源码去翻看了。
过期策略有3种:立即过期、定时过期、访问过期(惰性过期)。但看了源码后,发现Redis并没采用立即过期的策略,而是采用 定时过期访问过期 混合方式。使用立即过期的话,Linux环境下在Redis进程里会有很多timerfd,在几十万个Key这种数量级开始,对cpu是很大的负担。

redis.h

在redis.h文件里有redisDb结构体

typedef struct redisDb {
  dict *dict;
  dict *expires;
  ......
}

expires这属性是存放当前db有过期时间的键,使用hash数据结构。

定期删除策略

代码在redis.c的activeExpireCycle函数,需要传个type参数,用以区分是用“快速模式”还是“正常模式”。
在“正常模式”下,会遍历每一个编号下的库,然后最多随机获取20个带过期时间的key(20是宏ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP的默认值),倘若key太多则直接return了。接着调用redis.c/activeExpireCycleTryExpire函数尝试去删除它,能删除成功则再发送expired的pub通知给订阅者即可。定期删除的定时时长是100ms。

惰性过期

代码分布在所有读写命令里,如SET、GET、TTL、SADD、HGET...等。每次调用这些命令的实际执行前,都会调用db.c/expireIfNeeded函数来删除过期键,在删除之前,也会发送expired的pub通知。

EXPIRE/PEXPIRE/SETEX的作用?

这几个命令的真正作用是设置过期时间,如EXPIRE命令的处理在db.c/expireCommand开始,然后将过期时间单位从秒转换成毫秒,接着判断是否存在从节点,最后传播删除了的expired key(pub del)。在主节点则设置过期时间,是在宏代码里去设置值(联合体结构),最后在pub expire的通知。

后记

redis是单线程的,但个人觉得在pub方面可以用另一条线程去处理。

上一篇下一篇

猜你喜欢

热点阅读