1.概述
Redis
没有使用第三方的libevent等网络库,而是基于Reactor模式
自己开发了一个单线程的Reactor模型的事件处理模型。
称为文件事件处理器,其使用I/O多路复用,同时监听多个套接字,根据套接字执行的任务来为套接字关联不同的事件处理器。
Redis在主循环中统一处理文件事件和时间事件,信号事件则由专门的handler来处理。
2.实现
分为四个部分:套接字、I/O多路复用程序、文件事件派发器、事件处理器。
I/O多路复用程序会监听多个套接字,并将所有产生事件的套接字放到一个队列中,通过队列,每次一个套接字的方式向文件事件派发器传送套接字,相应的有事件处理器处理这些套接字。
当该套接字为事件所关联的事件处理器处理完毕之后,I/O多路复用程序才会继续向文件事件派发器传送下一个套接字。
图片参考:https://www.cnblogs.com/harvyxu/p/7499396.html
2.1 服务启动过程:
2.1.1 启动redisServer(redis.c/main),在main主线程中initServer:
int main(int argc, char **argv) {
// 初始化服务器
initServerConfig();
// 如果服务器以 Sentinel 模式启动,那么进行 Sentinel 功能相关的初始化
// 并为要监视的主服务器创建一些相应的数据结构
if (server.sentinel_mode) {
initSentinelConfig();
initSentinel();
}
// 创建并初始化服务器数据结构
initServer();
// 省略加载rdb、aof文件等过程
// 运行事件处理器,一直到服务器关闭为止
aeSetBeforeSleepProc(server.el,beforeSleep);
aeMain(server.el);
// 服务器关闭,停止事件循环
aeDeleteEventLoop(server.el);
}
2.1.2 在redis.c/initServer中,初始化eventloop,并注册文件描述符事件和相关handler事件处理器:
// 初始化EventLoop
server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
/* Create the serverCron() time event, that's our main way to process
* background operations. */
// 为 serverCron() 创建时间事件
if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
redisPanic("Can't create the serverCron time event.");
exit(1);
}
/* Create an event handler for accepting new connections in TCP and Unix
* domain sockets. */
// 为 TCP 连接关联连接应答(accept)处理器
// 用于接受并应答客户端的 connect() 调用
for (j = 0; j < server.ipfd_count; j++) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR)
{
redis