Redis有很多需要周期性执行的任务:
- 统计内存使用最高值,
- 记录数据库的使用情况,
- 对哈希表进行resize(如果哈希表的使用率小于10%时,需要对哈希表进行压缩),
- 检查客户端连接是否超时,
- 保存数据库到磁盘,
- 检查key是否过期并删除,
- 主备数据同步
- 删除异步关闭的客户端;
- 运行集群定时任务;
- 运行定时监视任务;
- . . .
这些周期性任务是由REDIS自己来维护定时器机制的,这些任务都在
serverCron中执行,serverCron定时任务在系统启动时创建,最开始的创建时的定时时间是1毫秒;后续的执行周期是10毫秒,相当于Redis创建了自己的tick任务,这个定时任务每次执行完后不会从定时任务队列中删除,而是每次都增加10毫秒,最为下次执行的定时器。上面的定时任务执行都是在10毫秒的基础上定时处理自己的任务(
run_with_period(_ms_)),即调用run_with_period(_ms_)[
_ms_是指多长时间执行一次,单位是毫秒]来确定自己是否需要执行。如定时主备同步需要每秒执行一次:
run_with_period(1000) replicationCron();
在redis中定时器是由一个链表来
aeEventLoop->timeEventHead,redis并没有对链表进行排序,而是遍历这个链表来比较时间来决定是否需要执行相应的定时器;这个设计对redis来说是在性能上是没有影响的,因为redis服务器上只有一个定时任务
serverCron,其他的周期执行任务都是在
serverCron里面运行的。[在libevent中是用最小堆来对定时任务进行了排序]。
定时任务执行完后会返回一个值来决定这个定时任务下次在多长时间后执行,如果返回值是
AE_NOMORE (#define AE_NOMORE -1),那么这个定时任务将从队列中删除,其他值表示将在将在返回值的时间后继续执行这个定时任务(单位是毫秒,
serverCron返回的是10毫秒);
redis的定时器的到时机制和libevent是相同的,都是利用IO接口的等待时间来触发的,在linux中用epoll_wait来实现的,即将定时器将要到期的最小时间最为epoll_wait的最大等待时间,在这时间之后没有收到IO的任务就触发定时任务。