Redis源码事件循环深挖,带你一步步理解底层循环机制和运行原理
- 问答
- 2026-01-10 08:54:35
- 3
要理解Redis为什么这么快,除了众所周知的内存存储和高效数据结构,其核心——事件循环机制——绝对是重中之重,这个机制就像是Redis的心脏,一刻不停地跳动,处理着成千上万的网络请求,我们今天就直接钻进Redis的源码里,看看这颗“心脏”是怎么工作的,主要参考的是Redis源码中的ae.c文件,这是事件循环的实现核心。
事件循环的“启动器”:main函数里的秘密
一切始于server.c文件中的main函数,当你启动Redis服务器,main函数会做一系列初始化工作,比如配置加载、数据结构初始化等,其中最关键的一步就是创建事件循环器,它会调用aeCreateEventLoop函数(定义在ae.c中)来创建一个aeEventLoop结构体,这个结构体是整个事件循环的“大脑”,它内部维护着几个关键成员:
events:一个数组,记录了所有被监听的事件(比如读事件、写事件)以及对应的处理函数。fired:一个数组,记录着本次事件循环中“已经发生”的事件。- 底层使用的多路复用API(如epoll、kqueue、select)的状态数据。
Redis会根据操作系统自动选择最高效的多路复用机制,在Linux上默认就是epoll,创建好事件循环器后,main函数就开始为服务器socket注册事件了。
注册“倾听者”:让事件循环知道该关心什么
服务器启动后,需要监听一个端口(比如6379)来等待客户端连接,这个过程就是通过事件循环注册事件实现的。main函数会调用aeCreateFileEvent函数(在ae.c中),告诉事件循环器:“请帮我监听服务器socket的AE_READABLE事件(即可读事件,表示有新的连接到来),当这个事件发生时,请调用acceptTcpHandler这个函数来处理。”
这个过程就像是给事件循环这个“门卫”下达指令:“注意大门口(服务器socket),一旦有人想进来(连接请求),就立刻叫我(调用处理函数)。” 同样地,当某个客户端连接成功,需要读取它发送的命令时,Redis也会为这个客户端连接注册一个AE_READABLE事件,并绑定命令请求处理器readQueryFromClient。

核心循环:aeMain 与 aeProcessEvents
初始化完毕,main函数最后会调用aeMain函数(在ae.c中),事件循环就正式开跑了!aeMain函数非常简单,就是一个大大的while循环,只要服务器不关闭,这个循环就会一直执行下去。
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}
可以看到,循环体内部一次又一次地调用aeProcessEvents函数,这个函数是事件循环最核心、最繁忙的部分,它每一次调用,我们称之为一次“事件循环滴答”(tick),它主要干了三件事:
-
寻找最近要发生的定时事件: Redis除了处理网络I/O,还要处理一些定时任务,比如清理过期键、更新统计信息等,这些任务被封装成“定时事件”。
aeProcessEvents会先检查所有定时事件,找出距离当前时间最近的那一个,计算出一个“等待超时时间”,这个设计很巧妙,它保证了事件循环既不会空转浪费CPU,又能准时执行定时任务,如果没有定时事件,它可能会一直阻塞等待I/O事件发生。
-
等待事件发生: 这是最“省力”的一步,函数会调用底层的多路复用API(如epoll_wait),并传入上一步计算出的超时时间,线程会在这里休眠,直到以下两种情况之一发生:
- 有网络I/O事件就绪:比如有新的连接到来,或者某个客户端发送了数据。
- 等待超时:即超过了定时事件设定的时间,这时需要去执行定时任务了。
-
处理就绪事件: 一旦被唤醒,
aeProcessEvents就知道有活干了,它会从多路复用API中获取所有“就绪”的事件列表,并把这些事件放入aeEventLoop的fired数组中,它会遍历这个fired数组,根据每个事件的类型(读/写),从events数组中找出第一步注册时绑定的那个处理函数,并执行它。- 如果是服务器socket的读事件,就执行
acceptTcpHandler,接受连接,创建新的客户端对象。 - 如果是客户端socket的读事件,就执行
readQueryFromClient,读取命令、解析命令、最终执行命令。 - 如果某个命令的回复数据很大,无法一次性写入socket,Redis会为这个客户端注册一个
AE_WRITABLE事件,并绑定相应的回复处理器,当网络可写时,事件循环就会触发这个写处理器,继续发送剩余的数据。
- 如果是服务器socket的读事件,就执行
事件循环的本质:一个高效的总指挥官
Redis的事件循环机制本质上是一个单线程的、基于事件驱动的、非阻塞I/O的模型。
- 单线程:指的是处理网络I/O和命令执行的核心逻辑只有一个线程,这避免了多线程的锁竞争,简化了实现。
- 事件驱动:它的工作不是主动去轮询成千上万的连接,而是“被动”等待事件发生,然后做出反应,这就像是一个总指挥官,他不会不停地问每个士兵“有情况吗?”,而是让士兵(操作系统内核)在有事的时候主动报告。
- 非阻塞I/O:所有socket都被设置为非阻塞模式,这意味着当
read或write调用不能立即完成时,函数会立刻返回一个错误码(如EAGAIN),而不会让线程傻等,事件循环则通过epoll等机制来监控这些socket何时再次可读或可写,从而在最佳时机进行操作。
通过深入ae.c源码,我们看到Redis如何通过一个精巧的循环,将网络I/O、命令处理、定时任务完美地整合在一起,以极高的效率处理海量并发,这正是Redis高性能的基石所在。
本文由黎家于2026-01-10发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/77967.html
