Tomcat7性能优化配置方案

2019年02月18日 99 字 教程整理


本文从Tomcat配置层面,提高Tomcat服务器的并发性能。

Tomcat的配置优化主要有三方面,分为系统优化,Tomcat配置优化,Java 虚拟机(JVM)调优。
接下来将详细介绍Tomcat自身配置与JVM参数优化,以 Tomcat 7 为例。

0.1. Tomcat配置参数优化

0.1.1. Connector连接器并发优化: BIO/NIO/APR运行模式的选用

Tomcat的运行模式有3种:

BIOTomcat-7及以下版本默认模式阻塞式I/O(blocking I/O),表示Tomcat使用的是传统Java I/O操作(java.io包及其子包)。由于每个请求都要创建一个线程来处理,线程开销较大,不能处理高并发的场景,在三种模式中性能也最低
NIO / NIO2(AIO)Tomcat-8版本默认模式即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)更好的并发运行性能。利用Java的异步IO处理,可以通过少量的线程处理大量的请求
APR即Apache Portable Runtime/Apache可移植运行时,是Apache HTTP服务器的支持库。APR从操作系统层面解决io阻塞问题,可以简单地理解为:Tomcat将以JNI的形式调用 Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高 Tomcat对静态文件的处理性能。Tomcat-APR也是在Tomcat上运行高并发应用的首选模式

0.1.1.1. 如何查看Tomcat当前以何种工作模式运行?

在Tomcat启动时,可以通过log文件(通常为catalina.out文件)看到Connector使用的是哪一种运行模式:

如日志显示: StartingProtocolHandler ["http-bio-8080"],即Tomcat正在以BIO模式运行;

如日志显示: StartingProtocolHandler ["http-nio-8080"],即Tomcat正在以NIO模式运行;

如日志显示: StartingProtocolHandler ["http-apr-8080"],即Tomcat正在以APR模式运行;

0.1.1.2. protocol-BIO模式的启用(需重启Tomcat生效)

Tomcat-7及更低版本默认使用BIO模式。如需由其他模式更改为BIO模式,则修改server.xml文件Connector-protocol属性,设置为protocol="HTTP/1.1"即可,如图示:

0.1.1.3. protocol-NIO模式的启用(需重启Tomcat生效)

Tomcat-8及更高版本默认使用NIO模式。如使用较低版本或由其他模式更改为NIO模式,同样修改server.xml文件Connector-protocol属性,设置为protocol="org.apache.coyote.http11.Http11NioProtocol"即可,如图示:

0.1.1.4. protocol-APR模式的启用(需重启Tomcat生效)

启用这种模式稍微麻烦一些,需要预先安装一些依赖库。

0.1.1.4.1. 安装APR/APR-iconv和APR-util
0.1.1.4.1.1. 安装包的获取

进入APR-官网选择适宜版本的安装包,下载并解压至系统路径:

cd /usr/local/src/
wget http://mirror.bit.edu.cn/apache//apr/apr-1.6.5.tar.gz
tar -xvf apr-1.6.5.tar.gz
wget http://mirror.bit.edu.cn/apache//apr/apr-util-1.6.1.tar.gz
tar -xvf apr-util-1.6.1.tar.gz
wget http://mirror.bit.edu.cn/apache//apr/apr-iconv-1.2.2.tar.gz
tar -xvf apr-iconv-1.2.2.tar.gz

0.1.1.4.1.2. 安装apr
cd /usr/local/src/apr-1.6.5/
./configure --prefix=/usr/local/APR-1.6.5
make
make install

【注】 configure这一步可能会报 rm: cannot remove 'libtoolT': No such file or directory config.status: executing default commands错误。出现这个错误时,需修改configure文件,将 $RM "$cfgfile" 改为 $RM -f "$cfgfile" ,然后重新编译一次即可。

0.1.1.4.1.3. 安装apr-iconv
cd /usr/local/src/apr-iconv-1.2.2/
./configure --prefix=/usr/local/APR-ICONV-1.2.2 --with-apr=/usr/local/APR-1.6.5
make
make install
0.1.1.4.1.4. 安装apr-util
cd /usr/local/src/apr-util-1.6.1/
./configure --prefix=/usr/local/APR-UTIL-1.6.1 --with-apr=/usr/local/APR-1.6.5 --with-apr-iconv=/usr/local/APR-ICONV-1.2.2/bin/apriconv
make
make install

【注】 如make这一步报错xml/apr_xml.c:35:19: fatal error: expat.h: No such file or directory compilation terminated,说明系统缺少expat库,预先安装expat库即可: apt-get install libexpat1-devyum install expat-deve -y

0.1.1.4.2. 安装tomcat-native

tomcat/bin/路径下有相应的安装tomcat-native的tar包,解压并安装至选定的路径即可:

cd /usr/local/Tomcat_Server/tomcat_server_colony/apache-tomcat-7.0.90_0/bin/
tar -xvf tomcat-native.tar.gz -C /usr/local/Tomcat_Server/tomcat-native/
cd /usr/local/Tomcat_Server/tomcat-native/tomcat-native-1.2.17-src/native/
./configure --with-apr=/usr/local/APR-1.6.5 --with-java-home=/usr/local/Java/jdk1.8.0_131
make
make install

【注】如系统同时安装多个tomcat副本,则安装一次tomcat-native即可。

0.1.1.4.3. 配置APR环境变量

编辑/etc/profile,在文件末尾追加如下路径:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/APR-1.6.5/lib
export LD_RUN_PATH=$LD_RUN_PATH:/usr/local/APR-1.6.5/lib

保存后,输入source /etc/profile命令,使改动立即生效。

如果tomcat-native并未安装在Tomcat内部路径下,而是安装至自定义路径,则需进一步修改tomcat/bin目录下setclasspath.sh文件,在其他命令之前加入LD_LIBRARY_PATH变量:

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<tomcat-native-libs路径>
export LD_LIBRARY_PATH    

如:

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/Tomcat_Server/tomcat-native/tomcat-native-1.2.17-src/native/.libs
export LD_LIBRARY_PATH

0.1.1.4.4. 启用protocol-APR模式

修改server.xml文件Connector-protocol属性,设置为protocol="org.apache.coyote.http11.Http11AprProtocol"即可,如图示:

0.1.2. Server配置参数(缓存/协议类型)优化(需重启Tomcat生效)

0.1.2.1. 禁用AJP连接器

AJP(Apache JServerProtocol)是为 Tomcat 与 HTTP 服务器之间通信而定制的协议,能提供较高的通信速度和效率。
如果tomcat前端放的是apache的时候,会使用到AJP这个连接器。
使用Nginx+tomcat的架构时,用不到AJP协议,所以在这里可以把AJP连接器禁用。
编辑server.xml文件,将AJP相关配置的代码注释掉即可:

< ! -- <Connector port="8019" protocol="AJP/1.3" redirectPort="8443" /> - - >

0.1.2.2. 启用线程池

默认的tomcat没有启用线程池。
在tomcat中每一个用户请求都是一个线程,所以启用线程池可以使用线程池提高性能。这里前台其实有一个调度线程,然后调度线程会放入线程池内,然后到到一定的时候线程池的任务变成工作线程。
具体配置方式如下:

  1. 打开server.xml文件,取消<Executor代码段的注释。

  1. 为Connector指定线程池。

     executor="tomcatThreadPool"
    

  1. 调整Executor参数,如:

< Executor

name=”tomcatThreadPool”

minSpareThreads=”4”

maxThreads=”500”

namePrefix=”catalina-exec-“

/ >

0.1.2.3. tomcat-Connector并发处理/缓存参数优化

maxThreads客户请求最大线程数
minSpareThreadsTomcat初始化时创建的 socket 线程数
maxSpareThreadsTomcat连接器的最大空闲 socket 线程数
enableLookups是否反查域名,取值为: true 或 false 。为了提高处理能力,应设置为 false
redirectPort在需要基于安全通道的场合,把客户请求转发到基于SSL 的 redirectPort 端口
acceptAccount监听端口队列最大数,满了之后客户请求会被拒绝(不能小于maxSpareThreads )
connectionTimeout连接超时
minProcessors服务器创建时的最小处理线程数
maxProcessors服务器同时最大处理线程数
URIEncodingURL统一编码

【注】其中和最大连接数相关的参数为maxProcessors 和 acceptCount 。如果要加大并发连接数,应同时加大这两个参数。

示例:

< Connector port=”8090”

minSpareThreads=”100”

maxThreads=”1000”

URIEncoding=”UTF-8”

enableLookups=”false”

disableUploadTimeout=”true”

tcpNoDelay=”true”

maxConnections=”10000”

acceptorThreadCount=”2”

acceptCount=”1000”

redirectPort=”8443”

connectionTimeout=”20000”

protocol=”org.apache.coyote.http11.Http11AprProtocol”

executor=”tomcatThreadPool”
/ >

0.1.2.4. tomcat-Connector压缩参数优化

compressioncompression="on";打开压缩功能
compressionMinSize启用压缩的输出内容大小,默认为2KB
noCompressionUserAgents对于指定的浏览器,不启用压缩
compressableMimeType针对哪些资源类型需要压缩

【注】 Tomcat 的压缩是在客户端请求服务器对应资源后,从服务器端将资源文件压缩,再输出到客户端,由客户端的浏览器负责解压缩并浏览。
相对于普通的浏览过程 HTML、CSS、Javascript和Text,它可以节省40% 左右的流量。更为重要的是,它可以对动态生成的,包括CGI、PHP、JSP、ASP、Servlet,SHTML等输出的网页也能进行压缩,压缩效率也很高。
但是压缩也会增加 Tomcat 的负担,因此最好采用Nginx + Tomcat 或者 Apache + Tomcat 方式,将压缩的任务交由 Nginx/Apache 去做。

示例:

< Connector port=”8090”

compressableMimeType=”text/html,text/xml,text/css,text/javascript,text/plain,application/javascript,text/json”

noCompressionUserAgents=”gozilla, traviata”

compressionMinSize=”2048”

compression=”on”

/ >

0.1.2.5. tomcat-Host项目路径调整

如果tomcat以集群的形式作为应用容器,在项目更新时逐一向集群中各个tomcat容器的webapps路径上传项目war包文件,不仅耗时,更占用系统的可用资源。
如将集群中的tomcat容器项目路径指向同一个指定目录下,容器中项目的维护和储存会更加简洁高效。
具体配置为:
编辑server.xml文件,修改Host-appBase属性至选定自定义路径,如:

< Host name=”localhost”

appBase=”/usr/local/Tomcat_Server/tomcat_server_colony/colony_webapps/“

unpackWARs=”true”

autoDeploy=”true”

0.1.2.6. log日志配置优化

在默认的配置下,tomcat运行期间会输出一大堆的日志。而这些日志对日常运维来说,基本没有帮助,反而徒增很多无用信息和I/O负担。
如能简化日志的写入配置,也能为tomcat增速不少。
Tomcat日志相关的优化主要包含如下方面:

0.1.2.6.1. 关闭localhost_access_log日志

修改在tomcat的安装目录conf文件夹下server.xml里配置,将AccessLogValue注释掉。

< ! - - Valve className="org.apache.catalina.valves.AccessLogValue" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" / - - >
0.1.2.6.2. 调整logging.properties设置,屏蔽非常用日志

修改conf/logging.properties日志配置文件可以屏蔽掉部分的日志信息。
将level级别设置成WARNING就可以大量减少日志的输出,当然也可以设置成OFF,直接禁用掉。

与此类似,也可以观察下tomcat容器内的项目日志级别,部署时尽量设置为OFFERRORWARNING等级。

示例配置如下:

    # Licensed to the Apache Software Foundation (ASF) under one or more
    # contributor license agreements.  See the NOTICE file distributed with
    # this work for additional information regarding copyright ownership.
    # The ASF licenses this file to You under the Apache License, Version 2.0
    # (the "License"); you may not use this file except in compliance with
    # the License.  You may obtain a copy of the License at
    #
    # http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    #handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, 3manager.org.apache.juli.FileHandler, 4host-manager.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
    
    #.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
    
    ############################################################
    # Handler specific properties.
    # Describes specific configuration info for Handlers.
    ############################################################
    
    1catalina.org.apache.juli.FileHandler.level = OFF
    1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
    1catalina.org.apache.juli.FileHandler.prefix = catalina.
    
    #2localhost.org.apache.juli.FileHandler.level = FINE
    #2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
    #2localhost.org.apache.juli.FileHandler.prefix = localhost.
    
    #3manager.org.apache.juli.FileHandler.level = FINE
    #3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
    #3manager.org.apache.juli.FileHandler.prefix = manager.
    
    #4host-manager.org.apache.juli.FileHandler.level = FINE
    #4host-manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
    #4host-manager.org.apache.juli.FileHandler.prefix = host-manager.
    
    java.util.logging.ConsoleHandler.level = OFF
    java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
    
    
    ############################################################
    # Facility specific properties.
    # Provides extra control for each logger.
    ############################################################
    
    org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = OFF
    org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler
    
    org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = OFF
    org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.AsyncFileHandler
    
    org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = OFF
    org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.AsyncFileHandler
    
    # For example, set the org.apache.catalina.util.LifecycleBase logger to log
    # each component that extends LifecycleBase changing state:
    #org.apache.catalina.util.LifecycleBase.level = FINE
    
    # To see debug messages in TldLocationsCache, uncomment the following line:
    #org.apache.jasper.compiler.TldLocationsCache.level = FINE
0.1.2.6.3. 定期清理或切割压缩catalina.out文件

catalina.out文件过大会造成日志写入速度慢,会间接拖慢tomcat的响应速度。
为了避免文件过大造成的I/O速度慢,可以通过定期清空或拆分catalina.out文件来降低catalina.out文件体积。这里比较推荐通过crontab自动执行脚本来实现。

  1. 清空catalina.out文件

      cat /dev/null > <catalina.out文件路径> ;
    
  2. 按日期切割压缩打包日志(tar.gz)

     #!/bin/bash
     DIR=$(cd $(dirname ${BASH_SOURCE[0]}); pwd )
     echo $DIR/../logs
     d=`date +%Y%m%d%H`
     cd $DIR/../logs
     cp catalina.out catalina.out.${d}
     echo "" > catalina.out
     tar -czvf catalina.out.${d}.tar.gz catalina.out.${d}
     rm -rf catalina.out.${d}
     find $DIR/../logs -type f -mtime +15 -name "*.log" -exec rm -f {} \;
     find $DIR/../logs -type f -mtime +15 -name "*.tar.gz" -exec rm -f {} \;
    
0.1.2.6.4. 关闭catalina.out文件(不推荐)

catalina.out文件是tomcat的启动日志,很多时候可以帮助我们运维,所以不建议完全关闭,如确实过大可以用上一个方式定期缩减此文件的体积。

如确实需要关闭,可以设置bin/catalina.sh文件。找到if [ -z "$CATALINA_OUT" ] ; then 代码段,改写成:

    if [ -z "$CATALINA_OUT" ] ; then
      CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out
    fi

0.2. JVM(Tomcat启动参数/内存)优化(需重启Tomcat生效)

在tomcat的启动脚本catalina.sh中设置JAVA_OPTS参数。

-server启用jdk 的 server 版
-Xmsjava虚拟机初始化时的最小内存
-Xmxjava虚拟机可使用的最大内存
-XX: PermSize内存永久保留区域
-XX:MaxPermSize内存最大永久保留区域

示例:

JAVA_OPTS="-Dfile.encoding=UTF-8 -server -Xms1024m -Xmx2048m -XX:NewSize=512m -XX:MaxNewSize=1024m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=356m -XX:NewRatio=2 -XX:MaxTenuringThreshold=12 -XX:+DisableExplicitGC"

0.3. 系统参数(网卡驱动)优化

优化网卡驱动可以有效提升性能,这个对于集群环境工作的时候尤为重要。
通常线上项目会采用Linux服务器,所以优化内核参数也是一个非常重要的工作。

现给一个参考的优化参数方案:

  1. 修改/etc/sysctl.cnf文件,在文件末尾追加如下配置:

     net.core.netdev_max_backlog = 32768
    
     net.core.somaxconn = 32768
    
     net.core.wmem_default = 8388608
    
     net.core.rmem_default = 8388608
    
     net.core.rmem_max = 16777216
    
     net.core.wmem_max = 16777216
    
     net.ipv4.ip_local_port_range = 1024 65000
    
     net.ipv4.route.gc_timeout = 100
    
     net.ipv4.tcp_fin_timeout = 30
    
     net.ipv4.tcp_keepalive_time = 1200
    
     net.ipv4.tcp_timestamps = 0
    
     net.ipv4.tcp_synack_retries = 2
    
     net.ipv4.tcp_syn_retries = 2
    
     net.ipv4.tcp_tw_recycle = 1
    
     net.ipv4.tcp_tw_reuse = 1
    
     net.ipv4.tcp_mem = 94500000 915000000 927000000
    
     net.ipv4.tcp_max_orphans = 3276800
    
     net.ipv4.tcp_max_syn_backlog = 65536
    
  2. 保存退出,执行sysctl -p命令,使上一步配置立即生效。