您的位置:首页 > 运维架构 > Tomcat

浅析tomcat nio 配置

2015-12-17 12:38 495 查看

tomcat的运行模式有3种.修改他们的运行模式.3种模式的运行是否成功,可以看他的启动控制台,或者启动日志.或者登录他们的默认页面http://localhost:8080/查看其中的服务器状态。

1)bio

默认的模式,性能非常低下,没有经过任何优化处理和支持.

2)nio

利用java的异步io护理技术,noblockingIO技术.

想运行在该模式下,直接修改server.xml里的Connector节点,修改protocol为

<Connectorport="80"protocol="org.apache.coyote.http11.Http11NioProtocol"
	connectionTimeout="20000"
	URIEncoding="UTF-8"
	useBodyEncodingForURI="true"
	enableLookups="false"
	redirectPort="8443"/>

启动后,就可以生效。

3)apr

安装起来最困难,但是从操作系统级别来解决异步的IO问题,大幅度的提高性能.

必须要安装apr和native,直接启动就支持apr。下面的修改纯属多余,仅供大家扩充知识,但仍然需要安装apr和native

如nio修改模式,修改protocol为org.apache.coyote.http11.Http11AprProtocol



Tomcat6.X实现了JCP的Servlet2.5和JSP2.1的规范,并且包括其它很多有用的功能,使它成为开发

和部署web应用和web服务的坚实平台。

NIO(No-blockingI/O)从JDK1.4起,NIOAPI作为一个基于缓冲区,并能提供非阻塞I/O操作的API

被引入。

作为开源web服务器的java实现,tomcat几乎就是web开发者开发、测试的首选,有很多其他商业服务

器的开发者也会优先选择tomcat作为开发时候使用,而在部署的时候,把应用发布在商业服务器上。也有

许多商业应用部署在tomcat上,tomcat承载着其核心的应用。但是很多开发者很迷惑,为什么在自己的应

用里使用tomcat作为平台的时候,而并发用户超过一定数量,服务器就变的非常繁忙,而且很快就出现了

connectionrefuse的错误。但是很多商业应用部署在tomcat上运行却安然无恙。

其中有个很大的原因就是,配置良好的tomcat都会使用APR(ApachePortableRuntime),APR是

ApacheHTTPServer2.x的核心,它是高度可移植的本地库,它使用高性能的UXINI/O操作,低性能的

javaio操作,但是APR对很多Java开发者而言可能稍稍有点难度,在很多OS平台上,你可能需要重新编

译APR。但是从Tomcat6.0以后,Java开发者很容易就可以是用NIO的技术来提升tomcat的并发处理能力。

但是为什么NIO可以提升tomcat的并发处理能力呢,我们先来看一下java传统io与javaNIO的差别。



Java传统的IO操作都是阻塞式的(blockingI/O),如果有socket的编程基础,你会接触过堵塞socket和

非堵塞socket,堵塞socket就是在accept、read、write等IO操作的的时候,如果没有可用符合条件的资

源,不马上返回,一直等待直到有资源为止。而非堵塞socket则是在执行select的时候,当没有资源的时

候堵塞,当有符合资源的时候,返回一个信号,然后程序就可以执行accept、read、write等操作,一般来

说,如果使用堵塞socket,通常我们通常开一个线程acceptsocket,当读完这次socket请求的时候,开一

个单独的线程处理这个socket请求;如果使用非堵塞socket,通常是只有一个线程,一开始是select状,

当有信号的时候可以通过可以通过多路复用(Multiplexing)技术传递给一个指定的线程池来处理请求,然

后原来的线程继续select状态。最简单的多路复用技术可以通过java管道(Pipe)来实现。换句话说,如果

客户端的并发请求很大的时候,我们可以使用少于客户端并发请求的线程数来处理这些请求,而这些来不

及立即处理的请求会被阻塞在java管道或者队列里面,等待线程池的处理。请求听起来很复杂,在这个架

构当道的java世界里,现在已经有很多优秀的NIO的架构方便开发者使用,比如Grizzly,ApacheMina等

等,如果你对如何编写高性能的网络服务器有兴趣,你可以研读这些源代码。

简单说一下,在web服务器上阻塞IO(BIO)与NIO一个比较重要的不同是,我们使用BIO的时候往往会

为每一个web请求引入多线程,每个web请求一个单独的线程,所以并发量一旦上去了,线程数就上去

了,CPU就忙着线程切换,所以BIO不合适高吞吐量、高可伸缩的web服务器;而NIO则是使用单线程(单

个CPU)或者只使用少量的多线程(多CPU)来接受Socket,而由线程池来处理堵塞在pipe或者队列里的请

求.这样的话,只要OS可以接受TCP的连接,web服务器就可以处理该请求。大大提高了web服务器的可

伸缩性。

我们来看一下配置,你只需要在server.xml里把HTTPConnector做如下更改,

<Connectorport="8080"protocol="HTTP/1.1"

connectionTimeout="20000"

redirectPort="8443"/>

改为

<Connectorport="8080"protocol="org.apache.coyote.http11.Http11NioProtocol"

connectionTimeout="20000"

redirectPort="8443"/>

然后启动服务器,你会看到org.apache.coyote.http11.Http11NioProtocolstart的信息,表示NIO已经启动。其他的配置请参考官方配置文档。

Enjoyit.

最后贴上官方文档上对tomcat的三种Connector的方式做一个简单比较,



JavaBlockingConnectorJavaNioBlockingConnectorAPRConnector

ClassnameHttp11ProtocolHttp11NioProtocolHttp11AprProtocol

TomcatVersion3.x4.x5.x6.x6.x5.5.x6.x

SupportPollingNOYESYES

PollingSizeN/AUnlimited-RestrictedbymemUnlimited

ReadHTTPRequestBlockingBlockingBlocking

ReadHTTPBodyBlockingBlockingBlocking

WriteHTTPResponseBlockingBlockingBlocking

SSLSupportJavaSSLJavaSSLOpenSSL

SSLHandshakeBlockingNonblockingBlocking

MaxConnectionsmaxThreadsSeepollingsizeSeepollingsize



如果读者有socket的编程基础,应该会接触过堵塞socket和非堵塞socket,堵塞socket就是在accept、read、write等IO操作的的时候,如果没有可用符合条件的资源,不马上返回,一直等待直到有资源为止。而非堵塞socket则是在执行select的时候,当没有资源的时候堵塞,当有符合资源的时候,返回一个信号,然后程序就可以执行accept、read、write等操作,这个时候,这些操作是马上完成,并且马上返回。而windows的winsock则有所不同,可以绑定到一个EventHandle里,也可以绑定到一个HWND里,当有资源到达时,发出事件,这时执行的io操作也是马上完成、马上返回的。一般来说,如果使用堵塞socket,通常我们时开一个线程acceptsocket,当有socket链接的时候,开一个单独的线程处理这个socket;如果使用非堵塞socket,通常是只有一个线程,一开始是select状态,当有信号的时候马上处理,然后继续select状态。
  
  按照大多数人的说法,堵塞socket比非堵塞socket的性能要好。不过也有小部分人并不是这样认为的,例如Indy项目(Delphi一个比较出色的网络包),它就是使用多线程+堵塞socket模式的。另外,堵塞socket比非堵塞socket容易理解,符合一般人的思维,编程相对比较容易。
  
  nio其实也是类似上面的情况。在JDK1.4,sun公司大范围提升Java的性能,其中NIO就是其中一项。Java的IO操作集中在java.io这个包中,是基于流的阻塞API(即BIO,BlockIO)。对于大多数应用来说,这样的API使用很方便,然而,一些对性能要求较高的应用,尤其是服务端应用,往往需要一个更为有效的方式来处理IO。从JDK1.4起,NIOAPI作为一个基于缓冲区,并能提供非阻塞O操作的API(即NIO,non-blockingIO)被引入。
  
  BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。
  
  这个时候,问题就出来了:我们非常多的java应用是使用ThreadLocal的,例如JSF的FaceContext、Hibernate的session管理、Struts2的Context的管理等等,几乎所有框架都或多或少地应用ThreadLocal。如果存在冲突,那岂不惊天动地?
  
  后来终于在Tomcat6的文档(http://tomcat.apache.org/tomcat-6.0-doc/aio.html)找到答案。根据上面说明,应该Tomcat6应用nio只是用在处理发送、接收信息的时候用到,也就是说,tomcat6还是传统的多线程Servlet,我画了下面两个图来列出区别:
  
  tomcat5:客户端连接到达->传统的SeverSocket.accept接收连接->从线程池取出一个线程->在该线程读取文本并且解析HTTP协议->在该线程生成ServletRequest、ServletResponse,取出请求的Servlet->在该线程执行这个Servlet->在该线程把ServletResponse的内容发送到客户端连接->关闭连接。
  
  我以前理解的使用nio后的tomcat6:客户端连接到达->nio接收连接->nio使用轮询方式读取文本并且解析HTTP协议(单线程)->生成ServletRequest、ServletResponse,取出请求的Servlet->直接在本线程执行这个Servlet->把ServletResponse的内容发送到客户端连接->关闭连接。
  
  实际的tomcat6:客户端连接到达->nio接收连接->nio使用轮询方式读取文本并且解析HTTP协议(单线程)->生成ServletRequest、ServletResponse,取出请求的Servlet->从线程池取出线程,并在该线程执行这个Servlet->把ServletResponse的内容发送到客户端连接->关闭连接。 
  
  
  从上图可以看出,BIO与NIO的不同,也导致进入客户端处理线程的时刻有所不同:tomcat5在接受连接后马上进入客户端线程,在客户端线程里解析HTTP协议,而tomcat6则是解析完HTTP协议后才进入多线程,另外,tomcat6也比5早脱离客户端线程的环境。
  
  实际的tomcat6与我之前猜想的差别主要集中在如何处理servlet的问题上。实际上即使抛开ThreadLocal的问题,我之前理解tomcat6只使用一个线程处理的想法其实是行不同的。大家都有经验:servlet是基于BIO的,执行期间会存在堵塞的,例如读取文件、数据库操作等等。tomcat6使用了nio,但不可能要求servlet里面要使用nio,而一旦存在堵塞,效率自然会锐降。
   
  
  所以,最终的结论当然是tomcat6的servlet里面,ThreadLocal照样可以使用,不存在冲突。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: