Redis服务器是一个事件驱动程序,处理以下两类事件:
- 文件事件:Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,文件事件就是对套接字操作的抽象。
- 时间时间:Redis服务器中的一些操作需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象。
1.文件事件
Redis基于Reactor模式开发了自己的网络事件处理器:称为文件事件处理器
- 文件事件处理器使用I/O多路复用程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
- 当被监听的套接字准备好执行连接应答、读取、写入、关闭等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件
文件事件处理器以单线程方式运行,但是通过I/O多路复用来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,由可以很好的与Redis服务器中其他同样以单线程方式运行的模块进行对接。
1.1 文件事件处理器的构成
1.2 I/O多路复用程序的实现
都是通过包装常见的select、epoll、evport和kqueue这些I/O多路复用函数库实现
1.3 事件的类型
I/O多路复用程序可以监听多个套接字的ae.h/AE_READABLE事件和ae.h/WRITABLE事件,与套接字操作之间的对应关系如下:
- 当套接字变得可读时(客户端对套接字执行write操作,或者执行close操作),或者有新的可应答套接字出现时(客户端对服务器的监听套接字执行connect操作),套接字产生AE_READABLE事件
- 当套接字变得可写时(客户端对套接字执行read操作),套接字产生AE_WRITABLE事件
如果一个套接字同时产生这两种事件,那么文件事件分派器会优先处理AE_READABLE事件,等到AE_READABLE事件处理完成之后,才处理AE_WRITABLE
1.4 API
ae.c/aeCreateFileEvent 函数接受一个套接字描述符、一个事件类型,以及一个事件处理器作为参数,
ae.c/aeDeleteFileEvent 函数接受一个套接字描述符和一个监听事件类型作为参数,取消监听,取消关联。
ae.c/aeGetFileEvents函数接受一个套接字描述符,返回该套接字正在被监听的时间类型。
ae.c/aeWait 函数接受一个套接字描述符,一个事件类型和一个毫秒数为参数,在给定时间内阻塞并等待套接字的给定类型时间产生,
ae.c/aeApiPoll函数接受一个sys/time.h/struct timeval 结构参数,并在指定时间内,阻塞并等待所有被aeCreateFileEvent函数设置为监听状态的套接字产生文件事件,当至少一个时间产生,或者等待超时后,函数返回。
ae.c/aeProcessEvents 函数是文件事件分派器,先调用aeApiPoll函数来等待时间产生,然后遍历所有已产生的事件,并调用响应的事件处理器来处理这些事件。
ae.c/aeGetApiName函数返回I/O多路复用程序底层所使用的I/O多路复用函数库的名称
1.5 文件事件的处理器
1.连接应答处理器
networking.c/acceptTcpHander
2. 命令请求处理器
networking.c/readQueryFromClient
3.命令回复处理器
networking.c/sendReplyToClient
2. 时间事件
- 定时事件
- 周期性事件
一个时间事件主要有以下三个属性组成:
- id
- when 毫秒精度的UNIX时间戳
- timeProc 时间时间处理器
2.1 实现
将所有时间事件都放在一个无序链表中(该链表不按when属性的大小排序)
2.2 API
ae.c/aeCreateTimeEvent 函数接受一个毫秒数milliseconds和一个时间事件处理器proc作为参数,将一个新的时间事件添加到服务器
ae.c/aeDeleteFileEvent 函数接受一个时间事件ID作为参数,然后从服务器中删除该ID所对应的时间事件。
ae.c/aeSearchNearestTimer 函数返回到达时间距离当前时间最接近的那个时间事件。
ae.c/processTimeEvents函数是时间事件的执行器
3.事件的调度与执行
ae.c/aeProcessEvents