Netty是基于异步的事件驱动的高性能网络框架和工具,常见的分布式中间件底层都有涉及到Netty。
要学习netty线程模型,先了解三种IO模型,这样理解netty线程模型和IO模型更轻松。
同步阻塞IO模型
一个线程负责连接,多线程则为每一个接入开启一个线程
一个请求一个应答
请求之后应答之前客户端会一直阻塞
同步非阻塞I/O
基于IO多路复用技术的“非阻塞同步”IO模型。简单来说,内核将可读可写事件通知应用,由应用主动发起读写操作;
异步非阻塞IO,AIO 引入异步通道的概念,采用了 Proactor
模式,简化了程序编写,有效的请求才启动线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用
NIO和AIO不同之处在于应用是否进行真正的读写操作。
netty的线程模型是基于reactor模式的一种实现,所以了我们先来了解一下reactor的三种线程模型
指所有的 I/O 操作都在同一个 NIO 线程上面完成的,此时NIO线程职责包括:
作为NIO服务端,接收客户端的TCP连接
作为NIO客户端,向服务端发起TCP连接
读取通信对端的请求或者应答消息
向通信对端发送消息请求或者应答消息
Reactor 为单个线程,如上图所示:不仅需要处理客户端的 accept 连接请求,同时也要负责分发(dispatch)读写请求到处理器中。
这样会导致的缺点也很明显
性能无法支撑一个NIO线程同时处理成百上千的链路
一旦NIO线程挂了,整个IO模型就会不可用,直接down掉
一个线程负责所有事情
Reactor多线程模型与单线程模型最大区别就是一组NIO线程处理I/O操作,一个NIO线程处理Accept
。一个NIO线程可以处理多个连接事件,一个连接的事件只能属于一个NIO线程。
将非IO事件交由线程池处理,reactor线程负责io事件
在绝大多数场景下,Reactor 多线程模型可以满足性能需求。
但是,当客户端短时间内连接请求爆表的时候,单个 Rector 不仅要处理注册事件,也要同时分发任务到 worker 线程池,分发是比较耗时的操作,单独一个 Acceptor 线程可能会存在性能不足的问题,有可能会导致阻塞。
服务端用于接收客户端连接的不再是一个单独的 NIO 线程,而是一个独立的 NIO 线程池
。
主reactor接受的请求给到从reactor后,全部走线程池,这样即使几十万个请求同时到来也是可以支撑的。
主reactor负责接收链接,从reactor负责传递io事件到线程池
首先需要明确的一点是
Netty的线程模型并不是一成不变的,它实际取决于用户的启动参数配置。通过设置不同的启动参数,Netty 可以同时支持 Reactor 单线程模型、多线程模型。
Netty默认的线程模型就是上面的主从NIO模型,是基于Reactor模型的。通常采用一主多从
,但是也可以根据实际需要配置启动参数改成 “多主多从”。
我们通过代码可以很直观的了解Netty的线程模型
单线程模型:
private EventLoopGroup group = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
.group(group)
.childHandler(new HeartbeatInitializer());
多线程模型:
private EventLoopGroup boss = new NioEventLoopGroup(1);
private EventLoopGroup work = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
.group(boss,work)
.childHandler(new HeartbeatInitializer());
主从多线程:
private EventLoopGroup boss = new NioEventLoopGroup();
private EventLoopGroup work = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
.group(boss,work)
.childHandler(new HeartbeatInitializer());
大伙可以需要根据具体的业务场景进行判断,灵活处理。
扫码关注我的微信公众号:Java架构师进阶编程
获取最新面试题,电子书专注分享Java技术干货,包括JVM、SpringBoot、SpringCloud、数据库、架构设计、面试题、电子书等,期待你的关注!