Tomcat调优

前言

Tomcat作为一个Java Servlet容器,用于运行Web应用程序,其性能和吞吐量对于确保应用程序的快速响应和高效运行至关重要。因此,Tomcat调优是为了最大限度地提高系统的性能和可扩展性,以满足高并发和大流量的需求。由于Tomcat的运行依赖于JVM,从虚拟机的角度把Tomcat的调整分为外部环境调优JVM和Tomcat自身调优两部分,当然操作系统(内核参数)也需要配合调整优化。

目录

一、JVM调优

1. JVM组成

1.1 JVM组成部分:

1.2 JVM运行时数据区域构成

1.3 虚拟机    

2. 垃圾回收

2.1 Garbage 垃圾确定方法

2.2 垃圾回收基本算法 

2.2.1 标记-清除 Mark-Sweep

2.2.2 标记压缩 (压实)Mark-Compact

2.2.3 复制 Copying

2.2.4 算法总结对比

2.2.5 STW

2.3 分代堆内存GC策略

2.3.1 堆内存分代

2.3.2 年轻代回收Minor GC

2.3.3 老年代回收 Major GC

2.4 Java内存调整相关参数

2.4.1 JVM 内存常用相关参数

2.4.2 JVM参数设置

二、Tomcat 配置文件参数优化

1. 常用的优化相关参数

2. 编辑全局配置 


一、JVM调优

1. JVM组成

1.1 JVM组成部分:

  • 类加载子系统: 使用Java语言编写.java Source Code文件,通过javac编译成.class Byte Code文件。class loader类加载器将所需所有类加载到内存,必要时将类实例化成实例
  • 运行时数据区: 最消耗内存的空间,需要优化
  • 执行引擎: 包括JIT (JustInTimeCompiler)即时编译器, GC垃圾回收器
  • 本地方法接口: 将本地方法栈通过JNI(Java Native Interface)调用Native Method Libraries, 比如:C,C++库等,扩展Java功能,融合不同的编程语言为Java所用

1.2 JVM运行时数据区域构成

  • Method Area (线程共享):方法区是所有线程共享的内存空间,存放已加载的类信息(构造方法,接口定义),常量(final),静态变量(static), 运行时常量池等。但实例变量存放在堆内存中. 从JDK8开始此空间由永久代改名为元空间
  • heap (线程共享):堆在虚拟机启动时创建,存放创建的所有对象信息。如果对象无法申请到可用内存将抛出OOM异常.堆是靠GC垃圾回收器管理的,通过-Xmx -Xms 指定最大堆和最小堆空间大小
  • Java stack (线程私有):Java栈是每个线程会分配一个栈,存放java中8大基本数据类型,对象引用,实例的本地变量,方法参数和返回值等,基于FILO()(First In Last Out),每个方法为一个栈帧 1 50 %
  • Program Counter Register (线程私有):PC寄存器就是一个指针,指向方法区中的方法字节码,每一个线程用于记录当前线程正在执行的字节码指令地址。由执行引擎读取下一条指令.因为线程需要切换,当一个线程被切换回来需要执行的时候,知道执行到哪里了
  • Native Method stack (线程私有):本地方法栈为本地方法执行构建的内存空间,存放本地方法执行时的局部变量、操作数等。

内存区域图示: 

1.3 虚拟机    

JVM(Java Virtual Machine)是Java虚拟机的缩写,是Java平台的核心组成部分之一。JVM是一个虚拟计算机,它提供了一个安全的、可移植的运行环境,使得Java程序可以在不同的操作系统和硬件平台上运行。

2. 垃圾回收

垃圾回收是JVM的一个重要特性,它负责回收不再使用的Java对象,以释放内存空间。JVM中的垃圾回收器会定期扫描堆内存中的对象,标记那些仍然被引用的对象,并回收那些没有被引用的对象。垃圾回收器可以自动管理内存,使得Java程序员不需要手动释放内存,从而减少了内存泄漏和内存溢出的风险。

2.1 Garbage 垃圾确定方法

  • 引用计数法:这种方法是通过给每个对象维护一个引用计数器,记录该对象被引用的次数,当引用计数器为0时,就可以判断该对象可以被回收。但是,这种方法无法解决循环引用的问题,即两个或多个对象相互引用,导致它们的引用计数器永远不为0,从而无法被回收。
  • 可达性分析法:这种方法是通过从一组称为"GC Roots"的对象开始,查找所有被这些对象直接或间接引用的对象,如果一个对象没有被GC Roots引用,则可以判断该对象可以被回收。在Java中,GC Roots包括虚拟机栈中引用的对象、方法区中静态变量引用的对象、方法区中常量引用的对象、本地方法栈中JNI引用的对象等等。

2.2 垃圾回收基本算法 

2.2.1 标记-清除 Mark-Sweep

分垃圾标记阶段和内存释放阶段。标记阶段,找到所有可访问对象打个标记。清理阶段,遍历整个堆,对未标记对象(即不再使用的对象)逐一进行清理。

注意:标记-清除最大的问题会造成内存碎片,但是不浪费空间,效率较高(如果对象较多,逐一删除效率也会影响)  

2.2.2 标记压缩 (压实)Mark-Compact

分垃圾标记阶段和内存整理阶段。标记阶段,找到所有可访问对象打个标记。内存清理阶段时,整理时将对象向内存一端移动,整理后存活对象连续的集中在内存一端。

注意:标记-压缩算法好处是整理后内存空间连续分配,有大段的连续内存可分配,没有内存碎片。缺点是内存整理过程有消耗,效率相对低下  

2.2.3 复制 Copying

先将可用内存分为大小相同两块区域A和B,每次只用其中一块,比如先用A区域。当A用完后,则将A中存活的对象复制到B。复制到B的时候连续的使用内存,最后将A一次性清除干净。缺点是比较浪费内存,只能使用原来一半内存,因为内存对半划分了,复制过程毕竟也是有代价。好处是没有碎片,复制过程中保证对象使用连续空间,且一次性清除所有垃圾,所以效率很高。

2.2.4 算法总结对比

在不同场景按需选择最合适的算法

  • 效率: 复制算法>标记清除算法> 标记压缩算法
  • 内存整齐度: 复制算法=标记压缩算法> 标记清除算法
  • 内存利用率: 标记压缩算法=标记清除算法>复制算法
2.2.5 STW

在JVM中,垃圾回收器会定期扫描堆内存中的对象,标记那些仍然被引用的对象,并回收那些没有被引用的对象。垃圾回收的过程中,会发生一种称为"Stop-The-World"(STW)的现象,即垃圾回收器会暂停应用程序的执行,以便进行垃圾回收。STW是垃圾回收器的一个缺点,因为它会导致应用程序的停顿时间变长,影响应用程序的性能和响应性。为了减少STW对应用程序的影响,JVM中的垃圾回收器采用了一些优化策略。

2.3 分代堆内存GC策略

2.3.1 堆内存分代

为了减少STW对应用程序的影响,JVM中的垃圾回收器采用了一些优化策略。分代垃圾回收策略将堆内存分为新生代、老年代和永久代三个部分,采用不同的垃圾回收算法进行处理,以减少垃圾回收的时间和空间开销,提高应用程序的性能和响应性。在实际应用中,我们需要根据应用程序的特点和需求选择合适的垃圾回收策略,并进行适当的调优,以获得更好的性能和稳定性。

说明: 

在JVM中,新生代内存被分为三个部分:Eden空间、From Survivor空间和To Survivor空间。这三个空间的作用如下:

  • Eden空间:是新创建对象的初始分配区域。当一个对象被创建时,它会被分配到Eden空间中。在Minor GC时,Eden空间中的存活对象会被复制到Survivor空间中,并清空Eden空间。
  • From Survivor空间和To Survivor空间:是用于存储在垃圾回收过程中存活的对象的。在Minor GC时,Eden空间中的存活对象会被复制到To Survivor空间中。在下一次Minor GC时,To Survivor空间中的存活对象会被复制到From Survivor空间中,同时将Eden空间和From Survivor空间中的对象清空。在这个过程中,垃圾回收器会根据对象的存活时间和大小等因素,将对象放到不同的Survivor空间中。

Heap堆内存分为:

  • 年轻代Young:Young Generation
  • 老年代Tenured:Old Generation, 长时间存活的对象  
2.3.2 年轻代回收Minor GC

Eden空间满时,会触发一次Minor GC(也称为Young GC),在这个过程中,垃圾回收器会扫描Eden空间和From Survivor空间中的对象,标记那些仍然被引用的对象,并将它们复制到To Survivor空间中。同时,垃圾回收器会清空Eden空间和From Survivor空间中的对象,以便下一次的对象分配。在Minor GC后,To Survivor空间变成了From Survivor空间,From Survivor空间变成了To Survivor空间。

① 标记存活对象:垃圾回收器会从根对象开始,标记所有在Eden空间和From Survivor空间中仍然被引用的对象。

② 复制存活对象:垃圾回收器会将标记为存活的对象复制到To Survivor空间中,并按照对象的年龄将对象放入相应的Survivor空间中。

③ 清空非存活对象:垃圾回收器会清空Eden空间和From Survivor空间中的非存活对象。

④ 空间交换:在Minor GC后,To Survivor空间变成了From Survivor空间,From Survivor空间变成了To Survivor空间。

通常场景下,大多数对象都不会存活很久,而且创建活动非常多,新生代就需要频繁垃圾回收。但是,如果一个对象一直存活,它最后就在from、to来回复制,如果from区中对象复制次数达到阈值(默认15次,CMS为6次,可通过java的选项 -XX:MaxTenuringThreshold=N 指定),就直接复制到老年代。

2.3.3 老年代回收 Major GC

老年代内存主要用于存放存活时间较长的对象。当老年代中的对象达到一定的数量时,会触发一次Major GC(也称为Full GC),在这个过程中,垃圾回收器会扫描整个堆内存中的对象,标记那些仍然被引用的对象,并将没有被引用的对象清除掉。

① 标记存活对象:垃圾回收器会从根对象开始,标记所有在堆内存中仍然被引用的对象。

② 清理非存活对象:垃圾回收器会清除所有没有被标记为存活的对象,并将空间释放出来。

③ 整理堆内存:垃圾回收器会将存活的对象移动到堆内存的一端,以便后续的对象分配。

④ 更新引用:垃圾回收器会更新所有存活对象的引用,使其指向正确的内存地址。

2.4 Java内存调整相关参数

2.4.1 JVM 内存常用相关参数

选项参数说明:

选项分类:

-选项名称:此为标准选项,所有HotSpot都支持

-X选项名称:为稳定的非标准选项

-XX:选项名称:非标准的不稳定选项,下一个版本可能会取消

参数说明示例
-Xms设置应用程序初始使用的堆内存大小(年轻代+老年代)-Xms2g
-Xmx设置应用程序能获得的最大堆内存早期JVM不建议超过32G,内存管理效率下降-Xms4g
-XX:NewSize设置初始新生代大小-XX:NewSize=128m
-XX:MaxNewSize设置最大新生代内存空间-XX:MaxNewSize=256m
-Xmnsize同时设置-XX:NewSize 和 -XX:MaxNewSize,代-Xmn1g
-XX:NewRatio以比例方式设置新生代和老年代-XX:NewRatio=2new/old=1/2
-XX:SurvivorRatio以比例方式设置eden和survivor(S0或S1)-XX:SurvivorRatio=6eden/survivor=6/1new/survivor=8/1
-Xss设置每个线程私有的栈空间大小,依据具体线程-Xss256k

标准选项:

[root@localhost ~]#java
用法: java [-options] class [args...]
           (执行类)
   或  java [-options] -jar jarfile [args...]
           (执行 jar 文件)
其中选项包括:
    -d32	  使用 32 位数据模型 (如果可用)
    -d64	  使用 64 位数据模型 (如果可用)
    -server	  选择 "server" VM
                  默认 VM 是 server,
                  因为您是在服务器类计算机上运行。


    -cp <目录和 zip/jar 文件的类搜索路径>
    -classpath <目录和 zip/jar 文件的类搜索路径>
                  用 : 分隔的目录, JAR 档案
                  和 ZIP 档案列表, 用于搜索类文件。
    -D<名称>=<值>
                  设置系统属性
    -verbose:[class|gc|jni]
                  启用详细输出
    -version      输出产品版本并退出
    -version:<值>
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  需要指定的版本才能运行
    -showversion  输出产品版本并继续
    -jre-restrict-search | -no-jre-restrict-search
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  在版本搜索中包括/排除用户专用 JRE
    -? -help      输出此帮助消息
    -X            输出非标准选项的帮助
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  按指定的粒度启用断言
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  禁用具有指定粒度的断言
    -esa | -enablesystemassertions
                  启用系统断言
    -dsa | -disablesystemassertions
                  禁用系统断言
    -agentlib:<libname>[=<选项>]
                  加载本机代理库 <libname>, 例如 -agentlib:hprof
                  另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
    -agentpath:<pathname>[=<选项>]
                  按完整路径名加载本机代理库
    -javaagent:<jarpath>[=<选项>]
                  加载 Java 编程语言代理, 请参阅 java.lang.instrument
    -splash:<imagepath>
                  使用指定的图像显示启动屏幕

非标准的稳定选项:

[root@localhost ~]#java -X
    -Xmixed           混合模式执行 (默认)
    -Xint             仅解释模式执行
    -Xbootclasspath:<用 : 分隔的目录和 zip/jar 文件>
                      设置搜索路径以引导类和资源
    -Xbootclasspath/a:<用 : 分隔的目录和 zip/jar 文件>
                      附加在引导类路径末尾
    -Xbootclasspath/p:<用 : 分隔的目录和 zip/jar 文件>
                      置于引导类路径之前
    -Xdiag            显示附加诊断消息
    -Xnoclassgc       禁用类垃圾收集
    -Xincgc           启用增量垃圾收集
    -Xloggc:<file>    将 GC 状态记录在文件中 (带时间戳)
    -Xbatch           禁用后台编译
    -Xms<size>        设置初始 Java 堆大小
    -Xmx<size>        设置最大 Java 堆大小
    -Xss<size>        设置 Java 线程堆栈大小
    -Xprof            输出 cpu 配置文件数据
    -Xfuture          启用最严格的检查, 预期将来的默认值
    -Xrs              减少 Java/VM 对操作系统信号的使用 (请参阅文档)
    -Xcheck:jni       对 JNI 函数执行其他检查
    -Xshare:off       不尝试使用共享类数据
    -Xshare:auto      在可能的情况下使用共享类数据 (默认)
    -Xshare:on        要求使用共享类数据, 否则将失败。
    -XshowSettings    显示所有设置并继续
    -XshowSettings:all
                      显示所有设置并继续
    -XshowSettings:vm 显示所有与 vm 相关的设置并继续
    -XshowSettings:properties
                      显示所有属性设置并继续
    -XshowSettings:locale
                      显示所有与区域设置相关的设置并继续

-X 选项是非标准选项, 如有更改, 恕不另行通知。

有不稳定选项的当前生效值:

[root@centos7 ~]#java -XX:+PrintFlagsFinal

查看所有不稳定选项的默认值:

[root@centos7 ~]#java -XX:+PrintFlagsInitial
2.4.2 JVM参数设置

默认的内存池空间大小:

① 查看默认状态页信息

② 修改现有内存池空间大小

[root@localhost ~]# vim /usr/local/tomcat/bin/catalina.sh
119 JAVA_OPTS="-server -Xms512m -Xmx512m -XX:NewSize=100m -XX:MaxNewSize=200m"
[root@localhost ~]# systemctl restart tomcat.service

-server:服务器模式
-Xms:堆内存初始化大小
-Xmx:堆内存空间上限
-XX:NewSize=:新生代空间初始化大小 
-XX:MaxNewSize=:新生代空间最大值

 ③ 再次查看状态页信息

二、Tomcat 配置文件参数优化

1. 常用的优化相关参数

【redirectPort】如果某连接器支持的协议是HTTP,当接收客户端发来的HTTPS   443 请求时,则转发至此属性定义的 8443 端口。

【maxThreads】Tomcat使用线程来处理接收的每个请求,这个值表示Tomcat可创建的最大的线程数,即支持的最大并发连接数,默认值是 200。

【minSpareThreads】最小空闲线程数,Tomcat 启动时的初始化的线程数,表示即使没有人使用也开这么多空线程等待,默认值是 10。

【maxSpareThreads】最大备用线程数,一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。默认值是-1(无限制)。一般不需要指定。

【processorCache】进程缓冲器,可以提升并发请求。默认值是200,如果不做限制的话可以设置为-1,一般采用maxThreads的值或者-1。

【URIEncoding】指定 Tomcat 容器的 URL 编码格式,网站一般采用UTF-8作为默认编码。

【connnectionTimeout】网络连接超时,单位:毫秒,设置为 0 表示永不超时,这样设置有隐患的。通常默认 20000 毫秒就可以。

【enableLookups】是否反查域名,以返回远程主机的主机名,取值为:true 或 false,如果设置为 false,则直接返回 IP 地址,为了提高处理能力,应设置为 false。

【disableUploadTimeout】上传时是否使用超时机制。应设置为 true。

【connectionUploadTimeout】上传超时时间,毕竟文件上传可能需要消耗更多的时间,这个根据你自己的业务需要自己调,以使Servlet有较长的时间来完成它的执行,需要与上一个参数一起配合使用才会生效。

【acceptCount】指定当所有可以使用的处理请求的线程数都被使用时,可传入连接请求的最大队列长度,超过这个数的请求将不予处理,默认为 100 个。

【maxKeepAliveRequests】指定一个长连接的最大请求数。默认长连接是打开的,设置为1时,代表关闭长连接;为-1时,代表请求数无限制

【compression】是否对响应的数据进行GZIP压缩,off:表示禁止压缩;on:表示允许压缩(文本将被压缩)、force:表示所有情况下都进行压缩,默认值为 off,压缩数据后可以有效的减少页面的大小,一般可以减小 1/3 左右,节省带宽。

【compressionMinSize】表示压缩响应的最小值,只有当响应报文大小大于这个值的时候才会对报文进行压缩,如果开启了压缩功能,默认值就是 2048。

【compressableMimeType】压缩类型,指定对哪些类型的文件进行数据压缩。

【noCompressionUserAgents="gozilla, traviata"】对于以下的浏览器,不启用压缩
#如果已经进行了动静分离处理,静态页面和图片等数据就不需做 Tomcat 处理,也就不要在 Tomcat 中配置压缩了。

2. 编辑全局配置 

vim /usr/local/tomcat/conf/server.xml
......
<Connector port="8080" protocol="HTTP/11.1" 
connectionTimeout="20000" 
redirectPort="8443" 
--71行--插入
minSpareThreads="50" 
enableLookups="false" 
disableUploadTimeout="true" 
acceptCount="300" 
maxThreads="500" 
processorCache="500"
URIEncoding="UTF-8" 
maxKeepAliveRequests="100"
compression="on" 
compressionMinSize="2048" 
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,image/gif,image /jpg,image/png"/>
  • 25
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是Tomcat面试题的答案: 1. Tomcat的缺省端口是多少,怎么修改? Tomcat的缺省端口是8080,可以通过修改server.xml文件中的Connector节点来修改端口号。 2. tomcat 有哪几种Connector 运行模式(化)? Tomcat有三种Connector运行模式:BIO、NIO和APR。其中,BIO是传统的阻塞式I/O模式,NIO是非阻塞式I/O模式,APR是使用本地库实现的高性能模式。 3. Tomcat有几种部署方式? Tomcat有两种部署方式:WAR包部署和目录部署。WAR包部署是将应用程序打包成WAR包,然后将WAR包放到Tomcat的webapps目录下;目录部署是将应用程序解压到Tomcat的webapps目录下。 4. tomcat容器是如何创建servlet类实例?用到了什么原理? Tomcat容器在启动时会扫描web.xml文件,将其中的servlet类加载到内存中,并创建servlet实例。Tomcat使用Java反射机制来创建servlet实例。 5. tomcat 如何化? Tomcat化可以从多个方面入手,包括内存、垃圾回收策略、共享session处理、添加JMS远程监控、使用专业的分析工具等。 6. 内存 可以通过整JVM的内存参数来进行内存,例如-Xms和-Xmx参数可以分别设置JVM的初始内存和最大内存。 7. 垃圾回收策略 可以通过整JVM的垃圾回收策略来进行垃圾回收策略,例如使用CMS垃圾回收器或G1垃圾回收器。 8. 共享session处理 可以使用集中式session管理方案,例如使用Redis等缓存服务器来存储session数据,从而实现session共享。 9. 添加JMS远程监控 可以使用JMX来进行远程监控,例如使用JConsole等工具来监控Tomcat的运行状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值