Tomcat性能优化到底如何做?

Tomcat作为Web应用的服务器,目前绝大多数公司都是用其作为应用服务器的,应用服务器的执行效率会影响系统执行,这里会讲Tomcat怎样进行系统优化。

优化

对于Tomcat的优化,主要是从2个方面入手:

一是Tomcat自身的配置,另一个是Tomcat所运行的jvm虚拟机的调优。

硬件资源

服务器所能提供CPU、内存、硬盘的性能对处理能力有决定性影响。硬件我们不说了,这个方面是钱越多越好是吧。

Tomcat配置优化

管理界面

Linux环境安装运行Tomcat8,具体的安装步骤省略 (官网下载,解压即可)。

Tomcat官网

如果需要登录系统,必须配置tomcat用户,在安装完Tomcat后,进行如下操作

在/conf/tomcat-users.xml文件中的 标签里面添加如下内容


<!-- 修改配置文件,配置tomcat的管理用户 -->

<role rolename="manager"/>

<role rolename="manager-gui"/>

<role rolename="admin"/>

<role rolename="admin-gui"/>

<user username="tomcat" password="tomcat" roles="admin-gui,admin,manager-gui,manager"/>


Tomcat 运行模式

分3种模式:bio、nio、apr。一般使用nio模式。

bio效率低,apr对系统配置有一些比较高的要求。

确认 Tomcat 的运行模式

配置文件server.xml:


name="tomcatThreadPool"

   namePrefix="catalina-exec-"

   maxThreads="1024"

   minSpareThreads="512"

   prestartminSpareThreads="true" />


关键配置

maxThreads:最大线程数,默认是200。

minSpareThread:最小活跃线程数,默认是25。

maxQueueSize:最大的等待队列个数,超过则请求拒绝默认值是Integer.MAX_VALUE,一般不改变。在某些紧急状态修复问题需要调整。

连接器(Connector):Connector是连接器,负责接收客户的请求,以及向客户端回送响应的消息。所以Connector的优化是重要部分。默认情况下 Tomcat只支持200线程访问,超过这个数量的连接将被等待甚至超时放弃,所以我们需要提高这方面的处理能力。

/>

影响性能配置

protocol

org.apache.coyote.http11.Http11Protocol:阻塞式的Java连接器

org.apache.coyote.http11.Http11NioProtocol:不阻塞Java连接器

org.apache.coyote.http11.Http11AprProtocol:APR / native 连接器

选择不阻塞Java连接器。

enableLookups

若是你想request.getRemoteHost()的调用履行,以便返回的长途客户端的实际主机名的DNS查询,则设置为true。设置为false时跳过DNS查找,并返回字符串的IP地址(从而提高性能)。默认场景下,禁用DNS查找。

compression

设置成on,开启压缩。

禁用 AJP 链接器

使用Nginx+tomcat的架构,用不着AJP协议,所以把AJP连接器禁用。server.xml注释掉以下配置:

     <Connector port="8019" protocol="AJP/1.3" redirectPort="8443" />

优化JVM

/bin/catalina.sh:修改JAVA_OPTS参数,这里需要参照机器配置,对JVM进行参数优化。

JDK1.7:

JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms512m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=1024M -XX:PermSize=1024m -XX:MaxPermSize=1024m -XX:+DisableExplicitGC"

JDK1.8:

JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=1024M -XX:+DisableExplicitGC"

1.8 版本中已经没有PermSize、MaxPermSize。

JAVA8里对metaspace可以在小范围自动扩展永生代避免溢出。

参数说明

-Djava.awt.headless:没有设备、键盘或鼠标的模式。

-Dfile.encoding:设置字符集。

-server:jvm的server工作模式,对应的有client工作模式。使用java-version可以查看当前工作模式。

-Xms1024m:初始Heap大小,使用的最小内存。

-Xmx1024m:Java heap最大值,使用的最大内存。(经验:设置Xms大小等于Xmx大小)

-XX:NewSize=512m:表示新生代初始内存的大小,应该小于-Xms的值。

-XX:MaxNewSize=1024M:表示新生代可被分配的内存的最大上限,应该小于-Xmx的值。

-XX:PermSize=1024m:设定内存的永久保存区域,内存的永久保存区域,VM 存放Class 和 Meta 信息,JVM在运行期间不会清除该区域。程序加载很多class情况下,超出PermSize情况下:

JDK1.7会抛出java.lang.OutOfMemoryError: PermGen space异常

JDK1.8下会抛出 ERROR: java.lang.OutOfMemoryError: Metadata space 异常

-XX:MaxPermSize=1024m:设定最大内存的永久保存区域(经验:设置PermSize大小等于MaxPermSize大小)。

-XX:+DisableExplicitGC:自动将System.gc()调用转换成一个空操作,即应用中调用System.gc()会变成一个空操作,避免程序员在代码里进行System.gc()这种危险操作。System.gc()除非是到了万不得也的情况下使用,都交给JVM吧。

其他优化参数

XX:SurvivorRatio=2:年轻代中Eden区与Survivor区的大小比值。

-XX:ReservedCodeCacheSize=256m:保留代码占用的内存容量,无大的影响。

-Xss1024k:单个线程堆栈大小值,减少这个值可以生成更多线程,操作系统对于一个进程内的线程数是有限制的,经验值在3000-5000左右。

-XX:+CMSParallelRemarkEnabled:CMS 垃圾回收算法,对响应时间的重要性需求 大于 对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。

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

-XX:+UseCMSInitiatingOccupancyOnly:在FULL GC的时候, 对年老代的压缩。CMS是不会移动内存的, 因此这个非常容易产生碎片,导致内存不够用,因此,内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。可能会影响性能,但是可以消除碎片。

-XX:CMSInitiatingOccupancyFraction=60:使用cms作为垃圾回收,使用60%后开始CMS收集。

-XX:+UseGCOverheadLimit:用来限制使用内存,如果不做控制,可能会报出:java.lang.OutOfMemoryError:GC overhead limit exceeded。

-XX:+UseConcMarkSweepGC:使用CMS内存收集。

-XX:+UseParNewGC:设置年轻代为并行收集。

-XX:+HeapDumpOnOutOfMemoryError、-XX:HeapDumpPath=/x/dump_tomcat.hprof:JVM会在遇到OutOfMemoryError时拍摄一个“堆转储快照”,并将其保存在一个文件中。

-Xloggc:/xx/gc_tomcat.log:gc的日志,如果该日志中出现频繁的Full GC就是有相关的系统问题,如果很少,说明暂时还算正常。

-XX:+PrintGCDateStamps:输出GC的时间戳(以基准时间的形式)。

-XX:+PrintGCDetails:输出GC的日志格式

-Dnetworkaddress.cache.ttl=60、-Dsun.net.inetaddr.ttl=60:设置DNS缓存时间。

-DautoStartup=false、-Dsun.net.client.defaultConnectTimeout=60000:连接建立超时时间。

-Dsun.net.client.defaultReadTimeout=60000:内容获取超时设置。

-Djmagick.systemclassloader=no:是否生成缩略图的一个框架的配置。

最佳实践

<html>

<head></head>

<body>

  export JAVAOPTS=&quot;-server -showversion -Xms2000m -Xmx2000m -Xmn500m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:SurvivorRatio=2 -XX:ReservedCodeCacheSize=256m -Xss1024k -Djava.awt.headless=true -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=60 -XX:+UseGCOverheadLimit -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tomcatpath/logs/dumptomcat.hprof -Xloggc:/tomcatpath/logs/gc_tomcat.log -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCDetails -Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60 -DautoStartup=false -Dsun.net.client.defaultConnectTimeout=60000 -Dsun.net.client.defaultReadTimeout=60000 -Djmagick.systemclassloader=no -Djava.security.egd=file:/dev/./urandom -Dfile.encoding=UTF-8&quot;

</body>

</html>

常见JVM异常

java.lang.OutOfMemoryError: Java heap space:JVM Heap(堆)溢出

JVM 在启动的时候会自动设置 JVM Heap 的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)不可超过物理内存。可以利用 JVM提供的 -Xmn -Xms -Xmx 等选项可进行设置。Heap 的大小是 Young Generation 和 Tenured Generaion 之和。在 JVM 中如果 98% 的时间是用于 GC,且可用的 Heap size 不足 2% 的时候将抛出此异常信息。

解决方法:手动设置 JVM Heap(堆)的大小。

java.lang.OutOfMemoryError: PermGen space:PermGen space溢出

jdk1.8 抛出ERROR:java.lang.OutOfMemoryError:Metadataspace异常。

PermGen space 的全称是 Permanent Generation space,是指内存的永久保存区域。为什么会内存溢出,这是由于这块内存主要是被 JVM 存放Class 和 Meta 信息的,Class 在被 Load 的时候被放入 PermGen space 区域,它和存放 Instance 的 Heap 区域不同,sun 的 GC 不会在主程序运行期对 PermGen space 进行清理,所以如果你的 APP 会载入很多 CLASS 的话,就很可能出现 PermGen space 溢出。

解决方法: 手动设置MaxPermSize大小。

java.lang.StackOverflowError:栈溢出

栈溢出了,JVM 依然是采用栈式的虚拟机。函数的调用过程都体现在堆栈和退栈上了。调用构造函数的 “层”太多了,以致于把栈区溢出了。通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要 1K 的空间(这个大约相当于在一个 C 函数内声明了 256 个 int 类型的变量),那么栈区也不过是需要 1MB 的空间。通常栈的大小是 1-2MB 的。

解决方法:代码中递归也不要递归的层次过多。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354