Redis 事件

Redis 事件

Redis 服务器是一个事件驱动程序,服务器需要处理两类事件:

  • 文件事件(file event) - Redis 服务器通过套接字(Socket)与客户端或者其它服务器进行通信,文件事件就是对套接字操作的抽象。服务器与客户端(或其他的服务器)的通信会产生文件事件,而服务器通过监听并处理这些事件来完成一系列网络通信操作。
  • 时间事件(time event) - Redis 服务器有一些操作需要在给定的时间点执行,时间事件是对这类定时操作的抽象。

关键词:文件事件时间事件

文件事件

Redis 基于 Reactor 模式开发了自己的网络时间处理器。

  • Redis 文件事件处理器使用 I/O 多路复用程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
  • 当被监听的套接字准备好执行连接应答、读取、写入、关闭操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。

虽然文件事件处理器以单线程方式运行,但通过使用 I/O 多路复用程序来监听多个套接字,文件事件处理器实现了高性能的网络通信模型。

文件事件处理器有四个组成部分:套接字、I/O 多路复用程序、文件事件分派器、事件处理器。

img

时间事件

时间事件又分为:

  • 定时事件:是让一段程序在指定的时间之内执行一次;
  • 周期性事件:是让一段程序每隔指定时间就执行一次。

Redis 将所有时间事件都放在一个无序链表中,每当时间事件执行器运行时,通过遍历整个链表查找出已到达的时间事件,并调用响应的事件处理器。

事件的调度与执行

服务器需要不断监听文件事件的套接字才能得到待处理的文件事件,但是不能一直监听,否则时间事件无法在规定的时间内执行,因此监听时间应该根据距离现在最近的时间事件来决定。

事件调度与执行由 aeProcessEvents 函数负责,伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def aeProcessEvents():

## 获取到达时间离当前时间最接近的时间事件
time_event = aeSearchNearestTimer()

## 计算最接近的时间事件距离到达还有多少毫秒
remaind_ms = time_event.when - unix_ts_now()

## 如果事件已到达,那么 remaind_ms 的值可能为负数,将它设为 0
if remaind_ms < 0:
remaind_ms = 0

## 根据 remaind_ms 的值,创建 timeval
timeval = create_timeval_with_ms(remaind_ms)

## 阻塞并等待文件事件产生,最大阻塞时间由传入的 timeval 决定
aeApiPoll(timeval)

## 处理所有已产生的文件事件
procesFileEvents()

## 处理所有已到达的时间事件
processTimeEvents()

将 aeProcessEvents 函数置于一个循环里面,加上初始化和清理函数,就构成了 Redis 服务器的主函数,伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
def main():

## 初始化服务器
init_server()

## 一直处理事件,直到服务器关闭为止
while server_is_not_shutdown():
aeProcessEvents()

## 服务器关闭,执行清理操作
clean_server()

从事件处理的角度来看,服务器运行流程如下:

参考资料