Redis中的Key,可以通过 expire 指令进行设置过期时间,如设置key:test的过期时间为10s
jedis.expire("test", 10);
那服务端是如何来存储和处理这个过期时间呢?
过期原理
同样的,来看下 command.c中找到 expire 的处理命令,最终调用到 expireGenericCommand
以下是 setExpire
方法的逻辑
这里有两个地方,需要关注的
- 过期的key会通过db的 expires(也是一个dict类型)字典表来存储
- 过期列表中的 dictEntry,v字段是只使用了 s64这个字段,来存储key的过期时间,因为过期的字典中不存储value的值
那这里呢,已经知道,设置key的过期,如果是设置的过期时间已过,那会直接删除,如果是未来某个时间,那会加入expires 字典中,那这个字典中的数据是什么时候会处理呢?
过期处理
- 周期性事件
在前面的文章中有介绍redis的启动过程,redis服务器启动会通过一个循环来监听事件通知,分为文件事件与时间事件。文件事件通过IO多路复用来处理网络io请求,如socket连接、读写等操作;而时间事件是在主循环中周期性的调用时间函数来处理定时任务,如服务器的维护、key的删除等。
而所有的事件通知都是要提前先注册相应的回调方法,时间事件也不例外,会注册 serverCron方法
在主循环中 aeMain->aeProcessEvents,会检查每个注册的时间事件
serverCron是一个周期性事件(返回值为下次执行的时间间隔),周期与 server.hz的值有关,表示1s内执行的次数,默认为10(可以redis.conf中配置)
其中过期key的处理主要集中在databaseCron ->activeExpireCycle
activeExpireCycle中主要进行如下处理
- 过期key的清理时间不超过cpu时间的25%,当hz=1时,timelimit = 250ms, 当hz = 10时,timelimit=25ms
- 每次清理过期key都会依次遍历所有的库
- 从一个库随机抽取20个key,判断是否过期,如果过期,则会进行失效相应的key
- 当过期的数量占扫描的key的总数的10%时,则会继续扫描,否则遍历下一个库
- 访问时检查
在访问相应的key,也会进行key的过期检查
总结
redis key设置了过期时间后,redis会通过两种方式来删除相应的key
- 通过周期性任务来删除
- 当访问redis key时也会检查相应的key的过期时间
- 认识了server.hz 的作用,可以配置redis服务器中serverCron函数的执行频率