系统优化怎么作-Tomcat优化

前言

Tomcat做为Web应用的服务器,目前绝大多数公司都是用其做为应用服务器的,应用服务器的执行效率会影响系统执行,这里会讲Tomcat怎样进行配置能提升处理性能。另外必须提到对应的JVM参数的优化的一些经验。java

Tomcat运行模式

分3种模式: bio,nio,apr 通常使用nio模式
bio效率低,apr对系统配置有一些比较高的要求程序员

确认Tomcat的运行模式

配置文件 server.xml算法

<Executor name="tomcatThreadPool" 
namePrefix="catalina-exec-" 
maxThreads="1024" 
minSpareThreads="512" 
prestartminSpareThreads="true" />

关键配置

maxThreadsapache

最大线程数, 默认是200

minSpareThread缓存

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

maxQueueSizetomcat

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

链接器(Connector)服务器

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

nio配置- server.xml

<Connector port="14081" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
executor="tomcatThreadPool" 
URIEncoding="UTF-8" 
compression="on"   
useBodyEncodingForURI="true" 
enableLookups="false" 
redirectPort="14443" />

影响性能配置

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
是否生成缩略图的一个框架的配置
  • -Djava.security.egd=file:/dev/./urandom

最佳实践

export JAVA_OPTS="-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=/tomcat_path/logs/dump_tomcat.hprof -Xloggc:/tomcat_path/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"

常见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: Metadata space 异常
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 的。

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

思考题

线上应用系统出现问题,怎么快速定位系统哪块资源问题?