概述
Redis 的文件事件处理器是基于 Reactor 模式实现的,内部采用 IO 多路复用程序来同时监听多个套接字,当被监听的套接字准备好执行连接应答(accept)
、读取(read)
、写入(write)
、关闭(close)
等操作时,与操作相对应的文件事件就会产生,此时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
核心组件
文件事件处理器主要由以下4个核心组件构成:
- 套接字(Sockets):服务器与客户端之间的通信端点;
- I/O 多路复用程序:负责同时监听多个套接字,并在套接字准备好执行操作时通知文件事件分派器;
- 文件事件分派器(Dispatcher):接收 I/O 多路复用程序传来的事件,并根据事件类型调用相应的事件处理器;
- 事件处理器:定义了在特定事件发生时,服务器应该执行的动作。
IO多路复用程序
Redis 的 IO 多路复用程序是通过包装常见的select
、epoll
、evport
和 kqueue
这些 I/O 多路复用函数库来实现的, 每个 I/O 多路复用函数库在 Redis 源码中都对应一个单独的文件。
因为Redis 为每个 I/O 多路复用函数库都实现了相同的 API , 所以 I/O 多路复用程序的底层实现是可以互换的。
事件类型
在 Redis 中,文件事件主要分为两大类:
-
当套接字变得可读时(客户端对套接字执行 write 操作 或 close 操作),或者有新的可应答(acceptable)套接字出现时(客户端对服务器的监听套接字执行 connect 操作),套接字将产生
AE_READABLE
事件; -
当套接字变得可写时(客户端对套接字执行 read 操作),套接字将产生
AE_WRITEABLE
事件。
事件处理器
为了实现不同的网络通信需求,Redis 为文件事件编写了多个处理器。
连接应答处理器
当 Redis 服务器初始化时,会将连接应答处理器与服务器监听套接字的AE_WRITEABLE
事件关联起来;
当客户端用 connect 函数连接到服务器时,服务器的监听套接字会产生 AE_READABLE
事件;
此时,连接应答处理器会被触发,它负责接受客户端的连接请求,并创建客户端套接字。随后,服务器会将客户端套接字的 AE_READABLE
事件与命令请求处理器关联,以便接收客户端发送的命令请求。
命令请求处理器
当客户端向服务器发送命令请求时,客户端套接字会产生AE_READABLE
事件,引发命令请求处理器执行,并执行相应的套接字读入操作;
命令回复处理器
当服务器准备好回复数据给客户端时,它会将客户端套接字的 AE_WRITABLE
事件与命令回复处理器关联。当客户端准备好接收数据时,套接字会产生 AE_WRITABLE
事件,触发命令回复处理器执行,将命令回复写入套接字。
当命令回复发送完毕后,服务器就会解除命令回复处理器与客户端套接字的AE_WRITABLE
事件的关联。
完整的连接示例
- 假设一个 redis 服务器正在运行,那么服务器监听套接字的
AE_READABLE
事件就处于监听状态下,并与连接应答处理器关联; - 此时有一个客户端向服务器发起连接,服务器监听套接字将产生
AE_READABLE
事件,触发连接应答处理器执行,对客户端的连接请求进行应答;然后会创建客户端套接字,并将客户端套接字的AE_READABLE
事件与命令请求处理器关联; - 客户端向服务器发送命令请求,客户端套接字将产生
AE_READABLE
事件,触发命令请求处理器执行,处理器读取客户端的命令,传给相关程序去执行; - 服务器将客户端套接字的
AE_WRITABLE
事件与命令回复处理器关联,当客户端尝试读取命令回复时,客户端套接字将产生AE_WRITABLE
事件,触发命令回复处理器执行,当命令回复处理器将命令回复全部写入到套接字后,服务器就会解除客户端套接字的AE_WRITABLE
事件与命令回复处理器之间的关联。
总结
Redis 的文件事件处理器是其高性能网络通信的核心。通过单线程的事件驱动模型,Redis 能够有效地处理大量的并发连接和请求,同时保持了代码的简洁性和可维护性。
参考资料
《redis 设计与实现》