likes
comments
collection
share

Tomcat——调优指南

作者站长头像
站长
· 阅读数 48

  在上一篇文章 Tomcat——总体架构解析,我们学习了 Tomcat 整体架构,还知道了 Tomcat 是如何启动起来的,以及 Tomcat 的请求处理流程。今天我们来看下,如果优化 Tomcat

启动优化

   关于如何让Tomcat 启动变快,官方网站有专门的文章来介绍这个话题 ,HowTo FasterStartUp - Apache Tomcat - Apache Software Foundation,推荐大家阅读下,但是其中很多的配置,已经不适用现有的 Spring Boot 内嵌式启动的方式,下面主要是 Spring Boot 使用方式优化启动速度的几条建议。

清理 JAR 文件

   删除所有不需要的 JAR 文件。JVM 的类加载器在加载类时,需要查找每一个JAR 文件,去找到所需要的类。如果删除了不需要的 JAR 文件,查找的速度就会快一些。需要注意的是我们的项目中不应该出现 Servlet API 或者 Tomcat 自身的 JAR,如果使用 Maven 来构建你的应用,对Servlet API 的依赖应该范围是 provided

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <scope>provided</scope>
</dependency>

禁用 WebSocketJSP

   Tomcat 7.0.47 之后的版本, 会扫描 WebSocket 注解的API实现. 包括 @ServerEndpoint 注解的类, 以及实现了 ServerApplicationConfig 接口的类。如果项目中不需要使用 WebSockets, 则可以删除 WebSocket 相关的 jar 包 (websocket-api.jartomcat-websocket.jar)。或者设置containerSciFilter 属性

   Context 元素有一个 containerSciFilter 属性。 可以禁止 Tomcat 容器提供的插件功能: 如 WebSocket支持(Tomcat 7 及以后的版本可配置), JSP支持等(Tomcat 8 之后可配置)。

  • WebSocket 相关的是: org.apache.tomcat.websocket.server.WsSci
  • JSP相关的是:org.apache.jasper.servlet.JasperInitializer
@Component
public class MyTomcatCustomizer implements
        WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        factory.addContextCustomizers(new TomcatContextCustomizer() {
            @Override
            public void customize(Context context) {
                context.setContainerSciFilter("org.apache.tomcat.websocket.server.WsSci");
            }
        });
        factory.addContextCustomizers(new TomcatContextCustomizer() {
            @Override
            public void customize(Context context) {
                context.setContainerSciFilter("org.apache.jasper.servlet.JasperInitializer");
            }
        });
    }
}

禁止 Tomcat TLD 扫描

   Tomcat 为了支持JSP,在应用启动的时候会扫描JAR里的TLD文件,加载里面定义的tag libraries(标签库),在 Tomcat 的启动日志里,你可能会碰到这种提示:

org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

   可以配置 JarScanFilter 在启动中禁止扫描

@Component
public class MyTomcatCustomizer implements
        WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        factory.addContextCustomizers(new TomcatContextCustomizer() {
            @Override
            public void customize(Context context) {
                ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
            }
        });
    }
}

性能优化

Tomcat 的关键指标

   在了解性能优化之前,我们先来看下Tomcat 的关键指标

   Tomcat 的关键指标有:吞吐量、响应时间、错误数、线程池、CPU 以及 JVM 内存 。前三个指标是我们最关心的业务指标 ,后面三个指标是跟系统资源有关的

线程池调优

   线程池的调优就是设置合理的线程池参数。我们先来看看 Tomcat 线程池中有哪些关键参数 ,Apache Tomcat 8 配置参考 - 执行器(线程池)

Tomcat——调优指南

maxThreads

   每个传入的请求都由 Tomcat 中的一个线程处理。 maxThreads 可以设置最大线程数。如果 maxThreads 属性设置得太低,则请求需要等到线程可用于处理请求。这会增加请求的的响应时间。

   最大线程数取决于硬件及其拥有的 CPU 数量。硬件越好,处理器数量越多,Tomcat 需要支持的并发性就越大。一般建议在 500 ~ 800 ,最好的是根据自己的业务与配置反复压测调整,从而选择适合自己的以达到最优。

maxQueueSize

   建议使用默认值,除非在压测的过程发现了瓶颈。如果大量任务来不及处理都堆积在maxQueueSize 中,会导致内存耗尽,这个时候就需要设置一个限制。

minSpareThreads

   默认是 25 个线程,这个可以根据自己系统空闲度去适当的增加或者减少,从而减少线程池反复地创建和销毁线程的时间。

小结

   线程池的各种参数,其中最重要的参数是最大线程数 maxThreads。实际场景中,我们需要在理想值的基础上进行压测,来获得最佳线程数

IO 调优

   Tomcat 支持的 I/O 模型有:

  • BIO: 阻塞IO,Java 提供的最基本的 IO 方式
  • NIO:非阻塞 I/O,采用 Java NIO 类库实现。
  • NIO2:异步 I/O,采用 JDK7 最新的 NIO2 类库实现。
  • APR:采用 Apache 可移植运行库实现,是 C/C++ 编写的本地库

   我们通过官网的表格对比看下:The HTTP Connector

BIONIONIO2APR
Tomcat 版本自 3.0.x 起自 6.0.x 起自 8.0.x 起自 5.5.x 起
轮询支持
轮询队列大小N/AmaxConnectionsmaxConnectionsmaxConnections
读请求头阻塞非阻塞非阻塞非阻塞
读请求体阻塞阻塞阻塞阻塞
写响应阻塞阻塞阻塞阻塞
等待新的请求阻塞非阻塞非阻塞非阻塞
SSL支持Java SSLJava SSLJava SSLOpen SSL
SSL握手阻塞非阻塞非阻塞阻塞
最大链接数maxConnectionsmaxConnectionsmaxConnectionsmaxConnections

   在 Tomcat 8.0之前, 默认采用的I/O方式为BIO,之后改为NIO。无论NIO、NIO2还是APR,在性能方面均优于以往的BIO。如果采用APR,甚至可以达到接近于Apache HTTP Server的响应性能。

@Component
public class MyTomcatCustomizer implements
        WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        //设置使用协议
        factory.setProtocol("org.apache.coyote.http11.Http11NioProtocol");
    }
}

内存调优

Tomcat——调优指南

   Tomcat运行在Java虚拟机(JVM)之上。因此,内存调优就是 JVM 配置调优了。最常用的 JVM调优配置 :

# 使用 server 编译器
-server 
# 将堆的初始值和最大值直接设置成对应的数值避免频繁GC
-Xms2048m -Xmx2048m

  其他的配置建议使用默认值,在实际工作中要根据具体的错误信息去分析背后的原因,尤其是内存不够时,需要生成 Heap Dump 来分析,看再去调整各种 JVM 参数。

网络优化

  先看下 Tomcat 几个比较关键的参数:Apache Tomcat 9 配置参考

DNS查找设置

  enableLookups: 是否反查域名,以返回远程主机的主机名,默认为 false。

  DNS 查找的成本很高,如果此值设置为 true,可能会使 Tomcat 看起来很慢。为了获得最佳性能,请将正在使用的所有连接器的 enableLookups 设置为 false

连接数设置

  maxConnections :服务器将接受的最大连接数。当Tomcat 接收的连接数达到 maxConnections 时不会再从 队列中取走连接。

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

  Tomcat 的最大并发连接数等于maxConnections + acceptCount为了获得最佳性能,请将 acceptCount 设置为足够大,以可以接收突发连接。如果值过低,客户端会触发 Connection reset 。如果该值过高,队列将占用额外的服务器内存。

缓冲区设置

  rxBufSize:套接字接收缓冲区

  txBufSize : 套接字接收缓冲区

  使用 NIONIO2 连接器时,您可以配置 Tomcat 使用的套接字读取缓冲区和写入缓冲区的大小。socket.rxBufSizesocket.txBufSize 的值越大,支持的吞吐量就越高

响应压缩

  ompression:是否对响应的数据进行 GZIP 压缩,off:禁止压缩;on:允许压缩;force:都进行压缩,默认值为off。

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

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

  通过在 SpringBoot 配置文件,配置可以开启压缩。压缩数据后可以有效的减少数据的大小,一般可以减小1/3左右,提升网络传输速度

# 开启Gzip压缩,默认只压缩超过2048字节的数据
server:
  compression:
    enabled: true
    mime-types: application/json

总结

  最后的话,本篇文章介绍的仅仅是性能优化很少的一部分。本质上性能优化的范围涵盖非常广,而且也是一个非常复杂的过程,除了应用服务器优化,还包缓存优化、操作系统优化、前端页面优化、网络优化等。针对具体的应用场景,其优化方式也会多种多样,这并不是一些通用的规则可以概括的。这里仅仅起到一个启发和引导的作用。

参考

转载自:https://juejin.cn/post/7246264754141921341
评论
请登录