Netty的原理
Netty是什么呢?Netty是JBoss出品的高效的Java NIO开发框架。
Reactor模式
Netty使用了Reactor模式,包括三种模式:
- Reactor单线程模型
- Reactor多线程模型
- 主从多线程模型
实际上的Reactor模式,是基于Java NIO的,在他的基础上,抽象出来两个组件——Reactor和Handler两个组件:
- Reactor:负责响应IO事件,当检测到一个新的事件,将其发送给相应的Handler去处理;新的事件包含连接建立就绪、读就绪、写就绪等。
- Handler:将自身(handler)与事件绑定,负责事件的处理,完成channel的读入,完成处理业务逻辑后,负责将结果写出channel。
- Acceptor:接受客户端的请求,也可以看做一个Handler。
Reactor单线程模型
只有一个线程完成所有事情,包括接收客户端的TCP连接请求、监听事件、进行读取和写入套接字数据等。
对于一些小容量应用场景,可以使用单线程模型。但是对于高负载、大并发的应用却不合适,主要原因如下:
- 性能有极限,不能处理成百上千的事件 ,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送;
- 当NIO线程负载过重之后,性能将会下降,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加重了NIO线程的负载,最终会导致大量消息积压和处理超时,NIO线程会成为系统的性能瓶颈;
- 可靠性问题:一旦NIO线程的某一个事件处理器(handle)发送故障或者阻塞时,会使其他所有的handle都不能进行,而且acceptor也会阻塞住,也就是说,整个系统通信模块都不可用,不能接收和处理外部消息,造成节点故障。
为了解决这些问题,演进出了Reactor多线程模型。
Reactor多线程模型:
Rector多线程模型与单线程模型最大的区别就是:有一个线程池处理真实的IO操作,也就是说,将诸多handle放入线程池中进行IO操作,而acceptor、reactor还是单线程,接受客户端的TCP连接请求。
Reactor多线程模型的特点:
- 有专门一个NIO线程-Acceptor线程用于监听服务端,接收客户端的TCP连接请求;
- 网络IO操作-读(handler)、写等由一个NIO线程池负责,它包含一个任务队列和N个可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送;
- 1个NIO线程可以同时处理N条链路,但是1个链路只对应1个NIO线程,防止发生并发操作问题。
在绝大多数场景下,Reactor多线程模型都可以满足性能需求;但是,在极特殊应用场景中,一个NIO线程负责监听和处理所有的客户端连接可能会存在性能问题。
例如百万客户端并发连接,或者服务端需要对客户端的握手消息进行安全认证,认证本身非常损耗性能。在这类场景下,单独一个Acceptor线程可能会存在性能不足问题,为了解决性能问题,产生了第三种Reactor线程模型-主从Reactor多线程模型。
主从Reactor多线程模型
主从Reactor线程模型与Reactor多线程模型的最大区别就是:有一个主reactor监听连接,多个从reactor监听读写事件。也就是说,将一个Reactor分为主从两种,分别负责监听连接事件和读写事件。
这里MainReactor只有一个,但是subReactor可以有多个。
MainReactor会监控Acceptor线程池,而subReactor会监控Handler线程池。
Acceptor线程池只用于客户端的登录、握手和安全认证,一旦链路建立成功,就将链路注册到后端subReactor线程池的I/O线程上,有I/O线程负责后续的I/O操作。
即从多线程模型中由一个线程来监听连接事件和数据读写事件,拆分为一个线程监听连接事件,线程池的多个线程监听已经建立连接的套接字的数据读写事件,另外和多线程模型一样有专门的线程池处理真正的IO操作。
Netty的模式
说完Reacotr模型的三种形式,那么Netty是哪种呢?
其实,还有一种Reactor模型的变种,那就是去掉线程池的第三种形式的变种,这也 是Netty NIO的默认模式。
在实现上,Netty中的Boss类充当mainReactor,NioWorker类充当subReactor(默认 NioWorker的个数是Runtime.getRuntime().availableProcessors())。在处理新来的请求 时,NioWorker读完已收到的数据到ChannelBuffer中,之后触发ChannelPipeline中的ChannelHandler流。
- EventLoopGroup就相当于是Reactor,bossGroup对应主Reactor,workerGroup对应从Reactor
- TimeServerHandler就是Handler
- child开头的方法配置的是客户端channel,非child开头的方法配置的是服务端channel
NioEventLoop是Netty的Reactor线程,它在Netty Reactor线程模型中的职责如下:
- 作为服务端Acceptor线程,负责处理客户端的请求接入
- 作为客户端Connecor线程,负责注册监听连接操作位,用于判断异步连接结果
- 作为IO线程,监听网络读操作位,负责从SocketChannel中读取报文
- 作为IO线程,负责向SocketChannel写入报文发送给对方,如果发生写半包,会自动注册监听写事件,用于后续继续发送半包数据,直到数据全部发送完成
如下图,是一个NioEventLoop的处理链:
注意:
-
handler处理链中的处理方法是串行化执行的
-
一个客户端连接只注册到一个NioEventLoop上,避免了多个IO线程并发操作
-
Netty中模式具体是怎样的
原文链接:https://blog.csdn.net/qq_18603599/article/details/80768390