Reactor 单线程模型
描述:是指所有的 I/O 操作都在同一个 NIO 线程上面完成的,此时NIO线程职责包括:接收新建连接请求、读写操作等
优点:区别于传统的IO,一个线程可以处理多个连接的请求,提高吞吐量。
缺点:单线程,如果某个连接存在耗时操作,将会阻塞到其他客户端的连接和事件处理 (注:redis的线程模型就是单线程,为什么这么快,因为redis的操作是都是比较简单的操作,而且都是基于内存的操作所以比较快,所以redis发生耗时操作也会影响redis的吞吐量,比如存在大key或者keys命令)
Reactor 多线程模型
描述:一个NIO(selector)线程,负责通过epoll监听事件,然后将IO事件的处理分发到一个NIO线程池中去处理。
优点:区别于单线程模型,采用多线程的方式去处理IO事件,有效解决事件耗时阻塞selector线程的问题。
缺点:只有一个selector线程,这个线程要监听所有连接的事件,在高负载的情况下(并发百万客户端连接),会对selector线程造成极大的压力,处理连接的能力不够,会导致客户端连接超时
Reactor 主从线程模型
描述:一个NIO线程池负责监听accept事件,一个NIO线程池负责监听IO事件,类比到netty中去就是boss线程池和woker线程池,当boss中的线程接到连接请求,建立好连接后,会将这个连接注册到woker线程池中的某个线程 有woker中的线程去负责后续的IO事件的监听与事件处理,一个连接只会属于一个woker线程,一个woker线程处理多个连接。
(注:每个线程都是一个selector线程,boss注册到woker就是将这个channel注册到woker中的selector,以此实现让woker线程监听这个channel的后续IO事件, ** 虽然bossGroup也能指定多个NioEventLoop(一个NioEventLoop对应一个线程),但是默认情况下只会有一个线程,因为一般情况下应用程序只会使用一个对外监听端口**,如果多线程使用epoll_wait去监听同一个端口,依赖于内核的锁去保证线程安全性, 但是使用多线程去监听会有几个问题,一个是epoll的惊群问题,另一个是epoll默认是LT(水平触发),多线程epoll_wait时就会导致第一个线程epoll_wait之后还未处理完毕已发生的事件时,第二个线程也会epoll_wait返回)
优点:区别于一个NIO线程监听,主从线程模型提高了服务器处理连接请求的吞吐量,专门一个线程去监听accept时间,建立连接,IO事件的监听和处理由另个一个线程池去处理,将连接事件和处理IO事件分离开来。
题外话:IO模型
同步阻塞:传统IO,读取没有数据阻塞直到有数据,吞吐量低,线程利用率低(传统IO)
同步非阻塞:每次读取不管有没有数据都返回结果,不阻塞等待,线程可以去做别的事情,需要不断的去轮询是否有数据,消耗大量的cpu(socket非阻塞模式)
IO多路复用:借用select,epoll,有数据时才返回,不用轮询,并且可以一次处理多个连接(NIO)
异步阻塞:信号IO,读取无数据立即返回,等数据可读,此时数据还在内核缓冲区,系统通知进程读取,进程读取,阻塞在系统从内核缓冲区复制到用户缓冲区过程,复制完成后进行读取
异步非阻塞:读取无数据立即返回,等到数据完全准备好了,已经从内核缓冲区复制到用户缓冲区,系统通知进程进行读取。