保存成功
订阅成功
保存失败,请重试
提交成功

Tomcat 性能优化

工作三年,从事java开发工作,以前也从事过java系统运维工作,现在一直在做java web开发,服务器维护,系统部署等工作。在这个期间,从事系统架构的设计,开发,也完成过【省级平台】的开发和架构部署,积累了经验。在企业也搭建过高可用的集群架构,包括系统的设计以及数据库的优化等。现在利用业余时间,分享下中间遇到的有趣的技术。
查看本场Chat

一、Tomcat 简单介绍:

Sun 公司创建了第一个 Servlet 容器,即 Java Web Server,但 JWS 只是为了演示 Servlet 的相应功能,所以其性能很不稳定。与此同时,apache 基金会组织 (ASF) 创建了 JServ 项目,一个能够与 apache 整合起来的 servlet 容器。1999 年,Sun 公司把 JWS 捐给了 ASF,于是两个项目合二为一,即今天 Tomcat 的前身。第一个 tomcat 版本是 Tomcat 3.x 系列,而发布于 2001 年 Tomcat4.0 则是在此前基础上进行了重新设计和实现,其代码项目被命名为 Catalina。

Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试 JSP 程序的首选。

版本介绍:现在版本更新到 Apache Tomcat 8.x,但是 Apache Tomcat 7.x 是目前开发的焦点。Apache Tomcat 7.x 它在汲取了 Tomcat 6.0.x 优点的基础上,实现了对于 Servlet 3.0、JSP 2.2 和 EL 2.2 等特性的支持。

除此以外的改进列表如下:

  • Web 应用内存溢出侦测和预防
  • 增强了管理程序和服务器管理程序的安全性
  • 一般 CSRF 保护
  • 支持 web 应用中的外部内容的直接引用
  • 重构 (connectors, lifecycle) 及很多核心代码的全面梳理

二、tomcat 运行模式介绍

Tomcat Connector(Tomcat 连接器) 有 bio、nio、apr 三种运行模式,那么这三种运行模式有什么区别呢,我们又如何修改 Tomcat Connector 的运行模式来提高 Tomcat 的运行性能呢?

bio 模式

bio(blocking I/O),顾名思义,即阻塞式 I/O 操作,表示 Tomcat 使用的是传统的 Java I/O 操作 (即 java.io 包及其子包)。Tomcat 在默认情况下,就是以 bio 模式运行的。遗憾的是,就一般而言,bio 模式是三种运行模式中性能最低的一种。我们可以通过 Tomcat Manager 来查看服务器的当前状态。

  1. [root@web conf]# cd /data/node1/conf/tomcat-users.xml
  2. [root@web conf]# vim tomcat-users.xml #添加进去两行代码,也就是新创建一个账号和密码。
<role rolename="manager-gui"/>
 <user username="tomcat" password="tomcat" roles="manager-gui"/>
  1. 添加之后,然后保存退出此文件。想让配置文件生效,需要重启下 tomcat。
  2. [root@web conf]# /data/node1/bin/shutdown.sh [root@web conf]# /data/node1/bin/startup.sh

点击 Server Status 查看下状态:

enter image description here

enter image description here

nio 模式

nio(new I/O),是 Java SE 1.4 及后续版本提供的一种新的 I/O 操作方式 (即 java.nio 包及其子包)。Java nio 是一个基于缓冲区、并能提供非阻塞 I/O 操作的 Java API,因此 nio 也被看成是 non-blocking I/O 的缩写。它拥有比传统 I/O 操作 (bio) 更好的并发运行性能。要让 Tomcat 以 nio 模式来运行也比较简单,我们只需要在 Tomcat 安装目录 / conf/server.xml 文件中将如下配置:

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

其中的 protocol 属性值改为 org.apache.coyote.http11.Http11NioProtocol 即可:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8443" />

此时,我们就可以在 Tomcat Manager 中看到当前服务器状态页面的 HTTP 协议的 Connector 运行模式已经从 http-bio-8080 变成了 http-nio-8080。

enter image description here

apr 模式

apr(Apache Portable Runtime/Apache 可移植运行时),是 Apache HTTP 服务器的支持库。你可以简单地理解为,Tomcat 将以 JNI 的形式调用 Apache HTTP 服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高 Tomcat 对静态文件的处理性能。 Tomcat apr 也是在 Tomcat 上运行高并发应用的首选模式。如果我们的 Tomcat 不是在 apr 模式下运行,在启动 Tomcat 的时候,我们可以在日志信息中看到类似如下信息:

org.apache.catalina.core.AprLifecycleListener init
信息: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: xxx/xxx(这里是路径信息)

Tomcat apr 运行模式的配置是三种运行模式之中相对比较麻烦的一种。据官方文档所述,Tomcat apr 需要以下三个组件的支持:

  • APR library[APR 库] JNI wrappers for APR used by Tomcat (libtcnative)[简单地说,如果是在 Windows 操作系统上,就是一个名为 tcnative-1.dll 的动态链接库文件]

  • OpenSSL libraries[OpenSSL 库] 此外,与配置 nio 运行模式一样,也需要将对应的 Connector 节点的 protocol 属性值改为org.apache.coyote.http11.Http11AprProtocol。 不过,上述繁琐的操作都是 Tomcat 7.0.30 之前的版本才需要这样配置,从 Tomcat 7.0.30 版本开始,Tomcat 已经自带了 tcnative-1.dll 等文件,并且默认就是在 Tomcat apr 模式下运行,因此我们只需要下载最新版本的 Tomcat 直接使用即可。

默认情况下是 bio 模式,介绍下怎么更换成 apr 模式:

[root@web]#yum install -y apr apr-util apr-devel
[root@web]# cd /data/node1/bin
[root@web bin]# tar -zxvf tomcat-native.tar.gz
[root@web bin]# cd tomcat-native-1.1.32-src/jni/native/
[root@web native]# ./configure --with-apr=/usr/bin/apr-1-config --with-ssl=/usr/include/openssl/
[root@web native]# make && make install
tomcat和apr库整合,需要修改shell脚本文件catalina.sh
[root@web node1]# vim /data/node1/bin/catalina.sh +99
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=512m -XX:MaxPermSize=512m -XX:+DisableExplicitGC"  
cygwin=false
darwin=false
CATALINA_OPTS="-Djava.library.path=/usr/local/apr/lib"
os400=false

保存退出,重启 tomcat。看 tomcat 启动输出日志信息:

信息: Deploying web application directory /data/node1/webapps/host-manager
四月 10, 2018 16:42:19 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deployment of web application directory /data/node1/webapps/host-manager has finished in 156 ms
四月 10, 2018 16:42:19 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deploying web application directory /data/node1/webapps/examples
四月 10, 2018 16:42:19 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deployment of web application directory /data/node1/webapps/examples has finished in 1,490 ms
四月 10, 2018 16:42:19 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-apr-8080"]
四月 10, 2018 16:42:19 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 25191 ms

出现了 ["http-apr-8080"] 字段,说明现在 tomcat 已经是 apr 模式。

三、Tomcat 安全和性能优化。

1. 内存优化

修改内存等 JVM 相关配置

Linux 下修改 TOMCAT_HOME/bin/catalina.sh,在其中加入,可以放在 CLASSPATH = 下面:

JAVA_OPTS="-server -XX:PermSize=512M -XX:MaxPermSize=1024m -Xms2048m -Xmx2048m"  

windows 下修改 TOMCAT_HOME/bin/catalina.bat,在其中加入,可以放在 set CLASSPATH = 下面:

set JAVA_OPTS=-server -XX:PermSize=512M -XX:MaxPermSize=1024m -Xms2048m -Xmx2048m  

这些参数在我们学习 JVM 部分文章时已经都认识过了,不过这里还是简单介绍下:

-server:启用 JDK的 server 版本;
-Xms:Java虚拟机初始化时堆的最小内存,一般与 Xmx配置为相同值,这样的好处是GC不必再为扩展内存空间而消耗性能;
-Xmx:Java虚拟机可使用堆的最大内存;
-XX:PermSize:Java虚拟机永久代大小;
-XX:MaxPermSize:Java虚拟机永久代大小最大值;

除了这些参数外您还可以根据具体需要配置其他参数,参数的配置可以参考 JVM 参数的配置

2. 配置优化

我们知道 TOMCAT_HOME/conf/server.xml 可以配置端口,虚拟路径等等 Tomcat 相关主要配置。

1) Connector 优化

Connector 是连接器,负责接收客户的请求,以及向客户端回送响应的消息。所以 Connector 的优化是重要部分。默认情况下 Tomcat 只支持 200 线程访问,超过这个数量的连接将被等待甚至超时放弃,所以我们需要提高这方面的处理能力。

修改这部分配置需要修改 TOMCAT_HOME/conf/server.xml,打开 server.xml 找到 Connector 标签项,默认配置如下:

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

其中 port 代表服务接口;protocol 代表协议类型;connectionTimeout 代表连接超时时间,单位为毫秒;redirectPort 代表安全通信(https)转发端口,一般配置成 443。

可以看到除了这几个基本配置外并无特殊功能,所以我们需要对 Connector 进行扩展。

其中 Connector 支持参数属性可以参考 Tomcat 官方网站(https://tomcat.apache.org/tomcat-8.0-doc/config/http.html ),非常多,所以本文就只介绍些常用的。

我们将 Connector 配置修改为如下:

    <Connector port="8080"   
              protocol="HTTP/1.1"   
          maxThreads="1000"   
              minSpareThreads="100"   
          acceptCount="1000"  
              maxConnections="1000"  
          connectionTimeout="20000"   
          maxHttpHeaderSize="8192"  
              tcpNoDelay="true"  
              redirectPort="8443"  
      enableLookups="false"  
              URIEncoding="UTF-8" />  
  • port:代表 Tomcat 监听端口,也就是网站的访问端口,默认为 8080,可以根据需要改成其他。 -protocol:协议类型,可选类型有四种,分别为 BIO(阻塞型 IO),NIO,NIO2 和 APR。

BIO:BIO(Blocking I/O),顾名思义,即阻塞式 I/O 操作,表示 Tomcat 使用的是传统的 Java I/O 操作 (即 java.io 包及其子包)。Tomcat 在默认情况下,是以 bio 模式运行的。遗憾的是,就一般而言,bio 模式是三种运行模式中性能最低的一种。BIO 配置采用默认即可。 NIO:NIO(New I/O),是 Java SE 1.4 及后续版本提供的一种新的 I/O 操作方式 (即 java.nio 包及其子包)。Java nio 是一个基于缓冲区、并能提供非阻塞 I/O 操作的 Java API,因此 nio 也被看成是 non-blocking I/O 的缩写。它拥有比传统 I/O 操作 (bio) 更好的并发运行性能。要让 Tomcat 以 nio 模式来运行也比较简单,我们只需要 protocol 类型修改为:

  //NIO  
protocol="org.apache.coyote.http11.Http11NioProtocol"  
    //NIO2  
protocol="org.apache.coyote.http11.Http11Nio2Protocol"  
 即可。
2) 线程池

Executor 代表了一个线程池,可以在 Tomcat 组件之间共享。使用线程池的好处在于减少了创建销毁线程的相关消耗,而且可以提高线程的使用效率。

要想使用线程池,首先需要在 Service 标签中配置 Executor,如下:

<Service name="Catalina">  
<Executor name="tomcatThreadPool"   
       namePrefix="catalina-exec-"   
      maxThreads="1000"   
        minSpareThreads="100"  
        maxIdleTime="60000"  
       maxQueueSize="Integer.MAX_VALUE"  
       prestartminSpareThreads="false"  
        threadPriority="5"  
        className="org.apache.catalina.core.StandardThreadExecutor"/>   ....    
其中,
name:线程池名称,用于 Connector中指定。
namePrefix:所创建的每个线程的名称前缀,一个单独的线程名称为 namePrefix+threadNumber。
maxThreads:池中最大线程数。
minSpareThreads:活跃线程数,也就是核心池线程数,这些线程不会被销毁,会一直存在。
maxIdleTime:线程空闲时间,超过该时间后,空闲线程会被销毁,默认值为6000(1分钟),单位毫秒。
maxQueueSize:在被执行前最大线程排队数目,默认为Int的最大值,也就是广义的无限。除非特殊情况,这个值不需要更改,否则会有请求不会被处理的情况发生。
prestartminSpareThreads:启动线程池时是否启动 minSpareThreads部分线程。默认值为false,即不启动。
threadPriority:线程池中线程优先级,默认值为5,值从1到10。
className:线程池实现类,未指定情况下,默认实现类为org.apache.catalina.core.StandardThreadExecutor。如果想使用自定义线程池首先需要实现 org.apache.catalina.Executor接口。

线程池配置完成后需要在 Connector 中指定:

<Connector executor="tomcatThreadPool"  
...  
3) Listener 配置

另一个影响 Tomcat 性能的因素是内存泄露。Server 标签中可以配置多个 Listener,其中 JreMemoryLeakPreventionListener 是用来预防 JRE 内存泄漏。此 Listener 只需在 Server 标签中配置即可,默认情况下无需配置,已经添加在 Server 中。

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />  

3. 缓存优化

参数说明

  compression 打开压缩功能 
  compressionMinSize 启用压缩的输出内容大小,这里面默认为2KB 
  compressableMimeType 压缩类型 
  connectionTimeout 定义建立客户连接超时的时间. 如果为 -1, 表示不限制建立客户连接的时间
<Connector port="9027"
  ...........
  compression="on"
  compressionMinSize="2048"
connectionTimeout="20000"
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"
................
  />

大家通过以上我们队 tomcat 的有效配置,包括 (从内存,运行模式、并发、缓存 4 个方面) 优化。能让自己的项目稳定的服务于客户,达到我们理想的运行效果。


本文首发于GitChat,未经授权不得转载,转载需与GitChat联系。

互动评论
评论
城市中的游牧民族2 年前
redirectPort 代表安全通信(https)转发端口,一般配置成 443。 不是8443?
评论
查看更多