龙空技术网

Netty线程模型(深入+详解),Java学习必备

没想好做什么 65

前言:

此时看官们对“netty线程数量应该怎么选择”大体比较关怀,大家都需要分析一些“netty线程数量应该怎么选择”的相关内容。那么小编也在网摘上网罗了一些对于“netty线程数量应该怎么选择””的相关资讯,希望看官们能喜欢,咱们一起来学习一下吧!

当我们谈论Netty的线程模型时,首先会想到的是经典的Reactor IO多路复用线程模型。从这篇文章中,大家可以学习到如下知识:

什么是I/O多路复用

Reactor三种线程模型

Netty线程模型

NioEventLoop源码分析

什么是I/O多路复用

学习I/O多路复用之前,我们先来了解如下几个概念:

阻塞I/O:客户端从socket中读取数据或写入数据时,如果读取时流中没有数据,写入时缓冲区已满,就需要block,知道流中有数据或者缓冲区的数据被排空。

非阻塞I/O:客户端从流中读取数据,如果流中没有数据,则立即返回,不发生block。

同步I/O:同步I/O将导致请求的I/O操作一直被block,直到I/O完成。

异步I/O:异步I/O不会导致block,发出I/O请求后立即返回,直到完成I/O操作后再异步通知调用进程。

I/O多路复用可以监视多个FD(文件描述符),一旦某个FD准备就绪,就会通知相应进程处理。多路复用也是阻塞的,阻塞的方法是select/poll/epoll,可以在单个进程中同时处理多个I/O请求,原理是采用轮询的方式便利所有的I/O操作,当某些I/O有数据时,就通知用户进程处理。

select:系统提供select函数来实现多路复用输入/输出模型,select系统调用是用来让我们的程序监视多个文件句柄的状态变化。程序会阻塞在select函数上,直到被监视的文件句柄中有一个或多个发生了状态变化。

poll:poll函数与select函数的最大不同之处在于:select函数有最大文件描述符的限制,一般1024个,而poll函数对文件描述符的数量没有限制。

epoll:

监视的描述符数量不受限制,所支持的FD上限是Linux系统最大可以打开文件的数目;

I/O效率不会随着监视fd的数量增长而下降。epoll不同于select和poll轮询的方式,而是通过每个fd定义的回调函数来实现的,只有就绪的fd才会执行回调函数。

Reactor三种线程模型

1. Reactor单线程模型

是指所有的I/O操作都在同一个NIO线程上完成,职责如下

作为NIO服务端,接收客户端TCP连接

作为NIO客户端,向服务端发起TCP连接

读取对端请求或者应答消息

向对端发送请求或者应答消息

在一些小容量场景下,可以使用多线程模型,但对于高负载场景下并不适用,原因如下:

一个NIO线程同时处理成百上千的连接,性能上无法保证。

NIO线程负载过重,处理速度会越来越慢,会导致大量客户端连接超时

一旦NIO线程跑飞,或者死循环,会导致整个系统的不可用

2. Reactor多线程模型

与单线程模型最大的区别是,有一组NIO来处理I/O请求,特点如下

有一个NIO线程——Acceptor线程用户监听客户端的连接

有一个NIO线程池负责I/O的读写操作,该线程池可以是基于JDK的线程池。

3. 主从Reactor多线程模型

如果并发百万的客户端连接,在Reactor多线程模型下只有一个NIO的Acceptor线程处理客户端连接会有性能问题。主从Reactor线程模型的特点是:服务端用于接收客户端的连接不再是一个单独的NIO线程,而是一个NIO的Acceptor线程池。Acceptor接收到客户端的TCP连接请求处理完成后,将新创建的ChannelSocket注册到I/O线程池(sub reactor线程池)上的某一个线程上,由I/O负责后续的I/O读写操作。

4. Netty线程模型

还记得Netty服务端启动时的代码吗??

EventLoopGroup bossGroup = new NioEventLoopGroup();

EventLoopGroup workerGroup = new NioEventLoopGroup();

服务端启动时创建了两个NioEventLoopGroup,他们实际上时两个独立的Reactor线程池,一个负责接收客户端的TCP连接,另一个用于处理I/O操作,或执行系统Task、定时任务Task等,如上图所示的两个方法:

NioEventLoop.execute(Runnable task)

NioEventLoop.schedule(Runnable task)

NioEventLoop源码分析

先让我们来看看NioEventLoop的继承关系图

NioEventLoop需要处理网络I/O操作,首先聚合了一个多路复用器Selector,并且NioEventLoop的构造方法中直接调用openSelector()方法完成初始化。

标签: #netty线程数量应该怎么选择