Reactor设计模式Reactor设计模式的基本设计思想是基于IO复用模型实现的
这里介绍IO复用模型。 与传统的IO多线程块不同,IO复用模型中的多个连接共享一个块对象,而APP应用程序只需在一个块对象上等待。 当一个连接可以处理新数据时,操作系统会通知APP应用程序,线程将从阻塞状态恢复,并开始处理业务是什么意思? 餐馆老板也发现了顾客点晚的问题,所以他采用了大胆的方法,只留下了一个服务员。 客人点餐后,该服务员会邀请其他客人,客人点餐后直接叫服务员进行服务。 这里的顾客和服务员可以分别视为多个连接和一个线程。 服务器卡在一个客户那里,另一个客户点餐后,他马上去服务其他客户,了解了reactor的设计思想后,但是看看reactor单线程的实现方案
reactor通过IO多路复用器监视客户端请求实践,并在收到事件时通过任务调度器分发。
对于连接建立请求事件,由acceptor处理,建立对应的handle负责后续的业务处理。 对于未连接事件,reactor调用相应的handler完成read-业务处理write处理过程,并将结果返回给客户端。整个过程都在一个线程里面完成
redis的网络事件处理器redis基于reactor模式开发了自己的网络事件处理器。 此处理器称为文件事件处理器。
采用I/O多路复用同时监听多个socket,根据socket当前执行的事件来为 socket 选择对应的事件处理器当监听到的套接字准备执行accept、read、wriet、close等操作时,将发生操作的文件事件,此时FEH是与套接字之前相关联的事件
上述情况:
插座
文件事件是套接字操作的抽象。 当套接字准备执行连接到accept、read、write和close等操作时,将发生文件事件。 多个套接字通常连接到一个服务器,并且多个套接字可能同时生成不同的操作。 每个动作对应一个不同的文件事件。 I/O复用器
I/O复用器负责接收多个套接字。 虽然文件事件可能同时发生,但I/O复用器会对生成事件的所有套接字进行排队。 通过此队列,套接字按顺序按套接字发送到文件事件调度程序。 I/O复用器在前一个套接字上生成的事件在相应的事件处理器上运行后,将以下套接字发送到文件事件调度程序,如下所示: I/O复用器的实现
redis的IO复用程序的所有功能都是通过包装IO复用函数库(如常见的选择、轮询、ev端口、kqueue等)来实现的,每个IO复用函数库在redis源代码中位于单独的文件中
由于redis为每个I/O复用库实现了相同的API,因此I/O复用程序的基本实现是兼容的。 由于redis为每个I/O复用库实现了相同的API,因此I/O复用程序的基本实现是兼容的。 Redis在I/O复用程序的实现源代码ae.c文件中由宏定义适当的规则,并在编译程序时自动将系统中性能最高的I/O复用库作为redis I/o复用程序的下级实现文件事件调度程序
文件调度程序接收从I/o复用器发送来的套接字,并根据套接字生成的事件类型调用相应的事件处理器
文件事件处理器
服务器将不同的事件处理器与执行不同任务的套接字相关联。 这些处理器是定义服务器在事件发生时应执行的操作的函数。
redis为每个文件事件的请求创建多个处理器,如果客户端连接到redis并响应连接到服务器的每个客户端,则将套接字映射到链接响应服务器,并将数据写入redis,然后从客户端复制需要映射到命令请求处理器以从redis读取数据,并将命令的执行结果返回到客户端,并且需要映射到命令响应处理器以在主服务器和从服务器上执行复制操作的文件事件的类型
I/O复用器可以接收多个套接字的ae.h/AE_READABLE和ae.h/AE_WRITABLE事件。 这些事件与套接字操作的对应关系如下。
如果客户端对Redis执行write/close操作,或者出现新的响应套接字,即客户端对Redis执行connect操作,则socket将生成AE_READABLE事件例如,如果客户端可以向Redis写入,则I/O复用器可以同时接收AE_REABLE和AE_WRITABLE事件。 如果一个套接字同时生成两个事件,则为文件事件调度程序
优先处理AE_REABLE事件。即一个socket又可读又可写时, Redis服务器先读后写socket。最后,让我们梳理一下客户端和Redis服务器通信的整个过程:
Redis6 版本中引入了多线程。之前已经提到过 Redis 单线程处理有着很快的速度,那为什么还要引入多线程呢?单线程的瓶颈在什么地方?
先来看第二个问题,在 Redis 中,单线程的瓶颈主要在网络IO上。也就是在读写网络的read/write系统调用执行期间会占用大量的CPU时间。如果要对一些大的键值对进行删除操作的话,在短时间内是删不完的,那么对于单线程来说就会阻塞后边的操作。回想下上边讲的reactor模式中单线程的处理方式。针对非连接事件,Reactor 会调用对应的 handler 完成 read->业务处理->write 处理流程,也就是说这一步会造成性能上的瓶颈。
redis6.0的多线程是指,将网络数据读写和协议解析通过多线程的方式来处理,对于命令来说,仍然使用单线程操作。也就是说,redis6.0的多线程是为了解决其网络IO的瓶颈