Tomcat 8 参数配置性能优化

导读:本篇文章讲解 Tomcat 8 参数配置性能优化,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

前言

整理这篇 Tomcat优化,是因为以前从来没特地研究过,都是直接用服务器上已经有的压缩包解压使用,最多就是加大下内存,这几天心血来潮学习学习。

我用的环境是:

因为最后是要上线部署的,所以我下载了 Linux 版本,而且最后成品也是 Linux 版的。

最后的成品我也给放上,不过是直接本地压缩的 RAR 包:https://github.com/pic_bed_of_shiva/static-resources/blob/master/showns/software/apache-tomcat-8.5.49.rar

开启 manager-gui

在此之前,先删除一下无用的文件(开源协议也给删了,见谅见谅)。

然后,在调试过程,先临时开启下 manager-gui,Tomcat 建议不要使用 manager-gui。

并且,在线上环境也不需要使用 manager-gui,并且也有攻击从 Tomcat 控制台进入。

现在只是临时开启,调试时查看下服务器状态。

首先 conf/tomcat-users.xml 文件添加:

<role rolename="manager"/>
<role rolename="manager-gui"/>
<role rolename="admin-script"/>
<role rolename="admin-gui"/>
<role rolename="manager-jmx"/>
<role rolename="manager-script"/>
<role rolename="manager-status"/>
<user username="tomcat" password="123456" roles="manager,manager-gui,admin-script,admin-gui,manager-jmx,manager-script,manager-status"/>

然后 webapps/manager/META-INF/context.xml 文件注释以下配置:

  <!--  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />   -->

然后启动 Tomcat 进入控制台查看运行状态。

Tomcat 状态解读

在这里插入图片描述

首先看看JVM区

内存池 类型 初始化 最大值
PS Eden Space Heap memory 31.00 MB 646.50 MB
PS Old Gen Heap memory 83.00 MB 1313.50 MB
PS Survivor Space Heap memory 5.00 MB 5.00 MB
Code Cache Non-heap memory 2.43 MB 240.00 MB
Compressed Class Space Non-heap memory 0.00 MB 1024.00 MB
Metaspace Non-heap memory 0.00 MB -0.00 MB
  • PS Eden Space :新生带 Eden区,一个对象new 出来后会在Eden Space,直到GC到来,GC会逐一问清楚每个对象是否存在引用,进入Survivor Space(幸存区),没有引用将被kill。
  • PS Old Gen :老年代,主要存放生命周期长的对象
  • PS Survivor Space :新生带 Servivor区,幸存区。幸存者区的对象可以活段时间,GC会定期(可以自定义)会对这些对象进行访问,如果该对象的引用不存在了将被kill,如果每次访问该对象都存在引用,将被转移到老年代。(用于保存在eden space内存池中经过垃圾回收后没有被回收的对象。)
  • Code Cache :代码缓存区。HotSpot Java虚拟机包括一个用于编译和保存本地代码(native code)的内存。
  • Compressed Class Space :类指针压缩空间,存放 class 指针。
  • Metaspace :元空间,本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存

然后再往下,AJP-NIO-8009HTTP-NIO-8080 分别是两个连接服务监听的端口。

能看到两个服务的最大线程数,活跃线程数之类的参数,后面会对这些参数进行优化。

默认使用了 NIO,JDK 8 之前默认用的好像是 BIO,现在已经优化为 NIO 了,要不要改后面再说。

关闭 AJP 服务

在上面的控制台,大家可以看到 监听8009的AJP服务 ,默认是开启的。

AJP(Apache JServ Protocol)是定向包协议。因为性能原因,使用二进制格式来传输可读性文本。WEB 服务器通过 TCP 连接 和 SERVLET 容器连接。

它的作用是为了节省 Socket 创建的昂贵代价,WEB 服务器尝试维护一个永久的 TCP 连接到 Servlet 容器,并在多个请求和响应周期过程中复用。

然后看看它的工作原理:

在这里插入图片描述

注意上图是否使用 AJP服务的区别。但是现实的生产环境使用的都是:

Nginx + Tomcat 的基础架构,而 AJP 服务只有 Apache 和 IIS 服务器才能使用。

所以, 这个服务需要关闭,顺便还能省下一个端口,直接注释 AJP 连接器就好了。

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->

设置线程池

Connector 绝对是 Tomcat 配置中最核心的标签。默认的 Connector 配置如下:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

默认连接器基于 HTTP/1.1 协议,监听8080端口,超时连接20秒,每一个请求都会创建一个线程。

很明显,这样创建线程的方式很浪费资源,所以 Tomcat 内置了线程池优化方式。

删掉默认连接器,默认线程池标签去掉注释,如下:

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/>
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

然后来看下 Executor 标签的属性:

标签名 作用
className 用于实现此组件的java类的名称,这个类必须实现接口org.apache.catalina.Executor。不给定该属性时将采用默认的标准类org.apache.catalina.core.StandardThreadExecutor;
threadPriority 线程优先级,默认值为5
daemon 线程是否以守护线程的方式运行,默认值为true
namePrefix 执行器创建每个线程时的名称前缀,最终线程的名称为:namePrefix+threadNumber
maxThreads 最大并发数,默认值为200,一般建议在500~1000,根据硬件设备和业务量判断
minSpareThreads 线程池中最少空闲的线程数量。默认值为25
maxIdleTime 在空闲线程关闭前的毫秒数。除非激活的线程数量小于或等于minSpareThreads的值,否则会有空闲线程的出现。默认值为60000,即空闲线程需要保留1分钟的空闲时间才被杀掉
maxQueueSize 可执行任务的最大队列数,达到队列上限时的连接请求将被拒绝
prestartminSpareThreads 在启动executor时是否立即创建minSpareThreads个线程数,默认为false,即在需要时才创建线程

经过调整后,我的线程池长这样:

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500"
         minSpareThreads="20" maxIdleTime="60000" maxQueueSize="150" prestartminSpareThreads="true" />

NIO 还是 APR?Connector 配置

Tomcat8 有三种运行模式,BIO、NIO、APR。

  • BIO:Tomcat 7以前的默认运行模式;阻塞IO,性能低。适用于连接数目比较小且固定的架构。
  • NIO:基于缓冲区,非阻塞IO,有更好的并发性能,当然NIO更优的前提是,大量请求且请求耗时不高。Tomcat 8的默认使用方式。
  • APR:Apache Portable Runtime,从操作系统层面解决io阻塞问题。需要额外安装 Linux 组件,大幅度提高性能。单从性能来说是首选,不过作者在线上环境从没用过。

在 Tomcat 8 中自带最新的 NIO2,当然用新版本咯

<Connector executor="tomcatThreadPool" URIEncoding="UTF-8"
           port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
           connectionTimeout="20000"
           redirectPort="8443" />

然后,来看下 Connector 标签的参数,上面就说过,这毫无疑问是 Tomcat 最重要的标签,不过大多数情况下都不需要设置:

  • address:指定连接器监听的地址,默认为所有地址,即0.0.0.0。
  • maxThreads:支持的最大并发连接数,默认为200;如果引用了executor创建的共享线程池,则该属性被忽略。
  • acceptCount:设置等待队列的最大长度;通常在tomcat所有处理线程均处于繁忙状态时,新发来的请求将被放置于等待队列中;
  • maxConnections:允许建立的最大连接数。acceptCount和maxThreads是接受连接的最大线程数。存在一种情况,maxConnections小于acceptCount时,超出maxConnections的连接请求将被接收,但不会与之建立连接。
  • port:监听的端口,默认为0,此时表示随机选一个端口,通常都应该显式指定监听端口。
  • protocol:连接器使用的协议,用于处理对应的请求。默认为HTTP/1.1,此时它会自动在基于Java NIO或APR/native连接器之间进行切换。定义AJP协议时通常为AJP/1.3。
  • redirectPort:如果某连接器支持的协议是HTTP,当接收客户端发来的HTTPS请求时,则转发至此属性定义的端口。
  • connectionTimeout:等待客户端发送请求的超时时间,单位为毫秒,默认为60000,即1分钟;注意,这时候连接已经建立。
  • keepAliveTimeout:长连接状态的超时时间。超出该值时,长连接将关闭。
  • enableLookups:是否通过request.getRemoteHost()进行DNS查询以获取客户端的主机名;默认为true,应设置为false防止反解客户端主机;
  • compression:是否压缩数据。默认为off。设置为on时表示只压缩text文本,设置为force时表示压缩所有内容。应该在压缩和sendfile之间做个权衡。
  • useSendfile:该属性为NIO的属性,表示是否启用sendfile的功能。默认为true,启用该属性将会禁止compression属性。

只列举了一部分,全部请参考官方文档:

http://tomcat.apache.org/tomcat-8.5-doc/config/http.html

JVM 参数调整

Tomcat 本身还是运行在 JVM之上的,目前针对 JVM 的调优主要有两个方面:内存调优和垃圾回收策略调优

export JAVA_OPTS='-Xms1024m -Xmx1024m -XX:+PrintGCDetails -server  -Xloggc:../logs/gc.log'

我的配置就是上面这行了,就设置了一个并行收集器,再多也感觉不到有啥差别,而且看不懂。

这部分有点高深了,我目前就是看着大佬的博客画瓢。。JVM 还没研究过,看了点文章还是看不懂,先混个脸熟以后再详细研究。

内存调优

  1. -Xmx :设置Java虚拟机的堆的最大可用内存大小,单位:兆(m),整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m。堆的不同分布情况,对系统会产生一定的影响。尽可能将对象预留在新生代,减少老年代GC的次数(通常老年回收起来比较慢)。实际工作中,通常将堆的初始值和最大值设置相等,这样可以减少程序运行时进行的垃圾回收次数和空间扩展,从而提高程序性能。

  2. -Xms :设置Java虚拟机的堆的初始值内存大小,单位:兆(m),此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。

  3. -Xmn :设置年轻代内存大小,单位:兆(m),此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。一般在增大年轻代内存后,也会将会减小年老代大小。

  4. -Xss :设置每个线程的栈大小。JDK5.0以后每个线程栈大小为1M,以前每个线程栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

  5. -XX:NewRatio :设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 。

  6. -XX:SurvivorRatio :设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6。

垃圾回收策略调优

Java虚拟机的垃圾回收策略一般分为:串行收集器、并行收集器和并发收集器。

这一部分垃圾回收直接引用了大佬的总结,反正我也看不懂:

具体设置如下:

JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100"

具体的垃圾回收策略及相应策略的各项参数如下:

  1. 串行收集器(JDK1.5以前主要的回收方式) : -XX:+UseSerialGC:设置串行收集器

  2. 并行收集器(吞吐量优先)

    • -XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
    • -XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
    • -XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集
    • -XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。
    • -XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
  3. 并发收集器(响应时间优先)
    示例:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC

    • -XX:+UseConcMarkSweepGC:设置年老代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代大小最好用-Xmn设置。
    • -XX:+UseParNewGC: 设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。
    • -XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。
    • -XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片

其他方式

  1. 并发数量和业务代码有很大关系,可以通过 JMeter 测试将单台 Tomcat 调试至最大性能。然后根据该指标进行集群搭建。
  2. 代码优化,这个就不说了,要点太多了,比如:访问范围尽量可能小、避免使用反射、变量尽量复用、循环中别捕捉异常等等等等。。。好的代码真的可以让系统飞起来。。。

参考文章

http://tomcat.apache.org/tomcat-8.5-doc/config/http.html

https://blog.csdn.net/u011240877/article/details/52949046

https://www.bilibili.com/watchlater/#/BV1cE411Y7Am/p3

https://www.cnblogs.com/f-ck-need-u/p/8120008.html

https://blog.csdn.net/qq_35119422/article/details/81462034

https://www.cnblogs.com/xwjb/articles/8302960.html

https://cloud.tencent.com/developer/article/1346964

https://blog.51cto.com/dadloveu/2286359

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/10320.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!