如何理解Redis是单线程的?
单线程指的是Redis的网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,网络请求模块之外的其他模块仍用了多个线程。
单线程的Redis为何那么快?
(1) 绝大部分请求是纯粹的内存操作(非常快速)
(2) 采用单线程,避免了不必要的上下文切换和竞争条件
(3) 非阻塞IO —— IO多路复用,Redis采用epoll做为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接,读写,关闭都转换为了事件,不会在I/O上浪费过多的时间。
Redis处理流程分析简易版
Redis分客户端和服务端,一次完整的Redis请求事件有多个阶段(客户端到服务器的网络连接-->Redis读写事件发生-->Redis服务端的数据处理(单线程)-->数据返回)。平时所说的Redis单线程模型,本质上指的是服务端的数据处理阶段,不牵扯网络连接和数据返回,这是理解Redis单线程的第一步。
首先,客户端和服务器是socket通信方式,socket服务端监听可同时接受多个客户端请求,这点很重要,如果不理解可先记住。注意这里可以理解为本质上与Redis无关,这里仅仅做网络连接,或者可以理解为,为Redis服务端提供网络交互API。
首先确定一点,Redis的客户端与服务器端通信是基于TCP连接,第一阶段仅仅是建立了客户端到服务器的网络连接,然后才是发生第二阶段的读写事件。
完成了上一个阶段的网络连接,Redis客户端开始真正向服务器发起读写事件,假设是set(写)事件,此时Redis客户端开始向建立的网络流中发送数据,服务端接收客户端的请求数据。
服务端完成了第二阶段的数据接收,接下来开始依据接收到的数据做逻辑处理,然后得到处理后的数据。数据处理可以理解为一次方法调用,最终得到方法返回值。
当Redis服务端数据处理完后就会立即返回处理后的数据。
Redis内部实现?
什么文件事件处理器?
Redis单线程模型中最为核心的就是文件事件处理器。文件事件处理器结构包含5个部分,其实真正包含为4个部分(不包含socket队列,加上主要方便后面理解):多个socket、IO多路复用程序、socket队列、文件事件分派器和事件处理器。而事件处理器又分为3个部分为:连接应答处理器、命令请求处理器、命令回复处理器。如图(逻辑概念):
I/O 多路复用程序(I/O Multiplexing Module)会把消息放入队列中,然后通过文件事件分派器(Fileevent Dispatcher),转发到不同的事件处理器中。上图将I/O 多路复用程序与socket队列分开便于理解,真实的I/O 多路复用程序如下图所示。
什么是IO多路复用?
有多个客户连接,sockfd1,sockfd2,sockfd3..sockfdn,服务的同时监听这n个客户,当其中有一个发来消息时就从阻塞中返回,然后就调用read读取收到消息的sockfd,然后又循环回阻塞;这样就不会因为阻塞在其中一个上而不能处理另一个客户的消息
Redis单线程模型的工作流程
1、首先在Redis启动初始化的时候,Redis会先将事件处理器中的连接应答处理器和AE_READABLE事件关联起来;
2、如果客户端向Redis发起连接,会产生AE_READABLE事件(步骤A),产生该事件后会被IO多路复用程序监听到(步骤B),然后IO多路复用程序会把监听到的socket信息放入到队列中(步骤C),事件分配器每次从队列中取出一个socket(步骤D),然后事件分派器把socket给对应的事件处理器(步骤E)。由于连接应答处理器和AE_READABLE事件在Redis初始化的时候已经关联起来,所以由连接应答处理器来处理跟客户端建立连接,然后通过ServerSocket创建一个与客户端一对一对应的socket,如叫socket01,同时将这个socket01的AE_READABLE事件和命令请求处理器关联起来。
3、当客户端向Redis发生请求时(读、写操作),首先就会在对应的socket如socket01上会产生AE_READABLE事件(步骤A),产生该事件后会被IO多路复用程序监听到(步骤B),然后IO多路复用程序会把监听到的socket信息放入到队列中(步骤C),事件分配器每次从队列中取出一个socket(步骤D),然后事件分派器把socket给对应的事件处理器(步骤E)。由于命令处理器和socket01的AE_READABLE事件关联起来了,然后对应的命令请求处理器来处理。这个命令请求处理器会从事件分配器传递过来的socket01上读取相关的数据,执行相应的读写处理。操作执行完之后,Redis就会准备好相应的响应数据(如你在Redis客户端输入命令:set a 123,回车后看到的响应结果:ok),并将socket01的AE_WRITABLE事件和命令回复处理器关联起来。
4、当客户端查询Redis是否完成相应的操作,就会在socket01上产生一个AE_WRITABLE事件,会由对应的命令回复处理器来处理,就是将准备好的响应结果数据写入socket01(由于socket连接是双向的),返回给客户端,如读操作,客户端会显示ok。
5、如果命令回复处理器执行完成后,就会删除这个socket01的AE_WRITABLE事件和命令回复处理器的关联。
6、这样客户端就和Redis进行了一次通信。由于连接应答处理器执行一次就够了,如果客户端再次进行操作就会由命令请求处理器来处理,反复执行。