《Redis设计与实现》笔记4
更新日期:
单机数据库实现——事件
Redis服务器是一个事件驱动程序,分为:文件事件和时间事件两大类。
文件事件:执行客户端命令
时间事件:定时调度任务
文件事件
文件事件详述
redis文件事件是单线程的,但是通过io多路复用,监听多个套接字来实现高可用的网络通信模型(这里涉及异步io,系统内核epoll机制。。。。)
文件事件处理器4个组成部分:
尽管多个文件事件可能会并发的出现,单I/O多路复用程序会将套接字放在一个队列中,然后通过队列,以有序、同步、每次一个套接字的方式想文件事件分派器传送套接字。
Redis的I/O多路复用程序所有功能都是通过包装:select、epoll、evport和kqueue这些i/o多路复用函数库来实现的。
Redis为每个I/O多路复用函数库都实现了相同的api,所以I/O多路复用程序的底层实现是可以互换的。
时间事件
时间事件可以分为:定时事件、周期性事件。
ID:递增
when:时间戳
timePro:时间处理函数
一个时间事件是定时事件还是周期性事件,取决于时间事件处理器的返回值:
通过timePro返回值来确定是定时事件还是周期事件。
返回ae.h/AE_NOMORE为定时事件、非ae.h/AE_NOMORE(返回运行周期时间)为周期事件
实现
服务器将所有时间事件都放在一个无序链表中,每当时间事件执行器运行时,会遍历整个链表,查找所有已达到的时间事件,并调用相应的事件处理器。
(对when时间戳无序的,新的id事件总插入表头。)
在目前版本中正常模式下redis服务器只是用serverCron一个时间事件。而在benchmark模式下,服务器也只使用两个时间事件。所以使用无序链表也不会影响性能。
serverCron函数主要工作
- 更新服务器各类统计信息,比如时间、内存占用、数据库占用等
- 清理数据库中的过期键值对
- 关闭和清理链接失败的客户端
- 尝试进行RDB和AOF持久化操作
- 如果服务器是主服务器那么定期对从服务器进行同步
- 如果出于集群模式,对集群进行定期同步和链接测试
服务器默认配置serverCron每秒运行10次,平均每个100毫秒运行一次。redis.conf文件中的hz选项来配置serverCron每秒执行次数
事件调度
服务器中同时存在文件事件和时间事件两种事件类型,所以服务器必须对其进行调度。何时处理文件事件何时处理时间事件,以及花多少时间来处理它们。
- aeApiPoll函数的最大阻塞时间由到达时间最接近当前时间的时间事件决定,这个方法既可以避免服务器对时间事件进行频繁轮训(忙等待),也会确保aeApiPoll函数不会阻塞太长时间。
- 文件事件是随机出现的,所以等待并处理完一次文件事件时,如果没有任何时间事件到达,那么会继续等待处理文件事件,随着文件事件的执行,时间会趋向与下一个时间事件的执行时间,最终来执行时间事件。
- 对文件事件和时间事件都是同步、有序、原子执行的。服务器不会中途中断时间,也不会对事件进行抢占。因此不管是文件处理器还是时间处理器,他们会尽量减少程序阻塞时间,并在需要时让出执行权,降低造成事件饥饿的可能性。
- 因为时间事件在文件事件之后执行,并且事件之间不会出现抢占,所以时间事件的实际处理事件会比设定的事件晚一些。