Redis 事件处理实现
1. Redis事件介绍
Redis
服务器是一个事件驱动程序
。下面先来简单介绍什么是事件驱动。
所谓事件驱动,就是当你输入一条命令并且按下回车,然后消息被组装成Redis
协议的格式发送给Redis
服务器,这就会产生一个事件,Redis
服务器会接收该命令,处理该命令和发送回复,而当你没有与服务器进行交互时,那么服务器就会处于阻塞等待状态,会让出CPU从而进入睡眠状态,当事件触发时,就会被操作系统唤醒。事件驱动使CPU更高效的利用。
事件驱动是一种概括和抽象,也可以称为I/O多路复用(I/O multiplexing),它的实现方式各个系统都不同,一会会说到Redis的方式。
在redis
服务器中,处理了两类事件:
- 文件事件(file event):
Redis
服务器通过套接字于客户端(或其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象。 - 时间事件(time event):Redis服务器的一些操作需要在给定的事件点执行,而时间事件就是服务器对这类定时操作的抽象。
2. 事件的抽象
Redis
将这两个事件分别抽象成一个数据结构来管理。redis 所有源码注释
2.1 文件事件结构
/* File event structure */
typedef struct aeFileEvent {
// 文件时间类型:AE_NONE,AE_READABLE,AE_WRITABLE
int mask; /* one of AE_(READABLE|WRITABLE) */
// 可读处理函数
aeFileProc *rfileProc;
// 可写处理函数
aeFileProc *wfileProc;
// 客户端传入的数据
void *clientData;
} aeFileEvent; //文件事件
其中rfileProc
和wfileProc
成员分别为两个函数指针,他们的原型为
typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
这个函数是回调函数
,如果当前文件事件所指定的事件类型发生时,则会调用对应的回调函数
处理该事件。函数指针与回调函数详解
当事件就绪时,我们需要知道文件事件的文件描述符还有事件类型才能对于锁定该事件,因此定义了aeFiredEvent
结构统一管理:
/* A fired event */
typedef struct aeFiredEvent {
// 就绪事件的文件描述符
int fd;
// 就绪事件类型:AE_NONE,AE_READABLE,AE_WRITABLE
int mask;
} aeFiredEvent; //就绪事件
2.2 时间事件结构
/* Time event structure */
typedef struct aeTimeEvent {
// 时间事件的id
long long id; /* time event identifier. */
// 时间事件到达的时间的秒数
long when_sec; /* seconds */
// 时间事件到达的时间的毫秒数
long when_ms; /* milliseconds */
// 时间事件处理函数
aeTimeProc *timeProc;
// 时间事件终结函数
aeEventFinalizerProc *finalizerProc;
// 客户端传入的数据
void *clientData;
// 指向下一个时间事件
struct aeTimeEvent *next;
} aeTimeEvent; //时间事件
从这个结构中可以看出,时间事件表是一个链表,因为它有一个next
指针域,指向下一个时间事件。
和文件事件一样,当时间事件所指定的事件发生时,也会调用对应的回调函数
,结构成员timeProc
和finalizerProc
都是回调函数,函数原型如下:函数指针与回调函数详解
typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData);
虽然对文件事件和时间事件都做了抽象,Redis
仍然需要对事件做整体抽象,于是定义了aeEventLoop
结构。
2.3 事件状态结构
/* State of an event based program */
typedef struct aeEventLoop {
// 当前已注册的最大的文件描述符
int maxfd; /* highest file descriptor currently registered */
// 文件描述符监听集合的大小
int setsize; /* max number of file descriptors tracked */
// 下一个时间事件的ID
long long timeEventNextId;
// 最后一次执行事件的时间
time_t lastTime; /* Used to detect system clock skew */
// 注册的文件事件表
aeFileEvent *events; /* Registered events */
// 已就绪的文件事件表
aeFiredEvent *fired; /* Fired events */
// 时间事件的头节点指针
aeTimeEvent *timeEventHead;
// 事件处理开关
int stop;
// 多路复用库的事件状态数据