【⾯试总结】-tomcat调优⽅案
⼀、Tomcat本⾝的优化
Tomcat 的⾃⾝参数的优化,这块很像 ApacheHttp Server。修改⼀下 xml 配置⽂件中的参数,调整最⼤连接数,超时等。此外,我们安装 Tomcat 是,优化就已经开始了。
1、⼯作⽅式选择
为了提升性能,⾸先就要对代码进⾏动静分离,让 Tomcat 只负责 jsp ⽂件的解析⼯作。如采⽤ Apache 和 Tomcat 的整合⽅式,他们之间的连接⽅案有三种选择,JK、http_proxy 和 ajp_proxy。相对于 JK 的连接⽅式,后两种在配置上⽐较简单的,灵活性⽅⾯也⼀点都不逊⾊。但就稳定性⽽⾔不像JK 这样久经考验,所以建议采⽤ JK 的连接⽅式。
2、Connector连接器的配置
之前⽂件介绍过的 Tomcat 连接器的三种⽅式: bio、nio 和 apr,三种⽅式性能差别很⼤,apr 的性能最优, bio 的性能最差。⽽Tomcat 7 使⽤的 Connector  默认就启⽤的 Apr 协议,但需要系统安装 Apr 库,否则就会使⽤ bio ⽅式。
3、配置⽂件优化
配置⽂件优化其实就是对 l 优化,可以提⼤⼤提⾼ Tomcat 的处理请求的能⼒,下⾯我们来看 Tomcat 容器内的优化。
默认配置下,Tomcat 会为每个连接器创建⼀个绑定的线程池(最⼤线程数 200),服务启动时,默认创建了 5 个空闲线程随时等待⽤户请求。
⾸先,打开 ${TOMCAT_HOME}/l,搜索【<Executor name="tomcatThreadPool"】,开启并调整为
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="500" minSpareThreads="20" maxSpareThreads="50" maxIdleTime="60000"/>
注意, Tomcat 7 在开启线程池前,⼀定要安装好 Apr 库,并可以启⽤,否则会有错误报出,shutdown.sh 脚本⽆法关闭进程。
然后,修改<Connector …>节点,增加 executor 属性,搜索【port="8080"】,调整为
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
URIEncoding="UTF-8"
connectionTimeout="30000"
enableLookups="false"
disableUploadTimeout="false"
connectionUploadTimeout="150000"
acceptCount="300"
keepAliveTimeout="120000"
maxKeepAliveRequests="1"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,image/gif,image/jpg,image/png"
redirectPort="8443" />
maxThreads :Tomcat 使⽤线程来处理接收的每个请求,这个值表⽰ Tomcat 可创建的最⼤的线程数,默认值是 200 minSpareThreads:最⼩空闲线程数,Tomcat 启动时的初始化的线程数,表⽰即使没有⼈使⽤也开这么多空线程等待,默认值是 10。maxSpareThreads:最⼤备⽤线程数,⼀旦创建的线程超过这个值,Tomcat 就会关闭不再需要的 socket 线程。
上边配置的参数,最⼤线程 500(⼀般服务器⾜以),要根据⾃⼰的实际情况合理设置,设置越⼤会耗费内存和 CPU,因为 CPU 疲于线程上下⽂切换,没有精⼒提供请求服务了,最⼩空闲线程数 20,线程最⼤空闲时间 60 秒,当然允许的最⼤线程连接数还受制于操作系统的内核参数设置,设置多⼤要根据⾃⼰的需求与环境。当然线程可以配置在“tomcatThreadPool”中,也可以直接配置
在“Connector”中,但不可以重复配置。
URIEncoding:指定 Tomcat 容器的 URL 编码格式,语⾔编码格式这块倒不如其它 WEB 服务器软件配置⽅便,需要分别指定。
connnectionTimeout: ⽹络连接超时,单位:毫秒,设置为 0 表⽰永不超时,这样设置有隐患的。通常可设置为 30000 毫秒,可根据检测实际情况,适当修改。
enableLookups: 是否反查域名,以返回远程主机的主机名,取值为:true 或 false,如果设置为false,则直接返回IP地址,为了提⾼处理能⼒,应设置为 false。
disableUploadTimeout:上传时是否使⽤超时机制。
connectionUploadTimeout:上传超时时间,毕竟⽂件上传可能需要消耗更多的时间,这个根据你⾃⼰的业务需要⾃⼰调,以使Servlet 有较长的时间来完成它的执⾏,需要与上⼀个参数⼀起配合使⽤才会⽣效。
acceptCount:指定当所有可以使⽤的处理请求的线程数都被使⽤时,可传⼊连接请求的最⼤队列长度,超过这个数的请求将不予处理,默认为100个。
keepAliveTimeout:长连接最⼤保持时间(毫秒),表⽰在下次请求过来之前,Tomcat 保持该连接多久,默认是使⽤connectionTimeout 时间,-1 为不限制超时。
maxKeepAliveRequests:表⽰在服务器关闭之前,该连接最⼤⽀持的请求数。超过该请求数的连接也将被关闭,1表⽰禁⽤,-1表⽰不限制个数,默认100个,⼀般设置在100~200之间。
compression:是否对响应的数据进⾏ GZIP 压缩,off:表⽰禁⽌压缩;on:表⽰允许压缩(⽂本将被压缩)、force:表⽰所有情况下都进⾏压缩,默认值为off,压缩数据后可以有效的减少页⾯的⼤⼩,⼀
般可以减⼩1/3左右,节省带宽。
compressionMinSize:表⽰压缩响应的最⼩值,只有当响应报⽂⼤⼩⼤于这个值的时候才会对报⽂进⾏压缩,如果开启了压缩功能,默认值就是2048。
compressableMimeType:压缩类型,指定对哪些类型的⽂件进⾏数据压缩。
noCompressionUserAgents="gozilla, traviata": 对于以下的浏览器,不启⽤压缩。
如果已经对代码进⾏了动静分离,静态页⾯和图⽚等数据就不需要 Tomcat 处理了,那么也就不需要配置在 Tomcat 中配置压缩了。
以上是⼀些常⽤的配置参数属性,当然还有好多其它的参数设置,还可以继续深⼊的优化,HTTP Connector 与 AJP Connector 的参数属性值,可以参考官⽅⽂档的详细说明:
⼆、JVM 优化
Tomcat 启动命令⾏中的优化参数,就是 JVM 的优化 。Tomcat ⾸先跑在 JVM 之上的,因为它的启动其实也只是⼀个 java 命令⾏,⾸先我们需要对这个 JAVA 的启动命令⾏进⾏调优。不管是 YGC 还是 Full GC,GC 过程中都会对导致程序运⾏中中断,正确的选择不同的GC 策略,调整 JVM、GC 的参数,可
以极⼤的减少由于 GC ⼯作,⽽导致的程序运⾏中断⽅⾯的问题,进⽽适当的提⾼ Java 程序的⼯作效率。但是调整 GC 是以个极为复杂的过程,由于各个程序具备不同的特点,如:web 和 GUI 程序就有很⼤区别(Web可以适当的停顿,但GUI停顿是客户⽆法接受的),⽽且由于跑在各个机器上的配置不同(主要 cup 个数,内存不同),所以使⽤的 GC 种类也会不同。
1、JVM 参数配置⽅法
Tomcat 的启动参数位于安装⽬录 ${JAVA_HOME}/bin⽬录下,Linux 操作系统就是 catalina.sh ⽂件。JAVA_OPTS,就是⽤来设置JVM 相关运⾏参数的变量,还可以在 CATALINA_OPTS 变量中设置。关于这 2 个变量,还是多少有些区别的:
JAVA_OPTS:⽤于当 Java 运⾏时选项“start”、“stop”或“run”命令执⾏。
CATALINA_OPTS:⽤于当 Java 运⾏时选项“start”或“run”命令执⾏。
为什么有两个不同的变量?它们之间都有什么区别呢?
⾸先,在启动 Tomcat 时,任何指定变量的传递⽅式都是相同的,可以传递到执⾏“start”或“run”命令中,但只有设定在
JAVA_OPTS 变量⾥的参数被传递到“stop”命令中。对于 Tomcat 运⾏过程,可能没什么区别,影响的是结束程序,⽽不是启动程序。
第⼆个区别是更微妙,其他应⽤程序也可以使⽤ JAVA_OPTS 变量,但只有在 Tomcat 中使⽤ CATALINA_OPTS 变量。如果你设置环境变量为只使⽤ Tomcat,最好你会建议使⽤ CATALINA_OPTS 变量,⽽如果你设置环境变量使⽤其它的 Java 应⽤程序,例如 JBoss,你应该把你的设置放在JAVA_OPTS 变量中。
2、JVM 参数属性
32 位系统下 JVM 对内存的限制:不能突破 2GB ,那么这时你的 Tomcat 要优化,就要讲究点技巧了,⽽在 64 位操作系统上⽆论是系统内存还是 JVM 都没有受到 2GB 这样的限制。
针对于 JMX 远程监控也是在这⾥设置,以下为 64 位系统环境下的配置,内存加⼊的参数如下:
为了看着⽅便,将每个参数单独写⼀⾏。上⾯参数好多啊,可能有⼈写到现在都没见过⼀个在 Tomcat 的启动命令⾥加了这么多参数,当然,这些参数只是我机器上的,不⼀定适合你,尤其是参数后的 value(值)是需要根据你⾃⼰的实际情况来设置的。
上述这样的配置,基本上可以达到:
系统响应时间增快;
JVM回收速度增快同时⼜不影响系统的响应率;
JVM内存最⼤化利⽤;
线程阻塞情况最⼩化。
JVM 常⽤参数详解:
-server:⼀定要作为第⼀个参数,在多个 CPU 时性能佳,还有⼀种叫 -client 的模式,特点是启动速度⽐较快,但运⾏时性能和内存管理效率不⾼,通常⽤于客户端应⽤程序或开发调试,在 32 位环境下直接运⾏ Java 程序默认启⽤该模式。Server 模式的特点是启动速度⽐较慢,但运⾏时性能和内存管理效率很⾼,适⽤于⽣产环境,在具有 64 位能⼒的 JDK 环境下默认启⽤该模式,可以不配置该参数。
-Xms:表⽰ Java 初始化堆的⼤⼩,-Xms 与-Xmx 设成⼀样的值,避免 JVM 反复重新申请内存,导致性能⼤起⼤落,默认值为物理内存的 1/64,默认(MinHeapFreeRatio参数可以调整)空余堆内存⼩于 40% 时,JVM 就会增⼤堆直到 -Xmx 的最⼤限制。
-Xmx:表⽰最⼤ Java 堆⼤⼩,当应⽤程序需要的内存超出堆的最⼤值时虚拟机就会提⽰内存溢出,并
且导致应⽤服务崩溃,因此⼀般建议堆的最⼤值设置为可⽤内存的最⼤值的80%。如何知道我的 JVM 能够使⽤最⼤值,使⽤ java -Xmx512M -version 命令来进⾏测试,然后逐渐的增⼤ 512 的值,如果执⾏正常就表⽰指定的内存⼤⼩可⽤,否则会打印错误信息,默认值为物理内存的 1/4,默认(MinHeapFreeRatio参数可以调整)空余堆内存⼤于 70% 时,JVM 会减少堆直到-Xms 的最⼩限制。
-Xss:表⽰每个 Java 线程堆栈⼤⼩,JDK 5.0 以后每个线程堆栈⼤⼩为 1M,以前每个线程堆栈⼤⼩为 256K。根据应⽤的线程所需内存⼤⼩进⾏调整,在相同物理内存下,减⼩这个值能⽣成更多的线程,但是操作系统对⼀个进程内的线程数还是有限制的,不能⽆限⽣成,经验值在 3000~5000 左右。⼀般⼩的应⽤, 如果栈不是很深, 应该是128k 够⽤的,⼤的应⽤建议使⽤ 256k 或 512K,⼀般不易设置超过 1M,要不然容易出现out ofmemory。这个选项对性能影响⽐较⼤,需要严格的测试。
java设置环境变量的方法代码-XX:NewSize:设置新⽣代内存⼤⼩。
-XX:MaxNewSize:设置最⼤新⽣代新⽣代内存⼤⼩
-XX:PermSize:设置持久代内存⼤⼩
-XX:MaxPermSize:设置最⼤值持久代内存⼤⼩,永久代不属于堆内存,堆内存只包含新⽣代和⽼年代。
-
XX:+AggressiveOpts:作⽤如其名(aggressive),启⽤这个参数,则每当 JDK 版本升级时,你的 JVM 都会使⽤最新加⼊的优化技术(如果有的话)。
-XX:+UseBiasedLocking:启⽤⼀个优化了的线程锁,我们知道在我们的appserver,每个http请求就是⼀个线程,有的请求短有的请求长,就会有请求排队的现象,甚⾄还会出现线程阻塞,这个优化了的线程锁使得你的appserver内对线程处理⾃动进⾏最优调配。
-XX:+DisableExplicitGC:在 程序代码中不允许有显⽰的调⽤“()”。每次在到操作结束时⼿动调⽤ () ⼀下,付出的代价就是系统响应时间严重降低,就和关于 Xms,Xmx ⾥的解释的原理⼀样,这样去调⽤ GC 导致系统的 JVM ⼤起⼤落。
-XX:+UseConcMarkSweepGC:设置年⽼代为并发收集,即 CMS gc,这⼀特性只有 jdk1.5
后续版本才具有的功能,它使⽤的是 gc 估算触发和 heap 占⽤触发。我们知道频频繁的 GC 会造⾯ JVM
的⼤起⼤落从⽽影响到系统的效率,因此使⽤了 CMS GC 后可以在 GC 次数增多的情况下,每次 GC 的响应时间却很短,⽐如说使⽤了CMS
GC 后经过 jprofiler 的观察,GC 被触发次数⾮常多,⽽每次 GC 耗时仅为⼏毫秒。
-XX:+UseParNewGC:对新⽣代采⽤多线程并⾏回收,这样收得快,注意最新的 JVM 版本,当使⽤ -XX:+UseConcMarkSweepGC 时,-XX:UseParNewGC 会⾃动开启。因此,如果年轻代的并⾏ GC 不想开启,可以通过设置 -XX:-UseParNewGC 来关掉。
-XX:MaxTenuringThreshold:设置垃圾最⼤年龄。如果设置为0的话,则新⽣代对象不经过 Survivor 区,直接进⼊⽼年代。对于⽼年代⽐较多的应⽤(需要⼤量常驻内存的应⽤),可以提⾼效率。如果将此值设置为⼀ 个较⼤值,则新⽣代对象会在 Survivor 区进⾏多次复制,这样可以增加对象在新⽣代的存活时间,增加在新⽣代即被回收的概率,减少Full GC的频率,这样做可以在某种程度上提⾼服务稳定性。该参数只有在串⾏ GC 时才有效,这个值的设置是根据本地的 jprofiler 监控后得到的⼀个理想的值,不能⼀概⽽论原搬照抄。
-XX:+CMSParallelRemarkEnabled:在使⽤ UseParNewGC 的情况下,尽量减少 mark 的时间。
-XX:+UseCMSCompactAtFullCollection:在使⽤ concurrent gc 的情况下,防⽌ memoryfragmention,对 live object 进⾏整理,使 memory 碎⽚减少。
-XX:LargePageSizeInBytes:指定 Java heap 的分页页⾯⼤⼩,内存页的⼤⼩不可设置过⼤, 会影响 Perm 的⼤⼩。
-XX:+UseFastAccessorMethods:使⽤ get,set ⽅法转成本地代码,原始类型的快速优化。
-XX:+UseCMSInitiatingOccupancyOnly:只有在 oldgeneration 在使⽤了初始化的⽐例后 concurrent collector 启动收集。
-Duser.timezone=Asia/Shanghai:设置⽤户所在时区。
-Djava.awt.headless=true:这个参数⼀般我们都是放在最后使⽤的,这全参数的作⽤是这样的,有时我们会在我们的 J2EE ⼯程中使⽤⼀些图表⼯具如:jfreechart,⽤于在 web ⽹页输出 GIF/JPG 等流,在 winodws 环境下,⼀般我们的 app server 在输出图形时不会碰到什么问题,但是在linux/unix 环境下经常会碰到⼀个 exception 导致你在 winodws 开发环境下图⽚显⽰的好好可是在 linux/unix 下却显⽰不出来,因此加上这个参数以免避这样的情况出现。
-Xmn:新⽣代的内存空间⼤⼩,注意:此处的⼤⼩是(eden+ 2 survivor space)。与 jmap -heap 中显⽰的 New gen 是不同的。整个堆⼤⼩ = 新⽣代⼤⼩ + ⽼⽣代⼤⼩ + 永久代⼤⼩。在保证堆⼤⼩不变的情况下,增⼤新⽣代后,将会减⼩⽼⽣代⼤⼩。此值对系统性能影响较⼤,Sun官⽅推荐配置为整个堆的 3/8。
-XX:CMSInitiatingOccupancyFraction:当堆满之后,并⾏收集器便开始进⾏垃圾收集,例如,当没有⾜够的空间来容纳新分配或提升的对象。对于 CMS 收集器,长时间等待是不可取的,因为在并发垃圾收集期间应⽤持续在运⾏(并且分配对象)。因此,为了在应⽤程序使⽤完内存之前完成垃圾收集周期,
CMS 收集器要⽐并⾏收集器更先启动。因为不同的应⽤会有不同对象分配模式,JVM 会收集实际的对象分配(和释放)的运⾏时数据,并且分析这些数据,来决定什么时候启动⼀次 CMS 垃圾收集周期。这个参数设置有很⼤技巧,基本上满⾜(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100 >= Xmn 就不会出现 promotion failed。例如在应⽤中 Xmx 是
6000,Xmn 是 512,那么 Xmx-Xmn 是 5488M,也就是⽼年代有 5488M,CMSInitiatingOccupancyFraction=90 说明⽼年代到90% 满的时候开始执⾏对⽼年代的并发垃圾回收(CMS),这时还 剩 10% 的空间是 5488*10% = 548M,所以即使 Xmn(也就是新⽣代共512M)⾥所有对象都搬到⽼年代⾥,548M 的空间也⾜够了,所以只要满⾜上⾯的公式,就不会出现垃圾回收时的 promotion failed,因此这个参数的设置必须与 Xmn 关联在⼀起。
-XX:+CMSIncrementalMode:该标志将开启 CMS 收集器的增量模式。增量模式经常暂停 CMS 过程,以便对应⽤程序线程作出完全的让步。因此,收集器将花更长的时间完成整个收集周期。因此,只有通过测试后发现正常 CMS 周期对应⽤程序线程⼲扰太⼤时,才应该使⽤增量模式。由于现代服务器有⾜够的处理器来适应并发的垃圾收集,所以这种情况发⽣得很少,⽤于但 CPU情况。
-XX:NewRatio:年轻代(包括 Eden 和两个 Survivor 区)与年⽼代的⽐值(除去持久代),-XX:NewRatio=4 表⽰年轻代与年⽼代所占⽐值为 1:4,年轻代占整个堆栈的 1/5,Xms=Xmx 并且设置了 Xmn 的情况下,该参数不需要进⾏设置。
-XX:SurvivorRatio:Eden 区与 Survivor 区的⼤⼩⽐值,设置为 8,表⽰ 2 个 Survivor 区(JVM 堆内存年轻代中默认有 2 个⼤⼩相等的 Survivor 区)与 1 个 Eden 区的⽐值为 2:8,即 1 个 Survivor 区占整个年轻代⼤⼩的 1/10。
-XX:+UseSerialGC:设置串⾏收集器。
-XX:+UseParallelGC:设置为并⾏收集器。此配置仅对年轻代有效。即年轻代使⽤并⾏收集,⽽年⽼代仍使⽤串⾏收集。
-XX:+UseParallelOldGC:配置年⽼代垃圾收集⽅式为并⾏收集,JDK6.0 开始⽀持对年⽼代并⾏收集。
-XX:ConcGCThreads:早期 JVM 版本也叫-XX:ParallelCMSThreads,定义并发 CMS 过程运⾏时的线程数。⽐如 value=4 意味着CMS 周期的所有阶段都以 4 个线程来执⾏。尽管更多的线程会加快并发 CMS 过程,但其也会带来额外的同步开销。因此,对于特定的应⽤程序,应该通过测试来判断增加 CMS 线程数是否真的能够带来性能的提升。如果还标志未设置,JVM 会根据并⾏收集器中的 -
XX:ParallelGCThreads 参数的值来计算出默认的并⾏ CMS 线程数。
-XX:ParallelGCThreads:配置并⾏收集器的线程数,即:同时有多少个线程⼀起进⾏垃圾回收,此值建议配置与 CPU 数⽬相等。
-XX:OldSize:设置 JVM 启动分配的⽼年代内存⼤⼩,类似于新⽣代内存的初始⼤⼩ -XX:NewSize。
以上就是⼀些常⽤的配置参数,有些参数是可以被替代的,配置思路需要考虑的是 Java 提供的垃圾回收机制。虚拟机的堆⼤⼩决定了虚拟机花费在收集垃圾上的时间和频度。收集垃圾能够接受的速度和应⽤有关,应该通过分析实际的垃圾收集的时间和频率来调整。假如堆的⼤⼩很⼤,那么完全垃圾收集就会很慢,但是频度会降低。假如您把堆的⼤⼩和内存的需要⼀致,完全收集就很快,但是会更加频繁。调整堆⼤⼩的的⽬的是最⼩化垃圾收集的时间,以在特定的时间内最⼤化处理客户的请求。在基准测试的时候,为确保最好的性能,要把堆的⼤⼩设⼤,确保垃圾收集不在整个基准测试的过程中出现。
假如系统花费很多的时间收集垃圾,请减⼩堆⼤⼩。⼀次完全的垃圾收集应该不超过 3-5 秒。假如垃圾收集成为瓶颈,那么需要指定代的⼤⼩,检查垃圾收集的周详输出,研究垃圾收集参数对性能的影响。当增加处理器时,记得增加内存,因为分配能够并⾏进⾏,⽽垃圾收集不是并⾏的。
3、设置系统属性

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。