tomcat之性能优化

  tomcat是我们常用的web容器,它的性能高低直接影响到应用对外提供服务的能力和用户的体验,所以tomcat的优化至关重要。对于单台tomcat服务器而言,优化主要是两方面:内存优化和配置优化(例如,连接数,线程池,iO等),当然还有使用tomcat原生库。除了这些tomcat本身固有配置优化,还有一些减少占用tomcat连接时间的配置,比如数据压缩。如果单个服务器经过优化后依然无法满足,性能要求,这时服务器集群就是必须的手段了,下面针对这些方面的优化详细介绍。

内存优化

  主要是针对jvm各个内存大小的分配进行优化,以提高内存的使用率和减少资源变化带来的时间消耗。有关文件:catalina.sh(linux下)或者catalina.bat(window下)。

  注意:对于32位操作系统上对jvm的内存有不能超过2G的限制,但是64位系统上没有这个限制。但很多情况下32操作系统上jvm的最大使用内存是不到2G的,2G只是个理想值,根据服务器的配置不同,可能有些只能用1500M或者1700M。具体支持多少,可以在控制台输入:java -Xmx2089M -version,如果出现Java版本,说明你的jvm内存可以设置到2089M。

Linux系统中tomcat的启动参数:

export JAVA_OPTS="-server -Xms1400M -Xmx1400M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=31 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC  -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m  -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true "

Windows系统中tomcat的启动参数:

set JAVA_OPTS=-server -Xms1400M -Xmx1400M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=31 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC  -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m  -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true
  •  -server

  这个参数必须加上,因为tomcat默认是以一种叫java –client的模式来运行的,server即意味着你的tomcat是以真实的production的模式在运行的,这也就意味着你的tomcat以server模式运行时将拥有:更大、更高的并发处理能力,更快更强捷的JVM垃圾回收机制等。

  • -Xms和–Xmx

  Xms是JVM初始化时的内存大小;Xmx是jvm的最大内存大小。Xms默认是物理内存的1/64,Xmx默认是物理内存的1/4,建议是物理内存的80%,但是一般我们会把Xms和Xmx设置一样大,这样在服务器启动时就是最大值可以避免内存膨胀和回落时带来的资源的消耗。特别是回落时会带来cpu的高速运转进行垃圾回收,系统可能会出现几秒甚至几十秒的卡顿现象。

  • –Xmn

  Xmn是年轻代大小。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

  •  -Xss

  是指设定每个线程的堆栈大小。这个就要依据你的程序,看一个线程 大约需要占用多少内存,可能会有多少线程同时运行等。一般不易设置超过1M,要不然容易出现out ofmemory。

  • -XX:+AggressiveOpts

  作用如其名(aggressive),启用这个参数,则每当JDK版本升级时,你的JVM都会使用最新加入的优化技术(如果有的话)

  • -XX:+UseBiasedLocking

  启用一个优化了的线程锁,我们知道在我们的appserver,每个http请求就是一个线程,有的请求短有的请求长,就会有请求排队的现象,甚至还会出现线程阻塞,这个优化了的线程锁使得你的appserver内对线程处理自动进行最优调配。

  • -XX:PermSize=128M和-XX:MaxPermSize=256M

  JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;在数据量的很大的文件导出时,一定要把这两个值设置上,否则会出现内存溢出的错误。由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。那么,如果是物理内存4GB,那么64分之一就是64MB,这就是PermSize默认值,也就是永生代内存初始大小;四分之一是1024MB,这就是MaxPermSize默认大小。

  • -XX:+DisableExplicitGC

在程序代码中不允许有显示的调用”System.gc()”。看到过有两个极品工程中每次在DAO操作结束时手动调用System.gc()一下,觉得这样做好像能够解决它们的out ofmemory问题一样,付出的代价就是系统响应时间严重降低,就和我在关于Xms,Xmx里的解释的原理一样,这样去调用GC导致系统的JVM大起大落,性能不到什么地方去哟!

  • -XX:+UseParNewGC

对年轻代采用多线程并行回收,这样收得快。

  • -XX:+UseConcMarkSweepGC

即CMS gc,这一特性只有jdk1.5即后续版本才具有的功能,它使用的是gc估算触发和heap占用触发。

我们知道频频繁的GC会造面JVM的大起大落从而影响到系统的效率,因此使用了CMS GC后可以在GC次数增多的情况下,每次GC的响应时间却很短,比如说使用了CMS GC后经过jprofiler的观察,GC被触发次数非常多,而每次GC耗时仅为几毫秒。

  • -XX:MaxTenuringThreshold

设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。

这个值的设置是根据本地的jprofiler监控后得到的一个理想的值,不能一概而论原搬照抄。

  • -XX:+CMSParallelRemarkEnabled

在使用UseParNewGC 的情况下, 尽量减少 mark 的时间

  • -XX:+UseCMSCompactAtFullCollection

在使用concurrent gc 的情况下, 防止 memoryfragmention, 对live object 进行整理, 使 memory 碎片减少。

  • -XX:LargePageSizeInBytes

指定 Java heap的分页页面大小

  • -XX:+UseFastAccessorMethods

get,set 方法转成本地代码

  • -XX:+UseCMSInitiatingOccupancyOnly

指示只有在 oldgeneration 在使用了初始化的比例后concurrent collector 启动收集

  • -XX:CMSInitiatingOccupancyFraction=70

  CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就不会出现promotion failed。在我的应用中Xmx是6000,Xmn是512,那么Xmx-Xmn是5488兆,也就是年老代有5488 兆,CMSInitiatingOccupancyFraction=90说明年老代到90%满的时候开始执行对年老代的并发垃圾回收(CMS),这时还 剩10%的空间是5488*10%=548兆,所以即使Xmn(也就是年轻代共512兆)里所有对象都搬到年老代里,548兆的空间也足够了,所以只要满 足上面的公式,就不会出现垃圾回收时的promotion failed;

因此这个参数的设置必须与Xmn关联在一起。

  •  -Djava.awt.headless=true

这个参数一般我们都是放在最后使用的,这全参数的作用是这样的,有时我们会在我们的J2EE工程中使用一些图表工具如:jfreechart,用于在web网页输出GIF/JPG等流,在winodws环境下,一般我们的app server在输出图形时不会碰到什么问题,但是在linux/unix环境下经常会碰到一个exception导致你在winodws开发环境下图片显示的好好可是在linux/unix下却显示不出来,因此加上这个参数以免避这样的情况出现。

配置优化

  主要是优化conf/server.xml文件中相关配置参数。

  • 连接器

  这里主要是优化connector标签中的相关参数,用于处理访问的请求;当然此标签中也可以设置线程的相关参数,但是为了更好的性能一般我们使用外部的线程池,这样有利于线程的复用,以减少线程的创建和销毁带来的资源消耗;另外,我们也可以修改tomcat的运行模式:BIO,NIO,AIO(NIO2),APR.

  1. 首先,我们需要禁用AJP协议

  AJP连接器:
  用于将Apache与Tomcat集成在一起,当Apache接收到动态内容请求时,通过在配置中指定的端口号将请求发送给在此端口号上监听的AJP连接器组件。
  属性:
    backlog:当所有可能的请求处理线程都在使用时,队列中排队的请求最大数目。默认为10,当队列已满,任何请求都将被拒绝
    maxSpareThread:允许存在空闲线程的最大数目,默认值为50
    maxThread:最大线程数,默认值为200
    minSpareThreads:设当连接器第一次启动时创建线程的数目,确保至少有这么多的空闲线程可用,默认值为4
    port:服务端套接字的TCP端口号,默认值为8089(必须)
    topNoDelay:为true时,可以提高性能,默认值为true
    soTimeout:超时值
    例:
    <!—Define an AJP1.3 Connector on port 8089-->
    <Connector port=”8089” enableLookups=”false” redirectPort=”8443” protocol=”AJP/1.3” />  

  AJPv13协议是面向包的。WEB服务器和Servlet容器通过TCP连接来交互;为了节省SOCKET创建的昂贵代价,WEB服务器会尝试维护一个永久TCP连接到servlet容器,并且在多个请求和响应周期过程会重用连接。我们一般是使用Nginx+tomcat的架构,所以用不着AJP协议,所以把AJP连接器禁用。

  

  2.Connector标签常见参数的配置:

<Connector port="8080" protocol="HTTP/1.1"
    //编码格式
       URIEncoding="UTF-8" 
    //线程配置
    maxThreads="1000" maxProcessors="1000" minProcessors="5" minSpareThreads="100" maxSpareThreads="1000
    //连接数配置
    maxConnections="1000"
    connectionTimeout="20000" acceptCount="1000"
    //是否关闭DNS的反响查询 false:关闭,true:开启
    enableLookups="false"
    //是否保持长时间连接,false:关闭,ture:开启
    disableUploadTimeout="true"
    //是否开启对url进行校验的配置 ,false:关闭,true:开启
    useURIValidationHack="false"
    //启用压缩的配置 
    compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"
    //post请求提交最大大小
    maxPostSize="10485760"

    acceptorThreadCount="8"
    redirectPort
="8443" />
  •  port:代表Tomcat监听端口,也就是网站的访问端口,默认为8080,可以根据需要改成其他。
  • protocol:协议类型,可选类型有四种,分别为BIO(阻塞型IO),NIO,NIO2和APR。

(1)BIO:BIO(Blocking I/O),顾名思义,即阻塞式I/O操作,表示Tomcat使用的是传统的Java I/O操作(即java.io包及其子包)。Tomcat在默认情况下,是以bio模式运行的。遗憾的是,就一般而言,bio模式是三种运行模式中性能最低的一种。BIO配置采用默认即可。

(2)NIO:NIO(New I/O),是Java SE 1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是一个基于缓冲区、并能提供非阻塞I/O操作的java API,因此nio也被看成是non-   blocking I/O的缩写。它拥有比传统I/O操作(bio)更好的并发运行性能。要让Tomcat以nio模式来运行也比较简单,我们只需要protocol类型修改为:

 //NIO
 protocol="org.apache.coyote.http11.Http11NioProtocol"
 //NIO2
 protocol="org.apache.coyote.http11.Http11Nio2Protocol"

     即可。

(3)APR:APR(Apache Portable Runtime/Apache可移植运行时),是Apache HTTP服务器的支持库。你可以简单地理解为:Tomcat将以JNI的形式调用 Apache HTTP服务器的核心动态链接库来处理文件读取或   网络传输操作,从而大大地提高 Tomcat对静态文件的处理性能。 

    与配置 NIO运行模式一样,也需要将对应的 Connector节点的 protocol属性值改为:protocol="org.apache.coyote.http11.Http11AprProtocol" 

     相关APR介绍及配置会在下面专门讲。

  • maxThreads:由该连接器创建的处理请求线程的最大数目,也就是可以处理的同时请求的最大数目。如果未配置默认值为200。如果一个执行器与此连接器关联,则忽略此属性,因为该属性将被忽略,所以该连接器将使用执行器而不是一个内部线程池来执行任务。但是这个值的是指和jvm内存和为每个线程所分配的内存大小有关
  • minSpareThreads:tomcat初始化时创建的线程数,线程的最小运行数目,这些始终保持运行。如果未指定,默认值为10。
  • maxSpareThreads:一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程.
  • acceptCount:当所有可能的请求处理线程都在使用时传入连接请求的最大队列长度。如果未指定,默认值为100。一般是设置的跟 maxThreads一样或一半,此值设置的过大会导致排队的请求超时而未被处理。所以这个值应该是主要根据应用的访问峰值与平均值来权衡配置。
  • maxConnections:在任何给定的时间内,服务器将接受和处理的最大连接数。当这个数字已经达到时,服务器将接受但不处理,等待进一步连接。NIO与NIO2的默认值为10000,APR默认值为8192。
  • connectionTimeout:当请求已经被接受,但未被处理,也就是等待中的超时时间。单位为毫秒,默认值为60000。通常情况下设置为30000。
  • maxHttpHeaderSize:请求和响应的HTTP头的最大大小,以字节为单位指定。如果没有指定,这个属性被设置为8192(8 KB)。
  • tcpNoDelay:如果为true,服务器socket会设置TCP_NO_DELAY选项,在大多数情况下可以提高性能。缺省情况下设为true。
  • compression:是否启用gzip压缩,默认为关闭状态。这个参数的可接受值为“off”(不使用压缩),“on”(压缩文本数据),“force”(在所有的情况下强制压缩)。
  • compressionMinSize:如果compression="on",则启用此项。被压缩前数据的最小值,也就是超过这个值后才被压缩。如果没有指定,这个属性默认为“2048”(2K),单位为byte。
  • disableUploadTimeout:这个标志允许servlet Container在一个servlet执行的时候,使用一个不同的,更长的连接超时。最终的结果是给servlet更长的时间以便完成其执行,或者在数据上载的时候更长的超时时间。如果没有指定,设为false。
  • enableLookups:关闭DNS反向查询。
  • URIEncoding:URL编码字符集。
  • maxPostSize:设置post提交内容大小。通过将此属性设置为小于零的值,可以禁用限制。如果未指定,则此属性设置为2097152(2兆字节)。
  • acceptorThreadCount:默认是1,一般调成和cpu的线程数保持一致,比如8线程的cpu,值就调成:8.

  当然Connector标签中的参数还有很多,这是只是常见的参数设置;并且这些中的参数也不一定都要设置,需要根据项目的具体情况去设置。

  • 线程池

   在介绍Connector标签中我们看到已经有线程的相关参数的设置,为什么还要有线程池?其实这个和Java中的线程池是一个道理,使用线程池可以使多连接公用线程,避免线程的频繁的创建和销毁带来的资源消耗。 

引入线程池的方法,使用Connector标签中的executor的属性,将其值设置为Executor标签的name的值。例如:

<Connector port="8066" executor="tomcatThreadPool" protocol="org.apache.coyote.http11.Http11NioProtocol"
            connectionTimeout="20000"  enableLookups="false" maxPostSize="10485760" URIEncoding="UTF-8" useBodyEncodingForURI="true" 
      acceptCount="100" acceptorThreadCount="2" disableUploadTimeout="true" maxConnections="10000" SSLEnabled="false" />
 <Executor name="tomcatThreadPool"   
         namePrefix="catalina-exec-"  maxThreads="1000" minSpareThreads="100" maxIdleTime="60000"  
         maxQueueSize="Integer.MAX_VALUE" prestartminSpareThreads="false" threadPriority="5"  
         className="org.apache.catalina.core.StandardThreadExecutor"/>  
  • io

  

压缩

tomcat原生库

猜你喜欢

转载自www.cnblogs.com/htyj/p/10491282.html