Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器(file event handler)。它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。

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

虽然文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性。

Redis的线程模型 IO多路复用

redis 是基于 reactor 模式开发的网络事件处理器, 这个处理器叫做文件事件处理器, file event handler. 这个文件事件处理器是单线程的, 所以 redis 才叫单线程模型, 采用 IO 多路复用技术同时监听多个 socket, 根据 socket 上的事件来选择对应的事件处理器来处理事件.

image.png

①. 在 Redis 启动及初始化的时候, Redis 会 (预先) 将连接应答处理器跟 “AE_READABLE”事件关联起来, 接着如果一个客户端向 Redis 发起连接, 此时就会产生一个”AE_READABLE”事件, 然后由连接应答处理器来处理跟客户端建立连接, 创建客户端对应的 socket, 同时将这个 socket 的”AE_READABLE” 事件跟命令请求处理器关联起来;

②. 当客户端向 Redis 发起请求的时候 (不管是读请求还是写请求, 都一样), 首先就会在之前创建的客户端对应的 socket 上产生一个 “AE_READABLE”事件, 然后 IO 多路复用程序会监听到在之前创建的客户端对应的 socket 上产生了一个”AE_READABLE”事件, 接着把这个 socket 放入一个队列中排队, 然后由文件事件分派器从队列中获取 socket 交给对应的命令请求处理器来处理 (因为之前在 Redis 启动并进行初始化的时候就已经预先将”AE_READABLE” 事件跟命令请求处理器关联起来了). 之后命令请求处理器就会从之前创建的客户端对应的 socket 中读取请求相关的数据, 然后在自己的内存中进行执行和处理;

③. 当客户端请求处理完成, Redis 这边也准备好了给客户端的响应数据之后, 就会 (预先) 将 socket 的 “AE_WRITABLE”事件跟命令回复处理器关联起来, 当客户端这边准备好读取响应数据时, 就会在之前创建的客户端对应的 socket 上产生一个”AE_WRITABLE”事件, 然后 IO 多路复用程序会监听到在之前创建的客户端对应的 socket 上产生了一个”AE_WRITABLE”事件, 接着把这个 socket 放入一个队列中排队, 然后由文件事件分派器从队列中获取 socket 交给对应的命令回复处理器来处理 (因为之前在 Redis 这边准备好给客户端的响应数据之后就已经预先将”AE_WRITABLE” 事件跟命令回复处理器关联起来了), 之后命令回复处理器就会向之前创建的客户端对应的 socket 输出 / 写入准备好的响应数据, 最终返回给客户端, 供客户端来读取;

④. 当命令回复处理器将准备好的响应数据写完之后, 就会删除之前创建的客户端对应的 socket 上的 “AE_WRITABLE” 事件和命令回复处理器的关联关系;