前面两节,我们分别看了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%,当然对于学习和研究,更高更快更强是技术追求的目的,这个就另当别论了。
工业4.0、中国制造2025等智能制造的主要概念与发展趋势分析
中兴宣布:与美国政府达成和解,同意支付近9亿美元罚款
NI点对点数据流技术在FPGA模块的实例
村田中国将携多款创新产品,亮相2023慕尼黑上海电子展
智能农药残留检测仪的相关性能描述
BIO连接器与NIO连接器的对比测试
探博M1受邀参加“青少年机器人与人工智能科普教育活动”
土壤养分速测仪的使用说明以及它的使用效果
日本新秀Rapidus:能追上台积电与英特尔!
江苏电信发挥5G网络及信息化技术优势,为各小区“定制化”建设智慧车棚
BUCK电路中电感伏秒平衡的表达式推导
Bsquare调查:很少有工业组织使用先进的分析技术来洞察物联网数据
麦道90机载变速恒频发电系统的谐波分析
1000小时高温老化试验怎么进行,高温老化试验怎么办理
实测数据分析 PCIe 4.0固态硬盘性能如何
某雷达天线方向图自动测试系统的软硬件原理详解
ESP32C3 LED PWM控制器的使用方法
提速降费政策更进一步 取消流量“漫游”费为5G铺路
对于VR技术,它到底是财富还是泡沫
可穿戴缺氧监控电路设计图