- 如果返回值是 AE_NOMORE , 那么这个事件是一个定时事件 , 该事件在达到后删除 , 之后不会再重复 。
- 如果返回值是非 AE_NOMORE 的值 , 那么这个事件为周期性事件 , 当一个时间事件到达后 , 服务器会根据时间处理器的返回值 , 对时间事件的 when 属性进行更新 , 让这个事件在一段时间后再次达到 。
介绍完文件事件和时间事件 , 我们接下来看一下 aeEventLoop 的具体实现 。
创建事件管理器
Redis 服务端在其初始化函数 initServer 中 , 会创建事件管理器 aeEventLoop 对象 。
函数 aeCreateEventLoop 将创建一个事件管理器 , 主要是初始化 aeEventLoop 的各个属性值 , 比如 events 、 fired 、 timeEventHead 和 apidata :
- 首先创建 aeEventLoop 对象 。
- 初始化未就绪文件事件表、就绪文件事件表 。events 指针指向未就绪文件事件表、 fired指针指向就绪文件事件表 。表的内容在后面添加具体事件时进行初变更 。
- 初始化时间事件列表 , 设置 timeEventHead 和 timeEventNextId 属性 。
- 调用 aeApiCreate 函数创建 epoll 实例 , 并初始化 apidata。
aeApiState 对象中 epfd 存储 epoll 的标识 , events 是一个 epoll 就绪事件数组 , 当有 epoll 事件发生时 , 所有发生的 epoll 事件和其描述符将存储在这个数组中 。这个就绪事件数组由应用层开辟空间、内核负责把所有发生的事件填充到该数组 。
创建文件事件
aeFileEvent 是文件事件结构 , 对于每一个具体的事件 , 都有读处理函数和写处理函数等 。Redis 调用 aeCreateFileEvent 函数针对不同的套接字的读写事件注册对应的文件事件 。
比如说 , Redis 进行主从复制时 , 从服务器需要主服务器建立连接 , 它会发起一个 socekt连接 , 然后调用 aeCreateFileEvent 函数针对发起的socket的读写事件注册了对应的事件处理器 , 也就是 syncWithMaster 函数 。
aeCreateFileEvent 的参数 fd 指的是具体的 socket 套接字 , proc 指 fd 产生事件时 , 具体的处理函数 , clientData 则是回调处理函数时需要传入的数据 。aeCreateFileEvent 主要做了三件事情:
- 以 fd 为索引 , 在 events 未就绪事件表中找到对应事件 。
- 调用 aeApiAddEvent 函数 , 该事件注册到具体的底层 I/O 多路复用中 , 本例为epoll 。
- 填充事件的回调、参数、事件类型等参数 。
事件处理
因为 Redis 中同时存在文件事件和时间事件两个事件类型 , 所以服务器必须对这两个事件进行调度 , 决定何时处理文件事件 , 何时处理时间事件 , 以及如何调度它们 。
aeMain 函数以一个无限循环不断地调用 aeProcessEvents 函数来处理所有的事件 。
下面是 aeProcessEvents 的伪代码 , 它会首先计算距离当前时间最近的时间事件 , 以此计算一个超时时间;然后调用 aeApiPoll 函数去等待底层的I/O多路复用事件就绪; aeApiPoll函数返回之后 , 会处理所有已经产生文件事件和已经达到的时间事件 。
与 aeApiAddEvent 类似 , aeApiPoll 也有多套实现 , 它其实就做了两件事情 , 调用 epoll_wait 阻塞等待 epoll 的事件就绪 , 超时时间就是之前根据最快达到时间事件计算而来的超时时间;然后将就绪的 epoll 事件转换到fired就绪事件 。aeApiPoll 就是上文所说的I/O多路复用程序 。具体过程如下图所示 。

文章插图
processFileEvent 是处理就绪文件事件的伪代码 , 也是上文所述的文件事件分派器 , 它其实就是遍历 fired 就绪事件表 , 然后根据对应的事件类型来调用事件中注册的不同处理器 , 读事件调用 rfileProc , 而写事件调用 wfileProc。
推荐阅读
- Redis的链表结构
- 里弗斯谈美国会骚乱:假如是黑人呢 乔治·弗洛伊德事件是怎么回事
- 面试被问:Redis 内存满了怎么办?
- 美国警察暴力致黑人死亡事件始末 美国非裔男子弗洛伊德事件
- Redis为什么会这么快,看完这七点你就知道了
- Redis Sentinel基本实现原理
- 彻底搞懂Redis的线程模型
- Redis不只是缓存,还有n多种你没发现的妙用
- 如何设计秒杀系统?
- 小米Redis的K8s容器化部署实践
