1. Netty简介

简而言之,Netty就是一个高性能、异步事件驱动的NIO框架,基于JAVA NIO提供的API实现。Netty是典型的Reactor模型结构。Reactor模式首先是事件驱动的。

2. 四种io的简单区别

通常io操作分为以下步骤:发起IO请求IO操作
如果发起IO请求被阻塞那就是阻塞IO;如果不阻塞,那么就是非阻塞IO
如果IO读写阻塞请求进程,那么就是同步IO,而操作系统帮你做完IO操作之后然后再通知io请求已完成,那么就是异步IO

3. 什么是BIO、NIO、AIO

BIO(同步阻塞IO)当客户端有链接请求时服务端就会启动一个线程处理客户端的链接,一个链接就要启动一个线程,一个线程大致消耗1Mb的内存,当连接变多的时候就很耗性能。

grpc NettyServerBuilder 限制连接池数量 netty 连接池原理_客户端


BIO优点:

模型简单

编码简单

BIO缺点:

耗性能

BIO适用场景:

适用于连接数目比较小并且一次发送大量数据的场景

NIO(同步非阻塞IO)客户端发送的连接请求都会注册到多路复用器上(selector),多路复用器轮询到连接有I/O请求时用一个或者少量线程去处理。selector类似一个观察者, socket没有请求的时候selector一直处于阻塞状态,等到有accept/read/write等事件发生时唤醒Selector,这时候就分配一个线程去处理。

grpc NettyServerBuilder 限制连接池数量 netty 连接池原理_客户端_02


NIO优点:

性能瓶颈高

NIO缺点:

模型复杂

编码复杂

有异常bug

空循环耗性能

要处理粘包、半包问题

NIO适用场景:

适合处理连接数目特别多,但是连接比较短(轻操作)的场景,Jetty,Mina,ZooKeeper等都是基于java nio实现。

AIO(异步非阻塞式IO)在AIO中,客户端的io操作都是由系统完成的,完成后(读写完毕之后)然后才去通知服务器的,它无需一个线程去轮询有无请求。当进行读写操作时,只须直接调用API的read或write方法即可,读写都是异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。

AIO适用场景:

适用于连接数目多且连接比较长(重操作)的架构。

4. Netty线程模型

Netty是典型的Reactor模型结构,那么基于不同线程的Reactor模型,就有了不同的Netty线程模型。
可以分为三种模型:Reactor单线程模型Reactor多线程模型主从Reactor模型

1)Reactor单线程模型

grpc NettyServerBuilder 限制连接池数量 netty 连接池原理_客户端_03


在Reactor单线程模型中,Acceptor用于接收客户端的链接请求,生成对应的Handler,并向Reactor注册。Handler主要用于处理业务,比如io读写、编码解码、计算等等。Reactor线程采用异步非阻塞IO,Reactor线程负责分离套接字、处理链接请求、注册Handler、将Socket操作请求分发到对应的Handler去处理。在这个模式中当同一个客户端多次发送请求的时候是同一个Handler在处理,如果这个Handler异常或者处理过慢,那么后续的客户端请求就难以得到相应。

2)Reactor多线程模型

grpc NettyServerBuilder 限制连接池数量 netty 连接池原理_客户端_04


为了解决单线程模式读写压力的问题,Reactor多线程模型在读写方面增加了线程池,IO操作和非IO操作分开,操作IO的线程称为IO线程,非IO操作的线程称为工作线程。客户端的请求会直接被丢到线程池中,客户端发送请求也就不会堵塞了。Reactor多线程模型解决了读写性能问题,提高了整体性能,但是在用户量大量增加的时候, 一个Reactor可能出现性能不足的问题,Reactor又要处理链接请求又要处理读写操作。

3)主从Reactor模型

grpc NettyServerBuilder 限制连接池数量 netty 连接池原理_线程模型_05


将Reactor分成两部分,mainReactor负责监听socket,接收新连接,并将建立的Handler分派给subReactor。subReactor负责多路分离已连接的socket,读写数据等操作。

4. Netty模块简单接收

1)Selector
Netty 基于 Selector 对象实现 I/O 多路复用,通过 Selector 一个线程可以监听多个连接的 Channel 事件。
2)NioEventLoop
一个NioEventLoop有一个线程和一个任务队列,支持异步提交执行任务,线程启动时会调用 NioEventLoop 的 run 方法,执行 I/O 任务和非 I/O 任务。
3)NioEventLoopGroup
主要管理 eventLoop 的生命周期,类似一个线程池,内部维护了一组线程,每个线程(NioEventLoop)负责处理多个 Channel 上的事件。
4)ChannelHandler
处理 I/O 事件或拦截 I/O 操作,并将其转发到其 ChannelPipeline中的下一个处理程序。
5)ChannelPipeline
它保存 ChannelHandler 的 List,用于处理或拦截 Channel 的入站事件和出站操作。