c.BIO连接器与NIO连接器的对比

前面两节,我们分别看了BIO和NIO的两种模式Tomcat的实现方式。

BIO的方式,就是传统的一线程,一请求的模式,也就是说,当同时又1000个请求过来,如果Tomcat设置了最大Accept线程数为500,那么第一批的500个线程直接进入线程池中进行执行,而其余500个根据Accept的限制的数量在服务器端的操作系统的内核位置的socket缓冲区进行阻塞,一直到前面500个线程处理完了之后,Acceptor组件再逐步的放进来。

分析一下,这种模式的BIO的好处,可以让一个请求在cpu轮转时间片切换中最大限度的执行,如果业务请求不是很长时间的事务处理,通常在一个时间片内肯定能做完当前的请求,这样的效率算是相当的高了,因为其减少了最耗时也是最头疼的线程上下文切换;

1.但是,如果事务执行比较长的时间,例如等待一个IO数据库的操作,那么这个工作线程就会根据cpu轮转不断的进行切换,因为请求数在大并发中很多,所以不得不设置一个很高的Accept线程数,那么从cpu的耗费的资源上来看,甚至有70%的时间浪费在线程切换中,而没有真正的时间去做请求处理和业务,这是第一个问题。

2.其次,BIO每一次链接的建立和释放都需要重新来过一遍,例如一个socket进来之后,通常会对其SocketOptions的属性进行设置,包括各种Connector中配置都要与其进行一一对应,加上前面说的socket的建立,很多请求通道的资源的初始化都得重新创建,得不到复用,这个是第二个问题。

3.最后,BIO方式网络IO的阻塞等待是会让Accept线程工作效率降低很多的。

所以,基于这3个问题,特别是最后一个问题,引出了NIO的模型。

NIO的架构分为三个线程池,这里再次梳理一下:

1.Acceptor专门接socket请求,当发现又请求进来后,基于Tomcat配置的SocketOptions和一些属性的设置完毕,包装成SocketChannel,也就是NIO的socket通道抽象,塞入PollerEvent直接扔到队列当中;

2.Poller线程从队列中挨个获取PollerEvent,调用Poller线程自己持有的selector选择器,注册SocketChannel到当前的selector选择器中,然后进行selectKey的工作,这样Acceptor传递过来的SocketChannel中感兴趣的事件,就会被轮询出来,当接收事件接收之后,需要注册OP_READ事件或者OP_WRITE事件,当OP_READ事件或者OP_WRITE事件发生时,开始调用工作线程池;

3.工作线程池就是SocketProcessor,这个就是具体的工作线程,SocketProcessor的任务就是Poller线程从SocketChannel通道中轮询出来的数据包,进行解析,传递给后端的handler进行http的解析,解析出来的Request,Reponse对象,,直接调用CoyoteAdapter传递到后端的容器,通过Mapper,映射到对应的业务Servlet中。可以看到,从SocketProcessor一直到最终的业务Servlet实现,这些都是一个线程,这个线程就是工作线程。

对比Tomcat的BIO的架构,因为没有selector轮询的操作,所以并没有Poller线程,BIO中的Acceptor线程的作用依然是对socket简单的处理和属性包装,然后将socket直接扔到工作线程中来。NIO相当于是多了一个线程池,从流程上来讲,应该是多了一道手续,但是通过NIO本身基于事件触发的机制造成,Acceptor线程没必要设置的过多,这样从线程的数量上来看,大大的减少线程切换的频率,其次基于事件进行触发,将Acceptor线程执行效率中的网络IO延迟降低到最低,大大提升了Acceptor线程的执行效率。从这两点上来看,Tomcat的NIO在前面分析的BIO的三个问题中第一个问题,和第三个问题都有所改善,特别是第三个问题,全面进行了升级。

但是,对于BIO中的第一个问题,由后端事务时间过长导致工作线程池一直在运行,并且运行在一个高峰的数值,不断的进行切换,这种问题,NIO通道也没办法进行处理,这个是由业务来决定的,NIO只能保证降低的是Acceptor线程线程数,对业务帮助也是无能为力的,如果要提升这部分的效率,那就需要应用进行修改,优化JDBC和数据库,或者将业务切段来做,让事务时间尽量控制在一个可控的范畴之内。

对于第二个问题,无论是单纯的NIO和BIO通道都没有办法进行解决,但是HTTP协议中对链接的复用进行更新,在HTTP1.1中,这个keepalive是加到http请求头中的:

Keep-Alive: timeout=5, max=100 
timeout:过期时间5秒(对应httpd.conf里的参数是:KeepAliveTimeout);

max是最多能承受一百次请求的共享复用,就是在timeout时间内又有新的连接过来,同时max会自动减1,直到为0,强制断掉。

对应的Tomcat的服务器端的配置:

keepAliveTimeout:表示在下次请求过来之前,tomcat保持该连接多久。这就是说假如客户端不断有请求过来,且为超过过期时间,则该连接将一直保持。

maxKeepAliveRequests:表示该连接最大支持的请求数。超过该请求数的连接也将被关闭(此时就会返回一个Connection: close头给客户端)。

如果配置了上述的内容,可以解决BIO上面提出的第二个问题,当一个页面中的第一个请求后,后面的连接可以复用这个socket或者是socketchannel,不用再accept三次握手或者SSL握手了,相当于高效的推动了整体Tomcat的时间链条的处理效率,而对于keepAlive属性的加入,通过BIO和NIO对比测试发现,相当于放大了NIO的优势,导致NIO的测试结果要明显高于BIO一个水平线上,这也就是目前http1.1协议中,为什么Tomcat后续版本默认就是NIO的原因;而如果没有keepAlive属性加入,在大多数的场景下,NIO并没有拉开与BIO太大的差距,甚至有一些场景上,Tomcat的BIO模式反倒是比NIO要高;

这里单纯的对比性能没有任何的意义,因为性能测试是测试在不同应用类型,不同硬件环境,不同软甲版本,甚至是不同jdk性能差异都很大,客观因素很多,而且Tomcat的web服务器目前在企业应用或者是互联网应用上来看,都是其链条中的微小的时间占比环节,甚至有的长事务处理链条中,Tomcat这块占比不到1%,当然对于学习和研究,更高更快更强是技术追求的目的,这个就另当别论了。

后续会详细分析一下keepAlive的实现,还有APR,NIO2两个通道的实现,敬请期待。

来自为知笔记(Wiz)

时间: 2024-10-14 04:12:26

c.BIO连接器与NIO连接器的对比的相关文章

d.BIO连接器与NIO连接器的对比之二

前面在Tomcat中讲解了两个通道,BIO和NIO,我们这里来通过两端程序,简单模拟两个通道,找找异同点: BIO: 1. public class SocketServer { public SocketServer() { try { int clientcount = 0; // 统计客户端总数 boolean listening = true; // 是否对客户端进行监听 ServerSocket server = null; // 服务器端Socket对象 try { // 创建一个S

Tomcat 8(十)HTTP/AJP Connector、Bio/Nio/Apr性能对比

Tomcat 8(七)解读Bootstrap介绍过,Connector初始化/启动的时候,将初始化/启动内部的ProtocolHandler.其实ProtocolHandler只是个接口 ProtocolHandler的UML图(以下这些类在org.apache.coyote包下) 创建Connector对象时,Connector的构造函数内会根据server.xml的Connector标签的配置创建ProtocolHandler(默为Http11NioProtocol) public Conn

Java--Stream,NIO ByteBuffer,NIO MappedByteBuffer性能对比

目前Java中最IO有多种文件读取的方法,本文章对比Stream,NIO ByteBuffer,NIO MappedByteBuffer的性能,让我们知道到底怎么能写出性能高的文件读取代码. package com.seeyon.nio; import org.junit.Test; import java.io.*; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.Fi

MTP连接器和MPO连接器简介

随着人们对更快的数据传输速度的要求越来越高,尽可能高效地传输数据的能力仍然是当今通信时代的主要力量.由于大多数现代数字信息系统的骨干网都是由光纤网络支撑的,因此人们越来越关注MPO光纤连接器和MTP光纤连接器. 什么是MPO和MTP连接器? MPO是"多光纤推进"的行业缩写.MPO连接器最初创建于20世纪末,是日本NTT公司开发的第一代夹持多芯光纤连接器,它可以方便地互连多股光纤并传输不断增加的数据量. 虽然MTP是美国康耐克公司的注册商标,作为"与普通MPO连接器相比,具有

tomcat 用nio连接器,建ssl安全协议配置

第一步:用连接器 <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/> 启用 <Connector executor="tomcatThreadPool" port="80" protocol="org.apach

java 的nio与io对比

转:本文并非Java.io或Java.nio的使用手册,也不是如何使用Java.io与Java.nio的技术文档.这里只是尝试比较这两个包,用最简单的方式突出它们的区别和各自的特性.Java.nio提出了新的流(stream)通讯概念并且加入了新的缓冲.文件流以及socket(套接字)特性. java.io 概览 这个包通过数据流和序列化机制来实现系统输入和输出.并且支持多种类型的数据流,包括简单的字节.原生数据类型.地区字符以及对象.流是一个数据的序列:一个程序使用输入流从一个源头读取数据:

Mina NIO与BIO了解及Telnet简单测试-Getting Started

原文地址:Mina user guide getting started 1.1.1. NIO回顾 1.1.1.1. NIO回顾 NIO API是java 1.4引入的,已经被大多数应用系统所采用.NIO API包含了非阻塞non-blocking应用操作. java.nio.*包中包含了以下关键的结构: l Buffers - 数据容器 l Chartsets -  bytes 和Unicode的翻译容器 l Channels - 代表连接与实体的IO操作能力 l Selectors - 提供

浅析BIO、NIO、AIO

BIO(Blocking I/O)同步阻塞I/O 这是最基本与简单的I/O操作方式,其根本特性是做完一件事再去做另一件事,一件事一定要等前一件事做完,这很符合程序员传统的顺序来开发思想,因此BIO模型程序开发起来较为简单,易于把握. 但是BIO如果需要同时做很多事情(例如同时读很多文件,处理很多tcp请求等),就需要系统创建很多线程来完成对应的工作,因为BIO模型下一个线程同时只能做一个工作,如果线程在执行过程中依赖于需要等待的资源,那么该线程会长期处于阻塞状态,我们知道在整个操作系统中,线程是

每天学习一点(tomcat连接器优化)

server.xml文件中的相关配置 http连接器优化 port TCP端口号.连接器将创建服务器套接字并等待传入连接.您的操作系统只允许一个服务器应用程序侦听特定IP地址上的特定端口号.如果使用特殊值0(零),那么Tomcat将随机选择一个空闲端口用于此连接器.这通常只在嵌入式和测试应用程序中有用. redirectPort 如果这个连接器支持非ssl请求,并且接收到一个匹配的请求.<security-constraint>需要SSL传输时,Catalina将自动将请求重定向到此处指定的端