Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发、高吞吐量的环境中进行I/O处理。
I/O多路复用机制都依赖于一个事件分发器,事件分离器把接收到的客户事件分发到不一样的事件处理器中,以下图:java
在操做系统级别select,poll,epoll是3个经常使用的I/O多路复用机制,简单了解一下将有助于咱们理解Proactor和Reactor。
select的原理以下:react
用户程序发起读操做后,将阻塞查询读数据是否可用,直到内核准备好数据后,用户程序才会真正的读取数据。promise
poll与select的原理类似,用户程序都要阻塞查询事件是否就绪,但poll没有最大文件描述符的限制。
epoll是select和poll的改进,原理图以下:
epoll使用“事件”的方式通知用户程序数据就绪,而且使用内存拷贝的方式使用户程序直接读取内核准备好的数据,不用再读取数据缓存
Proactor是一个异步I/O的多路复用模型,原理图以下:
Reactor是一个同步的I/O多路复用模型,它没有Proactor模式那么复杂,原理图以下:
前面已经简单介绍了Proactor和Reactor模型,在实际中Proactor因为须要操做系统的支持,实现的案例很少,有兴趣的能够看一下Boost Asio的实现,咱们主要说一下Reactor模型,Netty也是使用Reactor实现的。
但单线程的Reactor模型每个用户事件都在一个线程中执行:安全
使用线程池的技术来处理I/O操做,原理图以下:
在多线程Reactor中只有一个Acceptor,若是出现登陆、认证等耗性能的操做,这时就会有单点性能问题,所以产生了主从Reactor多线程模型,原理以下:
Netty同时支持Reactor的单线程、多线程和主从多线程模型,在不一样的应用中经过启动参数的配置来启动不一样的线程模型。
经过线程池的线程个数、是否共享线程池方式来切换不一样的模型网络
Netty中的Reactor模型以下图:多线程
NioEventLoop是Netty的Reactor线程,它在Netty Reactor线程模型中的职责以下:并发
1. 做为服务端Acceptor线程,负责处理客户端的请求接入 2. 做为客户端Connecor线程,负责注册监听链接操做位,用于判断异步链接结果 3. 做为IO线程,监听网络读操做位,负责从SocketChannel中读取报文 4. 做为IO线程,负责向SocketChannel写入报文发送给对方,若是发生写半包,会自动注册监听写事件,用于后续继续发送半包数据,直到数据所有发送完成
以下图,是一个NioEventLoop的处理链:异步
Netty Reactor线程模型中有两种Task:系统Task和定时Task
基于以上缘由,NioEventLoop不是一个纯粹的IO线程,它还会负责用户线程的调度高并发
线程池对IO线程进行资源管理,是经过EventLoopGroup实现的。线程池平均分配channel到全部的线程(循环方式实现,不是100%准确),一个线程在同一时间只会处理一个通道的IO操做,这种方式能够确保咱们不须要关心同步问题。
NioEventLoop是Reactor的核心线程,那么它就就必须实现多路复用。
Selector的过程以下:
epoll-bug的处理
在netty中对java nio的epoll bug进行了处理,就是设置一个阀值,若是超过了就rebuidSelector来避免epoll()死循环
EventExecutorGroup:提供管理EevntLoop的能力,他经过next()来为任务分配执行线程,同时也提供了shutdownGracefully这一优雅下线的接口
EventLoopGroup继承了EventExecutorGroup接口,并新添了3个方法
EventLoopGroup的实现中使用next().register(channel)来完成channel的注册,即将channel注册时就绑定了一个EventLoop,而后EvetLoop将channel注册到EventLoop的Selector上。
NioEventLoopGroup还有几点须要注意: