目录
Redis 的线程模型其实是分两块的:
-
Redis 6.0 之前的单线程模型。其实从 4.0 开始,Redis 并不是严格意义上的单线程模型,因为 Redis 除了主线程外,也有一些后台的线程或者子进程在处理任务(例如清理脏数据、生成快照、AOF 重写),这个时候大家所说的单线程应该是 Redis 的主线程模型。
-
Redis 6.0 之后的多线程模型。Redis 在 6.0 之后引入了一种多线程模型,用于处理网络 I/O 的任务。
所以,你的回答要涉及这两个方面。
-
Redis 的单线程是指Redis 在执行一次命令时是单线程的。其过程包括「接收客户端请求 -> 解析请求 ->数据读写等操作->返回结果给客户端」,这个过程是由一个主线程来完成的,这也是我们常说 Redis 是单线程的原因。Redis 的模型是基于单线程事件驱动模型,内部使用文件事件处理器,而这个文件事件处理是单线程的,也就决定了 Redis 是单线程的。其核心原理是:采用 IO多路复用机制同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。
-
随着底层网络硬件越来越好,Redis 的性能瓶颈逐渐体现在网络 I/O 的读写上,单个线程处理网络 I/O 读写的速度跟不上底层网络硬件执行的速度。所以为了提高 Redis 的性能,在 Redis 6.0 引入多线程模型,该多线程模型只用来处理网络数据的读写和协议解析,执行读写命令的仍然是单线程。
Redis的线程模型是其高性能和高效率的关键所在。以下是对Redis线程模型的详细解释:
一、Redis线程模型概述
Redis基于Reactor模式开发了自己的网络事件处理器,即文件事件处理器(file event handler,FEH)。该处理器是单线程模式运行的,因此Redis的线程模型也被称为单线程模型。但Redis通过IO多路复用机制监听多个socket,可以实现高性能的网络通信模型,同时又能与内部其他单线程的模块进行对接,保证了Redis内部线程模型的简单性。
二、Redis线程模型的核心组件
- 多个socket:文件事件是对socket操作的抽象,每当一个socket准备好执行连接accept、read、write、close等操作时,与操作相对应的文件事件就会产生。多个socket可能会并发产生不同的操作,每个操作又会生成对应的文件事件。
- IO多路复用程序:负责各事件的监听(连接、读、写等),当有事件发生时,将对应事件放入队列中。
- 文件事件分派器:负责接受IO多路复用程序传递过来的文件事件,并根据文件事件关联的事件处理器,将该事件分派给对应的事件处理器去处理。
- 事件处理器:包括连接应答处理器、命令请求处理器和命令回复处理器。连接应答处理器负责客户端的接入操作;命令请求处理器负责处理客户端发送的读、写等请求命令;命令回复处理器负责将执行的结果返回给客户端。
三、Redis线程模型的工作流程
- 在Redis启动初始化时,IO多路复用程序会监听serverSocket,并且将事件处理器中的连接应答处理器和AE_READABLE事件关联起来。
- 当客户端跟Redis发起连接时,serverSocket会产生一个AE_READABLE事件,然后被IO多路复用程序监听到后传递给文件事件分派器。
- 文件事件分派器再分配给Redis初始化时与AE_READABLE事件关联的连接应答处理器去处理。
- 连接应答处理器完成与客户端的连接后,会创建一个与客户端一一对应的socket,同时将这个socket的AE_READABLE事件跟命令请求处理器关联起来,后续该客户端的所有请求都是在这个socket上进行操作。
- 当客户端发送一个请求命令到对应的socket时,socket会产生一个AE_READABLE(读事件)事件。IO多路复用程序监听到socket产生的AE_READABLE事件后,将该事件放入到socket队列中。
- 文件事件分派器读取socket队列中的事件,将该socket中的命令交给与该事件关联的命令请求处理器去处理。
- 命令请求处理器读取socket中的请求命令并执行完该命令后,会准备好需要返回给客户端的数据,并将socket的AE_WRITABLE事件和命令回复处理器关联起来。
- 当客户端准备接收Redis返回的数据时,会产生一个AE_WRITABLE事件,该事件被IO多路复用程序监听到后放入socket队列中,再由文件事件分派器分配给该事件关联的命令回复处理器去处理。
- 命令回复处理器将待返回到客户端的数据写入到socket中,写入完成之后会删除这个socket的AE_WRITABLE事件和命令回复处理器的关联。
- socket最终将命令处理的结果返回到客户端,完成一次命令的执行流程。
四、Redis线程模型的优势与局限性
优势
- 模型简单:所有的处理过程都在一个线程中完成,避免多线程同步机制的开销。
- 避免上下文切换:只用一个主线程来处理,可以有效地避免多线程上下文切换带来的损耗。
- 实现容易:单线程模型实现上比较容易,可维护性强。
局限性
- CPU多核利用不足:只有一个线程,连接处理和业务处理共用一个线程,无法充分利用CPU多核的优势。
- 性能瓶颈:当流量比较大、读写事件比较耗时情况下,容易导致系统出现性能瓶颈。
五、Redis线程模型的优化与发展
- Redis 4.0之前的优化:通过异步删除(如UNLINK命令)和Lazy-Free机制来减少大对象删除时对主线程的阻塞。
- Redis 6.0的引入多线程:为了充分利用服务器CPU的多核资源,Redis 6.0版本引入了多线程来处理网络IO的读写操作。但需要注意的是,Redis 6.0的多线程只针对网络IO的读写部分,而命令的执行仍然是在主线程中完成的。多线程的引入可以分摊Redis同步IO读写负荷,降低耗时,提高整体效率。
综上所述,Redis的线程模型是基于Reactor模式的单线程模型,通过IO多路复用机制实现高性能的网络通信。虽然单线程模型在某些方面存在局限性,但Redis通过一系列优化策略和多线程的支持,不断提升其性能和效率。
参考: