Netty源码之NIO
netty是什么
Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。简单说就是网络编程框架,编写服务端和客户端进行通信
Netty应用
Netty作为一个异步高性能通信框架,在远程服务调用的高性能RPC框架中的通信框架
阿里分布式服务框架 Dubbo(默认使用Netty 作为基础通信组件)
RocketMQ的消息生产者和消息消费者之间也是使用的netty
游戏行业网络通信
在具体了解netty如何使用之前,需要了解BIO、NIO、AIO的基本概念和原理及它们的区别。为什么Netty会选择NIO模型而放弃使用AIO。
同步和异步,阻塞和非阻塞
同步和异步是体现在服务提供者(服务端),当调用者调用服务提供的方法,服务提供者能立即返回,并在处理完之后能够返回(可以通过回调方法),那就是异步。如果是等处理完之后再返回,或需要调用者再次查询是否完成则是同步。
阻塞和非阻塞体现在调用者(客户端),当调用者调用服务提供者的方法,一直等待结果,那就是阻塞。立即返回则是非阻塞。
BIO、NIO和AIO
BIO
同步阻塞I/O模式
BIO通信模型的服务端,由一个 Acceptor 线程负责监听客户端的连接。我们一般通过在while(true) 循环中调用 accept() 方法监听等待接收客户端的连接,一旦接收到一个连接请求,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成, 可以通过多线程来支持多个客户端的连接。所以,数据的读写在一个线程内完成,如果需要增加并发访问量则需要创建线程。线程的
不断创建和销毁非常浪费性能
BIO测试案例
启动后,浏览器访问返回当前时间
伪异步 IO
为了解决并发访问量的线程创建问题出现的
image.png
伪异步I/O通信框架采用了线程池实现,避免了线程资源耗尽问题,因为它的底层仍然是BIO模型,因此无法从根本上解决问题
NIO (New I/O)
NIO是一种同步非阻塞的I/O模型。在java.nio包中,拥有3个核心概念:Selector(选择器),channel(通道),buffer(缓冲区)。
java.nio包和java.io包比较:
java.nio包中,是面向块(block)或是缓冲区(buffer)编程的。
而java.io包中最为核心的概念是流(stream),是面向流编程的,一个流要么是输入流,要么是输出流。
NIO组件的关系
image.png每一个channel(通道)都注册到selector(选择器)上,channel数据的读取和写入都是面向Buffer(缓冲区)
Nio服务端和客户端测试案例
测试方式及效果:客户端连接后,就可以与服务端交替得到另一端信息。先客户端输入,再服务端输入,一直这样交替下去。
流程:当服务端启动时,把serverSocketChannel对象注册到selector中,接受可连接事件。当客户端连接到服务端,在while死循环内获取到连接事件,并得到当前连接的SocketChannel对象,并注册到selector,设置事件是OP_READ可读事件。在客户端发送一串输入,在服务端的while死循环内走到isReadable读事件。读取到客户端输入数据,设置OP_WRITE可写事件,然后服务端键盘输入,客户端获取,再次变为可读事件。
AIO(Asynchronous I/O)
异步非阻塞的IO模型,异步 IO 是基于事件和回调机制实现的,应用操作之后会直接返回,不会堵塞在那里。
Netty为什么去掉支持AIO
https://github.com/netty/netty/issues/2515
1、在linux系统上,AIO的底层实现是epoll。并不比NIO快
2、Netty是reactor模型, 而AIO是proactor模型
3、AIO需要预先分配缓存,NIO按需分配
Reactor模型
Doug Lea大神文档
在了解NIO的基本使用及概念后,需要了解NIO在Reactor模式的应用。
1、单Reactor单线程模式
Reactor单.png单Reactor单线程测试案例
实现原理是:Reactor线程监控是否有新的事件,对于不同的事件dispatch转发到不同的处理模块。acceptor处理客户端连接事件,连接后获取SocketChannel通道并注册可读事件。在Reactor线程内检测到有新事件,则会转发到相应的事件(可读或可写事件)。对于这种实现方式,如果decode(解码)、compute(计算)、encode(编码)非常耗的资源,则客户端调用则会阻塞。所以出现了对这部分的多线程处理,叫单Reactor多线程模型。
2、单Reactor多线程模型
单Reactor多.png单Reactor多工作线程测试案例
相对于第一种,就是处理业务逻辑部分由线程池处理。这样可以减小reactor的性能开销,从而更专注的做事件分发dispatch工作了,从而提升整个应用的吞吐量。
缺点:连接和读写事件都是由一个Reactor进行处理
3、多Reactor多线程模型
MultipleReactor.png多Reactor线程模式测试案例
实现原理:mainReactor负责处理新连接的建立(需要一个线程就可以),然后把连接后获得的socketChannel通道注册到subReactor。对于读写网络数据,对业务处理等功能,交给worker线程池来处理。这种模式耦合度更低,性能和稳定性也有所提升。在这种模式下的应用有mina 和netty。
总结:
1、需要了解BIO、NIO、AIO的基本概念及其原理
2、NIO所涉及的类及其关系
3、Reactor三种模型
4、为什么Netty会选择NIO