Redis单线程模型
文件事件处理器
Redis基于Reactor模式开发了网络事件处理器,这个处理器就叫做文件事件处理器(file event handler).这个文件事件处理器是单线程的,所以Redis才叫做单线程的模型,文件事件处理器采用了IO多路复用机制同时监听多个socket,根据socket上的事件来选择对应的事件处理器来处理这个事件;
如果被监听的socket准备好执行accept,read,write,close等事件/操作的时候,跟事件/操作对应的文件事件就会产生,这个时候文件事件处理器就会调用之前关联好的事件处理器来处理这个事件;
文件事件处理器是单线程模式运行的,但是通过IO多路复用机制监听多个socket,可以实现高性能的网络通信模型.又可以跟内部其他单线程的模块进行对接,保证了Redis内部的线程模型的简单性;
文件事件处理器的结构包含4个部分
①.多个socket;
②.IO多路复用程序;
③.文件事件分派器;
④.事件处理器(命令请求处理器,命令回复处理器,连接应答处理器等等);
多个socket可能并发的产生不同的操作,每个操作对应不同的文件事件,但是IO多路复用程序会监听多个socket,会将socket放入一个队列中排队,然后每次从队列中取出一个socket给事件分派器,事件分派器再把socket分派给对应的事件处理器去处理;
当一个socket的事件被处理完之后,IO多路复用程序才会将队列中的下一个socket取出交给事件分派器.文件事件分派器再根据socket当前产生的事件来选择对应的事件处理器来处理;
文件事件
当socket变得可读时(比如客户端对Redis执行write操作或者close操作),或者有新的可以应答的socket出现时(客户端对Redis执行connect操作),socket就会产生一个”AE_READABLE”事件;
当socket变得可写的时候(客户端对Redis执行read操作),socket就会产生一个”AE_WRITABLE”事件;
IO多路复用程序可以同时监听”AE_READABLE”和”AE_WRITABLE”两种事件,要是一个socket同时产生了”AE_READABLE”和”AE_WRITABLE”两种事件,那么文件事件分派器会优先处理”AE_READABLE”事件,然后才是”AE_WRITABLE”事件;
常用的文件事件处理器
如果是客户端要连接Redis,那么会为socket关联连接应答处理器;
如果是客户端要写数据到Redis,那么会为socket关联命令请求处理器;
如果是客户端要从Redis中读取数据(Redis发送数据给客户端),那么会为socket关联命令回复处理器;
客户端与Redis通信的一次流程
如图:
说明:
①.在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”事件和命令回复处理器的关联关系;
为什么Redis单线程模型也能效率这么高?
纯内存操作;
核心是基于非阻塞的IO多路复用机制;
底层使用C语言实现,一般来说,C 语言实现的程序”距离”操作系统更近,执行速度相对会更快;
单线程同时也避免了多线程的上下文频繁切换问题,预防了多线程可能产生的竞争问题;