Tomcat的配置和优化

一、Tomcat之JVM内存查看

image-20191216141521299

点击Server Status,会弹出弹窗输入用户名、密码。点击取消,会显示如下页面。

image-20191216141654008

【配置管理员信息】:(Tomcat7示例)

1、打开tomcat7下的~/conf/tomcat-users.xml文件,关于用户角色、管理员的信息都在这个配置文件中。

2、在配置文件节点下添加如下xml:

1
2
3
<role rolename="admin-gui"/>
<role rolename="manager-gui"/>
<user username="admin" password="admin" roles="admin-gui,manager-gui"/>

3、启动tomcat,输入用户名:admin,密码:admin登录到管理员界面。访问网址:http://localhost:8080/manager/status

image-20191216143222579

(ps:上图是在windows下tomcat,最大堆内存为其物理内存的1/4。Linux下vim操作之设置行号:set nu

二、Tomcat之启动优化
1、概述

image-20191216173839300

2、修改参数

Linux环境下:大概在catalina.sh文件的97行(Windows是bat文件)

image-20191217091022392

修改内容如下:

image-20191217091038678

1
export JAVA_OPTS="-server -Xms1600M -Xmx1600M -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"

(ps:OPTS就是options选项的缩写。)

然后重启tomcat,查看是否生效命令:ps -ef|grep tomcat查看tomcat进程,找到进程号,执行Java堆内存映射命令jmap -heap 进程号(tomcat进程号) 来查看JVM内存信息。

( jdk安装后会自带一些小工具,jmap命令(Java Memory Map)是其中之一。主要用于打印指定Java进程(或核心文件、远程调试服务器)的共享对象内存映射或堆内存细节。)

image-20191217093730027

3、参数说明
  1. -server:启用jdk 的 server 版

    • 只要你的tomcat是运行在生产环境中的,这个参数必须添加 因为tomcat默认是以一种叫java –client的模式来运行的,server即意味着你的tomcat是以真实的production的模式在运行的,这也就意味着你的tomcat以server模式运行时将拥有: 更大、更高的并发处理能力,更快更强捷的JVM垃圾回收机制,可以获得更多的负载与吞吐量…
  2. -Xms -Xmx:-Xms:java虚拟机初始化时的最小堆内存;其初始空间(即-Xms)是物理内存的1/64。-Xmx:java虚拟机可使用的最大堆内存; 最大空间(-Xmx)是物理内存的1/4。

    • -Xmn 年轻代堆内存大小,此处是(eden+2 survivor space),默认为物理内存的1/64。
    • 可以利用JVM提供的-Xmn -Xms -Xmx等选项。要加“m”说明是MB,否则就是KB了,在启动tomcat时会报内存不足。
    • 把Xms与Xmx两个值设成一样是最优的做法。WHY?
      • 一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小。因为默认空余堆内存小于40% 时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的 最小限制。(这里40%和70%就是上图中的MinHeapFreeRatio 和 MaxHeapFreeRatio)
    • 如何知道我的JVM能够使用最大值:
      • image-20191217095935469
  3. -Xss:是指设定每个线程的栈大小。

    • 一般设置不超过1M,要不然容易出现out of memory。
  4. -XX:+AggressiveOpts :(优化时必须加)

    • 自带魔法属性,从单词可以看出,积极的、生猛的,也即可以将最新版的JDK优化后的新特性自动注入。(也就是JDK5、6、7、8等版本,由于JDK底层写的不一样,加上这个参数的效果可以将最新版的JDK优化后的新特性自动注入)
    • -XX表示开启属性参数。
  5. -XX:+UseBiasedLocking:(优化时必须加)

    • 启用一个优化了的线程锁,对于高并发访问很重要 ,太多的请求忙不过来它自动优化, 对于各自长短不一的请求,出现的阻塞、排队现象,他自己优化。
  6. -XX:PermSize -XX:MaxPermSize:(Java7及以前,Java8这里改成Metaspace即可)

    • -XX:PermSize设置Perm区的初始大小,默认是物理内存的1/64; 在数据量的很大的文件导出时,一定要把这两个值设置上,否则会出现内存溢出的错误
  • -XX:MaxPermSize设置Perm区的最大值,默认是32M,建议达到物理内存的1/4。
    • 存放的都是jvm初始化时加载器加载的一些类型信息(包括类信息、常量、静态变量等),这些信息的生存周期比较长,GC不会在主程序运行期对PermGen Space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen Space错误。
  1. -XX:MaxNewSize:设置新生代内存的最大内存值,默认是16M。(交给JDK去做就行,尽量不设。)

    • -XX:NewSize 设置新生代(年轻代)大小
  2. -XX:+DisableExplicitGC:(Explicit意思为显示的)

    • 在程序代码中不允许有显示的调用”System.gc()”,避免内存的大起大落。( System.gc()会启动重量级的垃圾回收线程,排队等待调度,而不是立即执行。比如main方法中有一个System.gc(),这里面存在两个线程,一个是main线程,一个是GC线程)
    • 忽略手动调用GC的代码使得 System.gc()的调用就会变成一个空调用,完全不会触发任何GC(即禁止用GC的意思)
  3. -XX:MaxTenuringThreshold:设置对象在新生代中存活的次数,设置垃圾最大年龄

    • 如果设置为零的话,则年轻代对象不经过Survivor区直接进入年老代。对于年老代比较多的应用,可以提高效率。
    • 如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代的存活时间,增加在年轻代即被回收的概率。
    • 这个值的设置是根据本地监控后得到的一个理想的值,不能一概而论原搬照抄
    • 默认为:15。
    • ps:上面配置中扩大了内存空间(-Xms1600M -Xmx1600M),生成养老区的对象年龄增大(-XX:MaxTenuringThreshold=31),减少了OOM出现的概率
  4. -Djava.awt.headless=true

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

  6. -XX:+HeapDumpOnOutOfMemoryError:

    • 表示当JVM发生OOM时,自动生成DUMP文件。
    • -XX:HeapDumpPath=${目录}参数表示生成DUMP文件的路径,也可以指定文件名称,例如:-XX:HeapDumpPath=${目录}/java_heapdump.hprof。如果不指定文件名,默认为:java_<pid>_<date>_<time>_heapDump.hprof。
  7. -XX:+UseConcMarkSweepGC:即CMS gc,这一特性只有jdk1.5即后续版本才具有的功能,它使用的是gc估算触发和heap占用触发。

    • 我们知道频频繁的GC会造面JVM的大起大落从而影响到系统的效率,因此使用了CMS GC后可以在GC次数增多的情况下,每次GC的响应时间却很短,比如说使用了CMS GC后经过jprofiler的观察,GC被触发次数非常多,而每次GC耗时仅为几毫秒
    • 添加该参数表示启动并发标识-清理(Mark-Sweep)回收器(CMS)
  8. -XX:+UseParNewGC :对年轻代采用多线程并行回收,这样收得快

  9. -XX:+CMSParallelRemarkEnabled:在使用UseParNewGC 的情况下, 尽量减少mark 的时间,降低标记停顿

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

  11. -XX:LargePageSizeInBytes:指定 Java heap的分页页面大小

  12. -XX:+UseFastAccessorMethods:get,set 方法转成本地代码

  13. -XX:+UseCMSInitiatingOccupancyOnly:指示只有在 old generation 在使用了初始化的比例后concurrent collector 启动收集

(上面12~19了解即可)

三、Tomcat之并发优化
1、修改配置

Linux环境下:/opt/tomcat7/conf下的server.xml文件中<Connector>节点的配置优化,记得先备份

默认出厂设置为:bio模式

image-20191217105934076

【标准版】优化修改:

1
2
3
4
5
6
7
8
<!--协议修改为NIO协议,添加连接相关常用参数: maxThreads、minSpareThreads、maxSpareThreads、acceptCount-->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="600"
minSpareThreads="100"
maxSpareThreads="500"
acceptCount="700"
connectionTimeout="20000"
redirectPort="8443" />

image-20191217113627637

【复杂情况】优化修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<Connector port="8080"
protocol="HTTP/1.1"
URIEncoding="UTF-8"
minSpareThreads="25"
maxSpareThreads="75"
enableLookups="false"
disableUploadTimeout="true"
connectionTimeout="20000"
acceptCount="300"
maxThreads="300"
maxProcessors="1000"
minProcessors="5"
useURIValidationHack="false"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/JavaScript,text/css,text/plain"
redirectPort="8443"/>

最后不要忘了把8443端口的地方也加上同样的配置,因为如果我们走https协议的话,我们将会用到8443端口这个段的配置。

image-20191217133527776

其他补充说明:指定JDK动态路径配置

一般情况下我们都是让Tomcat根据配置的java_home环境变量自动去找jdk路径,但是当同一台服务器下有不同的服务,且使用不同的jdk版本时就会出现问题。我们可以在catalina.sh脚本文件(Windows下为catalina.bat)中动态设置JAVA_HOME解决此问题。如:

image-20191217134617809

2、参数说明
  1. URIEncoding=”UTF-8”:使得tomcat可以解析含有中文名的文件的url

  2. minSpareThreads / maxSpareThreads:

    • minSpareThreads 最小备用线程数,tomcat启动时的初始化的线程数,默认10。

    • maxSpareThreads:最大备用线程数。一旦创建的线程超过这个值,Tomcat就会关闭不再需要的Socket线程。(比如PC端没有隐身状态的QQ,30分钟没说话头像变灰,因为既没有消息忘了,也没有消息发送。保证了连接的冗余容错有效性。)

  3. enableLookups:

    • 如果希望调用request.getRemoteHost()进行DNS查询,以返回远程客户的实际主机名,将enableLookups设为true。如果希望忽略DNS查询,仅仅返回IP地址,设为false(这样提高了性能)。
    • 缺省情况下,DNS查询是使能的。
    • 一句话:是否反查域名,取值为: true 或 false 。为了提高处理能力,应设置为 false。
  4. disableUploadTimeout:

    • disableUploadTimeout=“true”

    • 类似于Apache中的keeyalive一样,是否需要tomcat容器单独设置上传时间限制,这里是不用(设为true),还是使用标准的,不去给上传的附件单独做超时设置。

  5. connectionTimeout:网络连接超时,单位毫秒。设置为 -1 表示永不超时

  6. acceptCount

    • acceptCount是当线程数达到maxThreads后,后续请求会被放入一个等待队列,这个acceptCount是这个队列的大小,如果这个队列也满了,就直接refuse connection
    • 一句话:acceptCount:当处理任务的线程数达到最大时,接受排队的请求个数,默认100。指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。
  7. maxThreads:最大线程数,即同时处理的任务个数,默认值为200

    • Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数,即最大并发数。
    • 单机情况下保守推荐:600—900。如果是集群的话,可以配大一点。
  8. minProcessors / maxProcessors:

    • minProcessors :最小处理线程数。即使没有任何HTTP请求,TOMCAT也保持至少这么多线程以等待处理;默认值是5。
    • maxProcessors:最大处理线程数。如果系统中已经有这个数字的线程,那么,更多的连接请求将进入排队(上面说到的acceptCount等待队列)。默认值20。
    • 在 Java中线程是程序运行时的路径,是在一个程序中与其它控制线程无关的、能够独立运行的代码段。它们共享相同的地址空间。多线程帮助程序员写出CPU最大利用率的高效程序,使空闲时间保持最低,从而接受更多的请求。
    • 通常Windows是1000个左右,Linux是2000个左右。
  9. useURIValidationHack:

    • 减少它对一些url的不必要的检查从而减省开销,为提供性能可以设置为false。
  10. compression:设置是否开启GZip压缩。

  • compression=“on” 表示开启GZip压缩
  • HTTP 压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求网页后,从服务器端将网页文件压缩,再下载到客户端,由客户端的浏览器负责解压缩并浏览。相对于普通的浏览过程HTML、CSS、Javascript、Text ,它可以节省40%左右的流量。更为重要的是,它可以对动态生成的包括CGI、PHP 、JSP 、ASP、Servlet、SHTML等输出的网页也能进行压缩,压缩效率惊人。
  1. compressionMinSize:

    • compressionMinSize=“2048” 启用压缩的输出内容大小,这里面默认为2KB
  2. compressableMimeType:哪些类型需要压缩,默认是text/html,text/xml,text/plain

可以查看tomcat下的文档查看这些参数。

image-20191217133947118

3、超时控制

修改conf/web.xml配置文件,设置session-timeout的值(单位:分钟)。默认30

image-20191217134831321

综上,根据在catalina.sh文件调整内存(-Xms、-Xmx)、在server.xml调整并发访问量(maxThreads),一横向一纵向的优化。第一步先是纵向,先让其变胖,第二步是横向,让其扛得住并发,第三步变成APR,第四步让每一步很强的机器做成tomcat集群。

四、Tomcat之内存优化

查看%TOMCAT_HOME%\logs文件夹下,日志文件是否有内存溢出错误。(Linux环境下主要查看catalina.out总的输出文件和今天的日志文件catalina.yyyy-MM-dd.log)

linux命令查看:cat catalina.out(不知道cat命令的,可以使用man cat来查看具体命令说明)

  • 错误提示:java.lang.OutOfMemoryError: Java heap space

    • 导致原因:Tomcat默认可以使用的内存为128MB,在较大型的应用项目中,这点内存是不够的,有可能导致系统无法运行。常见的问题是报Tomcat内存溢出错误,Out of Memory(系统内存不足)的异常,从而导致客户端显示500错误,一般调整Tomcat的使用内存即可解决此问题。

    • 1
      2
      3
      4
      5
      6
      7
      //测试异常代码
      public static void main(String[] args)
      {
      System.out.println(Runtime.getRuntime().maxMemory()/1024/1024+" M");//假设当前物理内存是2G,默认最大堆内存就是2G/4=500M左右
      byte[] byteArray = new byte[1*1024*1024*650];//创建一个650M的大对象。这样就会报oom
      System.out.println("#######3");
      }
    • windows环境下修改:%TOMCAT_HOME%\bin\catalina.bat文件,在文件开头增加如下设置:

      • 1
        set JAVA_OPTS=-Dfile.encoding=UTF-8 -server -Xms1024m -Xmx2048m -XX:NewSize=512m -XX:MaxNewSize=1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=10 -XX:NewRatio=2 -XX:+DisableExplicitGC
    • Linux环境下修改:%TOMCAT_HOME%\bin\catalina.sh文件,在文件开头增加如下设置:

      • 1
        export JAVA_OPTS=-Xms2048m -Xmx2048m
  • 错误提示:java.lang.OutOfMemoryError: PermGen space

    • 错误原因:PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre-compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了

    • windows环境下修改:%TOMCAT_HOME%\bin\catalina.bat文件,在文件开头增加如下设置:

      • 1
        set JAVA_OPTS=-Xms256m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m - XX:MaxPermSize=256m
    • Linux环境下修改:%TOMCAT_HOME%\bin\catalina.sh文件,在文件开头增加如下设置:

      • 1
        export JAVA_OPTS=-Xms256m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m
五、Tomcat之BIO/NIO/APR三大模式
1、BIO

BIO是最稳定最老的一个连接器,是采用阻塞的方式,意味着每个连接线程绑定到每个Http请求,直到获得Http响应返回,如果Http客户端请求的是keep-Alive连接,那么这些连接也许一直保持着直至达到timeout时间,这期间不能用于其它请求。性能差但是最稳定。

使用方式:直接就是出厂默认:注意协议是HTTP/1.1。protocol="HTTP/1.1"

image-20191217144302119

2、NIO

NIO是使用Java的异步IO技术,不产生阻塞。nio(new I/O),是Java SE1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是一个基于缓冲区、并能提供非阻塞I/O操作的Java API,因此nio也被看成是non-blocking I/O的缩写。它拥有比传统I/O操作(bio)更好的并发运行性能。

使用方式:直接修改server.xml里的Connector节点,修改protocol为 : protocol="org.apache.coyote.http11.Http11NioProtocol"

3、APR

APR(Apache Portable Runtime)是使用原生C语言编写的非堵塞I/O,利用了操作系统的网络连接功能,速度很快。但是需先安装apr和native,若直接启动就支持apr,能大幅度提升性能,不亚于魔兽开局爆高科技兵种,威力强大。

使用方式:protocol="org.apache.coyote.http11.Http11AprProtocol"

思维导图文件参考

文章目录
  1. 1. Tomcat的配置和优化
    1. 1.1. 一、Tomcat之JVM内存查看
    2. 1.2. 二、Tomcat之启动优化
      1. 1.2.1. 1、概述
      2. 1.2.2. 2、修改参数
      3. 1.2.3. 3、参数说明
    3. 1.3. 三、Tomcat之并发优化
      1. 1.3.1. 1、修改配置
      2. 1.3.2. 2、参数说明
      3. 1.3.3. 3、超时控制
    4. 1.4. 四、Tomcat之内存优化
    5. 1.5. 五、Tomcat之BIO/NIO/APR三大模式
      1. 1.5.1. 1、BIO
      2. 1.5.2. 2、NIO
      3. 1.5.3. 3、APR
|