Tomcat的优化及OOM问题

Posted njsummer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tomcat的优化及OOM问题相关的知识,希望对你有一定的参考价值。

1. Tomcat优化

在目前流行的互联网架构中,Tomcat在网络编程中有着举足轻重的地位,Tomcat的调优可以从两个维度去考虑:一是外部环境调优;二是Tomcat的运行依赖的JVM和Tomcat 自身调优。


1.1 Tomcat调优--外部环境维度

  • 根据业务模型,规划最佳的架构,并优化。比如:Tomcat集群的引入、前端反向代理的采用、动静分离等。
  • Tomcat 只是作为JAVA程序运行空间,JAVA程序自身的优化也是提高Tomcat性能的重要因素。
  • 服务器硬件的优选,高带宽内存、高缓存CPU、高读写的磁盘(固态硬盘),解决性能短板。
  • 利用缓存和压缩技术:静态页面可采用缓存技术,提高响应速度,将图片、css、js文件都进行了缓存,有效的减少了后端tomcat的重复任务。
  • 提高网络性能:选用更大带宽和速率的网络技术,比如:40G、80G、100G等,提高服务器之间数据交互,也提高客户端的访问性能。
  • 虚拟化和容器化技术:鉴于Tomcat自身的因素,一台 tomcat 服务器并发连接数无法堆砌得很高,按照惯例一般生产建议8G左右一个虚拟机或者容器跑Tomcat比较被推荐,如果一台服务器物理内存很高,可以通过虚拟化技术或者容器技术实现多台tomcat集群,来完成前端的大并发用户请求。


1.2 Tomcat调优--JVM运行环境等内部配置维度

1.2.1 内存空间优化

Tomcat是运行在JVM上的,对JVM的调优也尤为重要。

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

# tomcat服务器并发连接数不高,生产建议分配物理内存通常4G到8G较多
[root@CentOS84 ~]#cat/usr/local/tomcat/bin/catalina.sh
JAVA_OPTS="-server -Xms4g -Xmx4g -Xss512k -Xmn1g -
XX:CMSInitiatingOccupancyFraction=65 -XX:+AggressiveOpts -XX:+UseBiasedLocking -
XX:+DisableExplicitGC -XX:MaxTenuringThreshold=10 -XX:NewRatio=2 -
XX:PermSize=128m -XX:MaxPermSize=512m -XX:CMSFullGCsBeforeCompaction=5 -
XX:+ExplicitGCInvokesConcurrent -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -
XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -
XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods"

1.2.2 线程池调整

[root@CentOS84 ~]#cat /usr/local/tomcat/conf/server.xml
......
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"
redirectPort="8443" />
......

常用参数选项:

  • connectionTimeout :连接超时时长,单位ms
  • maxThreads:最大线程数,默认200
  • minSpareThreads:最小空闲线程数
  • maxSpareThreads:最大空闲线程数
  • acceptCount:当启动线程满了之后,等待队列的最大长度,默认100
  • URIEncoding:URI 地址编码格式,建议使用 UTF-8
  • enableLookups:是否启用客户端主机名的DNS反向解析,缺省禁用,建议禁用,就使用客户端IP就行
  • compression:是否启用传输压缩机制,建议 "on",CPU和流量的平衡
  • compressionMinSize:启用压缩传输的数据流最小值,单位是字节
  • compressableMimeType:定义启用压缩功能的MIME类型text/html, text/xml, text/css,text/javascript


1.2.3 Tomcat连接器Connector 调优

打开Tomcat的server.xml,配置Connector的相关项

  • enableLookups == false:关闭DNS解析,减少性能损耗 【这个优化很重要的,一般都要关闭掉】
  • minProcessors:服务器启动时创建的最少线程数
  • maxProcessors:最大可以创建的线程数
  • acceprCount=1000:线程池中的线程都被占用,允许放到队列中的请求数
  • maxThreads = 3000;最大线程数
  • minSpareThreads = 20;最小空线程数,这里是一直会运行的线程


1.2.4 Tomcat的运行模式的优选

Tomcat 支持多种运行模式,依据业务类型选择合适的运行模式:

  • BIO,在tomcat8以下,默认使用BIO模式,对于每一个请求都要创建一个线程来进行处理,不适合高并发。
  • NIO,tomcat8以上的版本,默认使用NIO。
  • APR,全称 Apache Portable Runtime,是Tomcat生产环境运行的默认方式,如果操作系统未安装 APR 或者 APR 路径未指到 Tomcat 默认可识别的路径,则 APR 模式无法启动,自动切换启动 NIO 模式。所以必须要安装 APR 和 Native,直接启动就支持 APR,APR是从操作系统级别解决异步 IO 问题,APR 的本质就是使用 JNI 技术调用操作系统底层的 IO 接口,所以需要提前安装所需要的依赖提升 Tomcat 对静态文件的处理性能,当然也可以采用动静分离。但是如果使用的是nginx 搭配 Tomcat,则需要禁用AJP连接器。


2. 什么场景下会出现OOM?Java程序出现OOM如何解决?

2.1 OOM定义及原因

OOM(内存溢出 Out Of Memory,简称OOM)是java.lang.OutOfMemoryError问题,出现在程序需要的内存空间,系统无法提供满足要求的连续可用内存空间,所以会导致出现这个问题。具体表现为应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存。此时程序就运行不了,系统会提示内存溢出,有时候会自动关闭软件,重启电脑或者软件后释放掉一部分内存又可以正常运行该软件,而由系统配置、数据流、用户代码等原因而导致的内存溢出错误,即使用户重新执行任务依然无法避免。

2.2 几种主要的OOM

1、HeapSize OOM(堆空间内存溢出)

关键字:java.lang.OutOfMemoryError:java heap space

这是堆空间溢出。老年代区域剩余的内存,已经无法满足将要晋升到老年代区域的对象大小,会报此错。

2、PermGen OOM(永久代内存溢出)

关键字:java.lang.OutOfMemoryError:PermGen space

永久代(PermGen space)是JVM实现方法区的地方,因此该异常主要设计到方法区和方法区中的常量池。永久代存放的东西有class和一些常量。perm是放永久区的。如果一个系统定义了太多的类型,那永久区可能会溢出。jdk1.8中,被称为元数据区。

3、DirectBuffer OOM(直接内存内存溢出)

关键字:OutOfMemoryError: Direct buffer memory

Java中普通I/O用输入/输出流方式实现,输入流InputStream(终端—>直接内存->JVM),输出流(JVM->直接内存->终端),这一过程中有kenel与JVM之间的拷贝(很多次),为了使用直接内存,Java是有一块区域叫DirectBuffer,不是JavaHeap而是cHeap的一部分。

2.3 解决OOM

内存溢出的解决方案:

  第一步:检查 JVM 启动参数是否已经优化,是否可以增加内存等。 (-Xms , -Xmx 参数一定不要忘记加。 )

  第二步:检查错误日志,查看 “ OutOfMemory ”错误前是否有系统类的异常或错误导致的,尽量能初步定位下OOM原因。

  第三步:对代码进行检查和分析,找出可能发生内存溢出的位置。可借助Jprofiler等工具去定位OOM的问题原因和代码行,再去调整内存分配和代码优化,这样有的放矢地去解决掉导致OOM的问题。

  重点排查以下几点:

  1、检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

  2、检查代码中是否有死循环或递归调用。

  3、检查是否有大循环重复产生新对象实体。

  4、检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

  5、 检查 List 、 MAP 等集合对象是否有使用完后,未清除的问题。 List 、 MAP 等集合对象会始终存有对对象的引用,使得这些对象不能被 GC 回收。

  第四步,使用内存查看工具动态查看电脑内存使用情况,跟踪内存消耗的动态信息。


以上是关于Tomcat的优化及OOM问题的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat性能优化及JVM内存工作原理

Spark面对OOM问题的解决方法及优化总结

Spark面对OOM问题的解决方法及优化总结

Spark面对OOM问题的解决方法及优化总结

38 | Tomcat拒绝连接原因分析及网络优化

Android 防止OOM优化