Redis是单线程的,为什么还这么快,很大的原因就是redis采用的是IO多路复用程序,让我们一起来看下Redis的线程模型。
概念
Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为:文件事件处理器。
先看几个关键词:嵌套字,I/O多路复用程序,文件事件分派器,文件事件处理器。
redis会通过I/O多路复用程序,监听每个嵌套字,并根据套接字当前执行的任务,为套接字关联上对应的事件处理器。
当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件
关系图如下
I/O多路复用程序的实现
Redis的I/O多路复用程序的所有功能是通过包装select、epoll、evport和kqueue这些I/O多路复用函数库来实现的,每个I/O多路复用函数库在Redis源码中都对应一个单独的文件,比如ae_select.c、ae_epoll.c、ae_kqueue.c等。
文件事件分派器
I/O多路复用程序,将套接字推到一个队列里面,以有序,同步的方式推给文件事件分派器,只有当前套接字为事件关联的事件处理器被执行完,IO多路复用程序才会继续给文件事件分派器推下一个套接字,这也是redis是单线程的原因。
客户端每次调用redis时都会经历三个阶段:
发送命令,执行命令,返回结果。
如图:
具体的流程和工作原理如下:
一,客户端连redis
①redis在启动初始化的时候,会先把事件处理器中的连接应答处理器与AE_READABLE事件关联起来;
②客户端在连接redis的时候,会产生一个AE_READABLE事件,产生该事件后,I/O多路复用程序会把套接字压入队列;
③文件事件分派器从队列中取到套接字后,给到文件事件处理器;
④由于AE_READABLE事件跟连接应答处理器已经在redis启动初始化时已经关联上,文件事件处理器执行连接应答处理器,与客户端建立连接;(暂定名为:socket0),并将socket0的AE_READABLE事件与命令请求处理器关联起来。
二,客户端连接redis之后,发送请求(读/写操作)比如:set a 123
⑤产生一个AE_READABLE事件,同理由I/O多路复用程序把套接字(即socket)压入队列;
⑥文件事件分派器从队列中取到套接字,给到文件事件处理器;
⑦文件事件处理器执行AE_READABLE事件关联的命令请求处理器,并将socket0的AE_WRITABLE事件与命令回复处理器关联起来。
三,操作结果返回给客户端(set a 123 返回:ok)
⑧当客户端查询操作是否完成时,会在套接字产生一个AE_WRITABLE事件,同理由I/O多路复用程序把套接字压入队列。
⑨文件事件分派器读取,给到文件事件处理器
⑩文件事件处理器执行AE_WRITABLE事件关联的命令回复处理器,将结果返回给客户端。
四,最后
命令回复处理器执行完成后,就会删除这个socket0的AE_WRITABLE事件和命令回复处理器的关联。
以上就是客户端就和redis进行了一次通信的过程。由于连接应答处理器执行一次就够了,如果客户端在次进行操作就会由命令请求处理器来处理,反复执行