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

Tomcat 8(七)解读Bootstrap介绍过,Connector初始化/启动的时候,将初始化/启动内部的ProtocolHandler。其实ProtocolHandler只是个接口

ProtocolHandlerUML(以下这些类在org.apache.coyote包下)


创建Connector对象时,Connector的构造函数内会根据server.xmlConnector标签的配置创建ProtocolHandler(默为Http11NioProtocol)

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public Connector(String protocol) {  
  2.         setProtocol(protocol);  
  3.         // Instantiate protocol handler  
  4.         ProtocolHandler p = null;  
  5.         try {  
  6.             Class<?> clazz = Class.forName(protocolHandlerClassName);  
  7.             p = (ProtocolHandler) clazz.newInstance();  
  8.         } catch (Exception e) {  
  9.             log.error(sm.getString(  
  10.                     "coyoteConnector.protocolHandlerInstantiationFailed"), e);  
  11.         } finally {  
  12.             this.protocolHandler = p;  
  13.         }  
  14.    
  15.         if (!Globals.STRICT_SERVLET_COMPLIANCE) {  
  16.             URIEncoding = "UTF-8";  
  17.             URIEncodingLower = URIEncoding.toLowerCase(Locale.ENGLISH);  
  18.         }  
  19. }  

setProtocol(protocol)方法内容

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void setProtocol(String protocol) {  
  2.  //protocol对应server.xml的Connector标签的protocol属性  
  3.         if (AprLifecycleListener.isAprAvailable()) {  
  4.             if ("HTTP/1.1".equals(protocol)) {  
  5.                 setProtocolHandlerClassName  
  6.                     ("org.apache.coyote.http11.Http11AprProtocol");  
  7.             } else if ("AJP/1.3".equals(protocol)) {  
  8.                 setProtocolHandlerClassName  
  9.                     ("org.apache.coyote.ajp.AjpAprProtocol");  
  10.             } else if (protocol != null) {  
  11.                 setProtocolHandlerClassName(protocol);  
  12.             } else {  
  13.                 setProtocolHandlerClassName  
  14.                     ("org.apache.coyote.http11.Http11AprProtocol");  
  15.             }  
  16.         } else {  
  17.             if ("HTTP/1.1".equals(protocol)) {  
  18.                 setProtocolHandlerClassName  
  19.                     ("org.apache.coyote.http11.Http11NioProtocol");  
  20.             } else if ("AJP/1.3".equals(protocol)) {  
  21.                 setProtocolHandlerClassName  
  22.                     ("org.apache.coyote.ajp.AjpNioProtocol");  
  23.             } else if (protocol != null) {  
  24.                 setProtocolHandlerClassName(protocol);  
  25.             }  
  26.         }  
  27.    
  28.     }  

如果server.xml配置了AprLifecycleListener

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />  

AprLifecycleListener.isAprAvailable()true

Connector支持两种协议:HTTP/1.1和AJP/1.3

HTTP比较熟悉,在此不做说明了。AJP主要用于Tomcat的负载均衡,即Web Server(Apache可以通过AJP协议向Tomcat发请求

AJP(Apache JServ Protocol)是一种定向包协议用于将传入Web Server(Apache)request传递到处理具体业务的Application Server(如Tomcat

AJP的优点:

1. AJP使用二进制格式来传输可读性文本,Web Server通过TCP连接Application Server,较HTTP性能更高

2. 为了减少生成socket的开销,Web ServerApplication Server之间尝试保持持久性的TCP连接,对多个request/response循环重用一个连接

3. 一旦连接分配给一个特定的request,在该request完成之前不会再分配给其他request。因此,request在一个连接上是独占的,这使连接两端的编码变得简洁

4. 在连接上发送的基本请求信息是高度压缩的

AJP的缺点:

1. 某一时刻的连接数可能较多

2. HTTP Connector可以在Server.xml设置有效时间(connectionTimeout),而AJP Connector是永久有效

AJP协议的设计:http://httpd.apache.org/docs/2.2/mod/mod_proxy_ajp.html


下面来测试下HTTPAJP的性能

测试环境:win8.1 64位(4核、4G内存) + Tomcat8.0.3 64位 + jdk1.7.0_51 64位

压力测试工具:Apache ab

监控工具:Process Explorer、任务管理器

测试方法:在Tomcat\webapps\examples下创建index.jsp

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ page import="java.text.SimpleDateFormat"%>  
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  4. <html>  
  5.   <head>  
  6.     <title>Test</title>  
  7.   </head>  
  8.     
  9.   <body>  
  10.         Server Info:  
  11.   
  12.     <%  
  13.       String dtm = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());  
  14.       System.out.println("["+request.getLocalAddr()+":"+ request.getLocalPort()+"]" + dtm);  
  15.       out.println("<br>["+request.getLocalAddr()+":" +request.getLocalPort()+"]" + dtm+"<br>");   
  16.     %>  
  17.       
  18.     Session Info:  
  19.     <%  
  20.         session.setAttribute("name","dennisit");  
  21.         System.out.println("[Session Info] Session ID:"+session.getId());  
  22.         out.println("<br>[Session Info] Session ID:" + session.getId()+"<br>");  
  23.     %>  
  24.   </body>  
  25. </html>  

index.jsp的内容比较简单,就是获取Server信息和Session信息。Tomcat 8默认配置下,配置了AprLifecycleListener,监听8080端口的Connector使用HTTP/1.1协议;监听8009端口的Connector使用AJP/1.3协议,这两个端口默认使用apr模式。使用abHTTP Connector/AJP Connector发送10000个请求(并发量设为1000)

测试HTTP Connector的命令:ab -n 10000 -c 1000 localhost:8080/examples/index.jsp

测试AJP Connector的命令:ab -n 10000 -c 1000 localhost:8009/examples/index.jsp

以下数据是三次测试的平均值(注:每次只测一个Connector,每次测试都会重启Tomcat)

名词解释:

时间-处理完所有请求所用的时间(单位:s)

CPU-Java.exe进程的CPU占用峰值

内存-java.exe进程的内存占用峰值(单位:MB)

流量-处理请求期间的宽带占用(单位:kb/s)

测试结果:


通过上表可以看出,AJP处理请求稍快一点,但使用AJP时,CPU和内存占用更少,宽带占用几乎为0(由于使用AJP时,发送的基本请求信息是高度压缩。当然,也跟这个请求简单有关系)

所以,AJP Connector的性能更优

每个ProtocolHandler内部都有一个EndpointProtocolHandler初始化/启动的时候,将初始化/启动其内部的Endpoint

Tomcat有三种Endpoint:JIoEndpoint、NioEndpoint、AprEndpoint

ProtocolHandlerEndpoint的对应关系

Http11Protocol/AjpProtocol使用JIoEndpoint

Http11NioProtocol/AjpNioProtocol使用NioEndpoint

Http11AprProtocol/AjpAprProtocol使用AprEndpoint

Server.xmlConnector标签配置的部分属性(port),在Endpoint中才真正被使用。因此只有Endpoint启动了,Tomcat才开始监听指定端口

学习这三种Endpoint之前,需要了解下java iojava nio,可参考这两篇文章:

http://www.cnblogs.com/flyoung2008/p/3251826.html

http://tutorials.jenkov.com/java-nio/index.html

JIoEndpoint:使用java io(也称为bio)技术,即一个请求对应一个线程。缺点:并发量高时,线程数较多,占资源

NioEndpoint:使用java nio技术,可以通过少量的线程处理大量的请求

AprEndpointAprApache Portable Runtime,从操作系统层面解决io阻塞问题。使用Apr时将用到Tomcat\bin\tcnative-1.dll (使用Apr时,应用了jni技术)

Tomcat 8默认配置下,HTTP ConnectorAJP Connector均使用Apr。测试AprEndpoint,使用Tomcat 8的默认配置即可。测试JIoEndpointNioEndpoint需要将server.xml中的AprLifecycleListener注释掉

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!-- 
  2. <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> 
  3. -->  

并修改Connector标签的protocol属性

测试JIoEndpoint的配置:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <Connector port="8080" protocol="org.apache.coyote.http11.Http11Protocol "  
  2.                connectionTimeout="20000"  
  3.                redirectPort="8443" />  

测试NioEndpoint的配置:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol "  
  2.                connectionTimeout="20000"  
  3.                redirectPort="8443" />  

三种Endpoint的测试采用HTTP Connector 

测试结果: 


通过上表可以看出,Apr处理请求最快,Bio最慢;Apr宽带占用最高,Bio最低;但Apr的内存占用最高,而Nio的内存占用最低

所以综合来看,Nio适用于一般需求;Apr适用于高并发需求

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值