最全基础知识深化:NIO优化原理和Tomcat线程模型,SpringBoot项目瘦身指南

难道这样就够了吗?不,远远不够!

提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。

备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记

我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。

今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!

阿里一面就落马,恶补完这份“阿里面试宝典”后,上岸蚂蚁金服

阿里一面就落马,恶补完这份“阿里面试宝典”后,上岸蚂蚁金服

image.png

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

由此可见在网络I/O中,会有很多的因素导致数据的读取和写入过程出现阻塞,创建socket连接也一样。socket.accept()、socket.read()、socket.write()这类函数都是同步阻塞的,当一个连接在处理I/O的时候,系统是阻塞的,该线程当前的cpu时间片就浪费了。

2、阻塞优化

==========================================================================

2.1、BIO、NIO、AIO

===================================================================================

BIO、NIO、AIO对比

以socket.read()为例子:

  • 传统的BIO里面socket.read(),如果TCP RecvBuffer里没有数据,函数会一直阻塞,直到收到数据,返回读到的数据。

  • 对于NIO,如果TCP RecvBuffer有数据,就把数据从网卡读到内存,并且返回给用户;反之则直接返回0,永远不会阻塞。

  • 最新的AIO(Async I/O)里面会更进一步:不但等待就绪是非阻塞的,就连数据从网卡到内存的过程也是异步的。

换句话说,BIO里用户最关心“我要读”,NIO里用户最关心”我可以读了”,在AIO模型里用户更需要关注的是“读完了”。

NIO

NIO的优化体现在两个方面:

  1. 网络I/O模式 的优化,通过非阻塞的模式,提高了CPU的使用性能。

  2. 内存I/O 的优化,零拷贝等方式,让数据在内核态和用户态之前的传输消耗降低了。

NIO一个重要的特点是: socket主要的读、写、注册和接收函数,在等待就绪阶段都是非阻塞的,真正的I/O操作是同步阻塞的(消耗CPU但性能非常高) 。

NIO的主要事件有几个:读就绪、写就绪、有新连接到来。

我们首先需要注册当这几个事件到来的时候所对应的处理器。然后在合适的时机告诉事件选择器:我对这个事件感兴趣。对于写操作,就是写不出去的时候对写事件感兴趣;对于读操作,就是完成连接和系统没有办法承载新读入的数据的时;对于accept,一般是服务器刚启动的时候;而对于connect,一般是connect失败需要重连或者直接异步调用connect的时候。

其次,用一个死循环选择就绪的事件,会执行系统调用 (Linux 2.6之前是select、poll,2.6之后是epoll,Windows是IOCP) ,还会阻塞的等待新事件的到来。新事件到来的时候,会在selector上注册标记位,标示可读、可写或者有连接到来。

2.2、Reactor模式

=================================================================================

Reactor模式称之为响应器模式,通常用于 NIO 非阻塞IO的网络通信框架中。Reactor设计模式用于处理由一个或多个客户端并发传递给应用程序的的服务请求,可以理解成, Reactor模式是用来实现网络NIO的方式 。

Reactor是一种事件驱动机制,是处理并发I/O常见的一种模式,用于同步I/O,其中心思想是将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程阻塞在多路复用器上,一旦有I/O事件到来或是准备就绪,多路复用器将返回并将相应I/O事件分发到对应的处理器中。

Reactor模式主要分为下面三个部分:

  1. 事件接收器Acceptor :主要负责接收请求连接,接收请求后,会将建立的连接注册到分离器中。

  2. 事件分离器Reactor :依赖于循环监听多路复用器Selector,是阻塞的,一旦监听到事件,就会将事件分发到事件处理器。(例如:监听读事件,等到内核态数据就绪后,将事件分发到Handler,Handler将数据读到用户态再做处理)

  3. 事件处理器Handler :事件处理器主要完成相关的事件处理,比如读写I/O操作。

2.3、三种Reactor模式

===================================================================================

单线程Reactor模式

一个线程:

  • 单线程:建立连接(Acceptor)、监听accept、read、write事件(Reactor)、处理事件(Handler)都只用一个单线程。

多线程Reactor模式

一个线程 + 一个线程池:

  • 单线程:建立连接(Acceptor)和 监听accept、read、write事件(Reactor),复用一个线程。

  • 工作线程池:处理事件(Handler),由一个工作线程池来执行业务逻辑,包括数据就绪后,用户态的数据读写。

主从Reactor模式

三个线程池:

  • 主线程池:建立连接(Acceptor),并且将accept事件注册到从线程池。

  • 从线程池:监听accept、read、write事件(Reactor),包括等待数据就绪时,内核态的数据I读写。

  • 工作线程池:处理事件(Handler),由一个工作线程池来执行业务逻辑,包括数据就绪后,用户态的数据读写。

3、Tomcat线程模型

================================================================================

3.1、Api网络请求过程

=================================================================================

我们先补一下基础知识,讲解后端接口的响应过程。一个http连接里,完整的网络处理过程一般分为accept、read、decode、process、encode、send这几步:

  1. accept :接收客户端的连接请求,创建socket连接(tcp三次握手,创建连接)。

  2. read :从socket读取数据,包括等待读就绪,和实际读数据。

  3. decode :解码,因为网络上的数据都是以byte的形式进行传输的,要想获取真正的请求,必定需要解码。

  4. process :业务处理,即服务端程序的业务逻辑实现。

  5. encode :编码,同理,因为网络上的数据都是以byte的形式进行传输的,也就是socket只接收byte,所以必定需要编码。

  6. send :往网络socket写回数据,包括实际写数据,和等待写就绪。

3.2、各个线程模型

==============================================================================

在tomcat的各个版本中,所支持的线程模型也发生了一步步演变。一方面,直接将默认线程模型,从BIO变成了NIO。另一方面,在后续几个版本中,加入了对AIO和APR线程模型的支持,这里要注意,仅仅是支持,而非默认线程模型。

  • BIO :阻塞式IO,tomcat7之前默认,采用传统的java IO进行操作,该模式下每个请求都会创建一个线程,适用于并发量小的场景。

  • NIO :同步非阻塞,比传统BIO能更好的支持大并发,tomcat 8.0 后默认采用该模式。

  • AIO :异步非阻塞 (NIO2),tomcat8.0后支持。多用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂。

  • APR :tomcat 以JNI形式调用http服务器的核心动态链接库来处理文件读取或网络传输操作,需要编译安装APR库(也就是说IO操作的部分直接调用native代码实现)。

各个线程模型中,NIO是作为目前最实用的线程模型,因此也是目前Tomcat默认的线程模型,因此本文对此着重讲解。

3.3、BIO和NIO

===============================================================================

BIO模型

在BIO模型中,主要参与的角色有: Acceptor 和 Handler工作线程池 。对应于前文中Api的请求过程,它们的分工如下:

  • Acceptor :Accepter线程专门负责建立网络连接( accept )。新连接创建后,交给Handler工作线程池处理请求。

  • Handlers :针对每个请求的连接,Handler工作线程池都会分配一个线程,执行后面的所有步骤( read、decode、process、encode、send )。

前文的知识点有铺垫, read 和 send 是面向网络I/O的,在等待读写就绪过程中,其实是CPU阻塞的。因此Handler工作线程池中的每个线程,都会因为I/O阻塞而“空等待”,造成浪费。

NIO模型

tomcat的NIO模型,相比较于BIO模型,多了个Poller角色: Acceptor 、 Poller 和 Handler工作线程池 。这三个角色是不是很熟悉,如果将Poller换成Reactor,是不是就是Reactor模型。没错,tomcat的nio模型,的确就是基于 主从Reactor模型 ,只不过将Reactor换了个名字而已。

  • Acceptor :Accepter线程专门负责建立网络连接( accept )。新连接创建后,不是直接使用Worker线程处理请求,而是先将请求发送给Poller缓冲队列。

  • Poller :在Poller中,维护了一个Selector对象,当Poller从缓冲队列中取出连接后,注册到该Selector中,阻塞等待读写就绪( read等待就绪、send等待就绪 )。

  • Handlers :遍历Selector,找出其中就绪的IO操作,并交给Worker线程处理( read内存读、decode、process、encode、send内存写 )。

对比

  • BIO模型中,一个线程对应一个请求连接的完整过程,因此tomcat服务能处理的最大连接数,和最大线程数一致。

  • NIO模型中,在一个请求连接中,对应的一个工作线程,只处理I/O读写就绪后的非阻塞过程。因此tomcat服务能处理的最大连接数,要远大于最大线程数量。

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

在这里插入图片描述

最新整理电子书

在这里插入图片描述

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

4)]

最新整理电子书

[外链图片转存中…(img-hAgi8Z1U-1715599167534)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值