Redis学习笔记 - 时间事件、事件的调度与执行

参考:<<Redis设计与实现>>

  • 注:这本书是基于Redis3.0版本写的,和后面的版本有点差异

一、时间事件

Redis的时间事件分为两类:

  • 定时事件:让一段程序在指定的时间之后执行一次。
  • 周期性事件:让一段程序每隔指定时间就执行一次。

一个时间事件主要由以下三个属性组成:

  • id:服务器为时间事件创建的全局唯一ID(标识号)。ID号按从小到大的顺序递增。
  • when:毫秒精度的UNIX时间戳。记录了时间事件到达时间。
  • timeProc:时间处理器,一个函数。当时间事件到达时,服务器就会调用相应的处理器来处理事件。

事件是定时事件还是周期性事件取决于时间事件处理器的返回值:

  • 返回ae.h/AE_NOMORE(-1),则为定时事件:该事件在到达一次之后就会被删除,之后不再到达
  • 返回非AE_NOMORE(-1)的整数值,则为周期性事件:当一个时间事件到达之后,服务器会根据时间处理器返回的值对时间事件的when属性进行更新,让这个事件在一段时间后再次到达,并以这种方式一直更新运行。
    ae.h源码:https://github.com/antirez/redis/blob/3.0/src/ae.h

目前版本的Redis只使用周期性事件,没有使用时间事件。

1.1 实现

服务器将所有时间都放在一个无序列表中,每当时间事件执行器运行时,它遍历整个链表查找所有已到达的时间事件,并调用相应的时间处理器。

无序指的是不按照when属性值进行排序,由于新创建的时间事件是插入到链表的表头,所以链表中时间事件是按照id属性降序排序的。

一个保存了三个时间事件链表的例子:
用链表连接起来的三个时间事件
注:

  • 由于没有按照执行时间进行排序,所以时间事件执行器运行时,它必须遍历链表中的所有时间事件,这样才能确保服务器中所有已到达的时间事件都会被处理。
  • 在当前版本中,正常模式下只有一个serverCron时间事件,在benchmark模式下也只是使用了两个时间事件。这种情况下,使用无序链表并不影响事件的执行性能。
1.2 涉及的函数(ae.c源码中
  • aeCreateTimeEvent():添加新的时间事件至服务器,接收milliseconds(毫秒数)和proc(处理器)等参数。新的事件将在当前时间的milliseconds毫秒后到达,事件处理器是proc。
  • aeDeleteFileEvent():从服务器删除指定ID对应的时间事件
  • aeSearchNearestTimer():返回到达时间距离当前时间最近的时间事件。
  • processTimeEvents():时间事件的执行器。这个函数会遍历所有时间事件,并调用事件处理器来处理那些已到达的时间事件。
    已经到达:时间事件的when属性记录的UNIX时间戳小于等于当前时间。

1.3 时间事件的应用实例:serverCron函数

持续运行的Redis服务器需要定期对自身的资源和状态进行检查和调整,确保服务器可以长期、稳定地运行。这些操作由redis.c/serverCron函数负责执行,该函数主要工作如下:

  • 更新服务器的各类统计信息,如时间、内存占用、数据库占用情况等
  • 清理数据库中的过期键值对
  • 关闭和清理连接失效的客户端
  • 尝试进行AOF或RDB持久化操作
  • 如果服务器是主服务器,那么对从服务器进行定期同步
  • 如果处于集群模式,对集群进行定期执行同步和连接测试

Redis服务器一周期性事件方式运行该函数,直到服务器关闭。

在redis.conf中可以配置hz选项调整serverCron函数每秒执行次数

  • 默认配置值是10,取值范围是1-500。
  • 官方不建议将值设置大于等于100,因为当redis空闲时会占用更多CPU。除非在某些环境中,你需要一个非常低的延迟,可以将它设置为100

二、事件的调度与执行

服务器中同时存在文件事件和时间事件,所以服务器需要对这两种事件进行调度,决定何时该处理文件事件、何时又该处理时间事件,以及花多长时间执行等。

事件调度与执行流程如下:

  • 根据最近的时间事件判断是否阻塞并等待文件事件产生,如果时间事件已经到达或有文件事件产生,那么不阻塞;否则阻塞,阻塞最大时间由时间事件距离当前时间决定
  • 处理所有已经产生的文件事件
  • 处理所有已经到达的时间事件
  • 开始新的循环

上述流程如下图所示:
事件处理流程
注:

  • 最大阻塞时间由最近的时间事件决定,这样可以避免服务器对时间事件进行频繁轮询,也可以确保阻塞过长时间
  • 文件事件是随机出现的,如果等待处理完一次文件事件后仍没有时间事件到达,那么服务器会再次等待处理文件事件。直到有时间事件,服务器再处理。
  • 对文件事件、时间事件都是同步、有序、原子地执行的,服务器不会中途中断、抢占。因此,不管是文件事件还是时间事件的处理,都会尽可能的减少程序的阻塞时间,在有需要的时候让出执行权,降低事件饥饿的可能性。
    • 如在命令回复处理器将一个命令回复写入到客户端套接字时,如果写入字节数超过了一个预设常量,命令回复处理器就会主动跳出写入循环,将余下的数据下次再写
    • 时间事件会将非常耗时的持久化操作放到子线程或子进程中执行
  • 时间事件在文件事件后执行,由于事件之间不会出现抢占,所以时间事件的实际处理事件通常会比设定的时间晚一点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值