Redis事件详解
文件事件处理器的构成
文件事件是对套接字操作的抽象,每当一个套接字准备好执行 连接应答、写入、读取、关闭等操作时,就会产生一个文件事件。由于一个服务器通常会连接多个套接字,所以多个文件事件可能并发的出现。
I/O多路复用程序负责监听多个套接字,并向文件事件分派器传送那些产生了事件的套接字。
尽管多个文件事件可能会并发地出现,但I/O多路复用程序总是会将所有产生的套接字放到一个队列里,然后文件事件处理器会以有序、同步、单个套接字 的方式处理该队列中的套接字,也就是处理就绪的文件事件。
文件事件
Redis基于Reactor模式开发了自己的网络事件处理器,也就是文件事件处理器。文件事件处理器使用IO多路复用技术,同时监听多个套接字,并为套接字关联不同的事件处理函数。当套接字的可读或者可写事件触发时,就会调用相应的事件处理函数。
Redis的IO多路复用程序的所有功能都是通过包装常见的select、epoll、evport和kqueue这些IO多路复用函数库来实现的,每个IO多路复用程序的底层可以相互替换
事件类型
I/O多路复用可以监听多个套接字的ae.h/AE_READABLE事件和ae.h/AE_WRITABLE事件,这两类事件和套接字操作之间的对应关系如下:
- 当套接字变得可读时(),或者有新的可应答套接字出现时,套接字产生AE_READABLE事件。
- 当套接字变得可写时,套接字产生AE_WRITABLE事件。
I/O多路复用程序允许服务器同时监听套接字的AE_READABLE事件和AE_WRITABLE事件,如果一个套接字同时产生了这两种事件,等到AE_READABLE事件处理完之后,才处理AE_WRITABLE事件。
客户端与服务端一次完成请求
一次Redis客户端进行连接并发送命令的整个过程产生的事件以及如何处理如下:
当Redis服务进行初始化时,会将服务器监听套接字的AE_READABLE事件与连接应答处理器关联起来。
如果此时有一个Redis客户端向服务器发起连接请求,那么监听套接字将产生AE_READABLE事件,触发连接应答处理器的执行。处理器会对客户端的连接请求进行应答,然后创建客户端套接字,以及客户端状态,并将客户端套接字的AE_READABLE事件与命令请求处理器进行关联,使得客户端可以向主服务器发送命令请求。
接着,客户端向主服务器发送一个命令请求,那么客户端套接字将会产生AE_READABLE事件,引发命令请求处理器执行,处理器读取客户端的命令内容,然后传给相关程序去执行。
执行命令会产生相应的命令回复,为了将这些命令回复传送给客户端,服务器会将客户端套接字的AE_WRITABLE事件与命令回复处理器进行关联,当客户端尝试读取命令回复的时候,客户端套接字将会产生AE_WRITABLE事件,触发命令回复处理器执行,当命令回复处理器将命令回复全部写入到套接字之后,服务器就会解除客户端套接字的AE_WRITABLE事件与命令回复处理器之间的联系。
时间事件
Redis事件事件分为以下两类:
- 定时事件:让一段程序在指定的时间之后执行一次,
- 周期性事件:让一段程序每隔指定时间就执行一次
typedef struct aeTimeEvent {
/* 全局唯一ID */
long long id; /* time event identifier. */
/* 秒精确的UNIX时间戳,记录时间事件到达的时间*/
long when_sec; /* seconds */
/* 毫秒精确的UNIX时间戳,记录时间事件到达的时间*/
long when_ms; /* milliseconds */
/* 时间处理器 */
aeTimeProc *timeProc;
/* 事件结束回调函数,析构一些资源*/
aeEventFinalizerProc *finalizerProc;
/* 私有数据 */
void *clientData;
/* 前驱节点 */
struct aeTimeEvent *prev;
/* 后继节点 */
struct aeTimeEvent *next;
} aeTimeEvent;
主要参数介绍:
- id:服务器为时间事件创建的全局唯一ID
- when:UNIX时间戳,记录了时间事件的到达事件
- timeProc:时间事件处理器,一个函数,当时间事件到达时,服务器就会调用相应的处理器来处理事件。
一个时间事件是定时事件还是周期性事件取决于时间事件处理器的返回值: - 如果事件处理器返回ae.h/AE_NOMORE,那么这个事件为定时事件(该事件在达到一次之后就会被删除,之后不再达到)
- 如果事件处理器返回一个非AE_NOMORE的整数值,那么这个事件为周期性事件