BIO 同步阻塞
客户端:Socket
服务端:ServerSocket
服务端监听是否有连接(accept 阻塞),如果有新连接,则给连接分配个线程,线程中执行read、decode、业务处理、encode、write的所有流程,其中read是阻塞的。
这种模型下,并发数受限于线程数,而线程数有限。如果有耗时操作则会很大影响并发能力,而且如果连接建立但是没有发送数据,线程也不会释放。
NIO 同步非阻塞
客户端:SocketChannel
服务端:ServerSocketChannel
NIO采用多路复用技术,客户端的连接请求注册在Selector上,服务端通过一个线程轮询Selector上是否有连接请求,有则进行处理。由于read和write也是阻塞的,为了提高性能,使用两个线程池,一个线程池用于处理read、write这种耗时操作,内部也是通过selector轮询;另一个线程池用于处理业务请求。
经典的主从线程模型:mainReactor通过自己的selector监控连接事件,收到事件后通过Acceptor接收,将新的连接分配给subReactor。subReactor将连接加入到自己的连接队列中,通过selector监听所有的连接事件,当有数据写入时,创建个handler进行处理。handler完成read、业务处理、send。
NIO中的重要概念:
- channel
- buffer 数据必须从缓冲池写入,再写出到缓冲池
- selector
AIO 异步非阻塞
服务端通过返回FutureTask实现异步。accept、read、write都是异步的,有事件到达时,操作系统主动通知应用程序。
Netty
客户端启动辅助类:BootStrap
服务端启动辅助类:ServerBootStrap
Netty是基于NIO的事件驱动的高性能网络通信框架,使用Netty可以快速开发网络应用。Netty相比于直接用java NIO开发的有点在于,提供了简单易用的API,最小化不必要的内存拷贝,完整的SSL/TLS和StartTLS的支持。
Netty的线程模型:
boss group 和 worker group 是两个线程池,boss group用于接收客户端连接,相当于 MainReactor,worker group负责处理连接。线程池的默认线程数是2 * 处理器个数。boss group一般会指定线程数是1,够用了。每个group里面都有多个EventLoop,每个EventLoop包含一个Selector、一个队列、一个线程。线程用于轮询注册到selector上的channel的读写事件,和对投递到队列里面的时间进行处理。
boss eventloop的过程是:轮询是否有accept事件,有的话,生成NioSocketChannel并注册到某个worker nioEventLoop的selector上。(生成channel时会同时创建一个pipeline绑定到这个channel上)
worker eventloop的过程是:轮询注册到自己selector上的channel的read和write事件,如果有事件,则在channel对应的channelPipeline中处理业务。pipeline中维护了一系列channelHandler处理器链表。
Netty中几个重要的对象
- channel 套接字通道接口,客户端和服务端通过通道进行交互。客户端的通道是NioSocketChannel,服务端的通道是NioServerSocketChannel。每个连接对应一个channel,每个channel都有个专属的channelPipeline。所以没有安全问题。
- channelPipeline 是一个拦截流经channel的入站和出站事件的channelHandler实例链,定义了用于在该链上传播入站和出站事件流的API。channelHandler间通过channelHandlerContext传递数据。
- NioEventLoopGroup 实际上是一个线程池,一个Group中包含了多个EventLoop
- EventLoop
参考:
Apache HttpAsyncClient 源码解析 juejin.cn/post/712789…