Tomcat性能优化及部署整理(1)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
日志服务 SLS,月写入数据量 50GB 1个月
云解析 DNS,旗舰版 1个月
简介: Tomcat性能优化及部署整理(1)

Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器

Tomcat性能优化整理

一、常见配置详解

1 目录结构

20200401134307494.png/bin:脚本文件目录。

/lib:存放Tomcat服务器所需要的所有Jar包。

/conf:存放配置文件,最重要的是server.xml。

/logs:存放日志文件。

/backup:保存了一些配置文件,是在第一次运行了Tomcat服务器以后产生的。它是对服务器进行简单的备份日志。

/temp:Tomcat运行时候存放临时文件用的。

/webapps:web应用发布目录,平时我们部署war包的地方

/work:Tomcat把各种由jsp生成的servlet文件放在这个目录下。删除后,启动时会自动创建。


2 配置文件

server.xml:tomcat主要的配置文件。主要作用还是处理来自客户端的访问请求的

web.xml:缺省的web app配置,WEB-INF/web.xml会覆盖该配置。

context.xml:是Tomcat公用的环境配置

tomcat-users.xml:看到uesrs那肯定是与用户相关的啦。主要是用来配置用户名、密码以及用户的权限的。

20200401134307494.png

server.xml配置

  1. server标签
<Server port="8006" shutdown="SHUTDOWN">

port:指定一个端口,这个端口负责监听关闭tomcat的请求。

shutdown:指定向端口发送的命令字符串。

  1. Service标签
  <Service name="Catalina">
  ....
   </Service>

name:指定service的名字。

  1. Connector(表示客户端和service之间的连接)标签
  <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

port:指定服务器端要创建的端口号,并在这个断口监听来自客户端的请求。

minProcessors:服务器启动时创建的处理请求的线程数。

maxProcessors:最大可以创建的处理请求的线程数。

enableLookups:如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名,若为false则不进行DNS查询,而是返回其ip地址。

redirectPort:指定服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号。

acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。

connectionTimeout:指定超时的时间数(以毫秒为单位)。


4.Engine(表示指定service中的请求处理机,接收和处理来自Connector的请求)标签

<Engine defaultHost="localhost" name="Catalina">
...
   </Engine>

defaultHost:指定缺省的处理请求的主机名,它至少与其中的一个host元素的name属性值是一样的。

  1. Context(表示一个web应用程序,通常为WAR文件,关于WAR的具体信息见servlet规范)标签
 <Context docBase="jeesite" path="/jeesite" reloadable="true" source="org.eclipse.jst.jee.server:jeesite"/></Host>

docBase:该web应用的文档基准目录(Document Base,也称为Context Root,或者是WAR文件的路径。可以使用绝对路径,也可以使用相对于context所属的Host的appBase路径。


reloadable:这个属性非常重要,如果为true,则tomcat会自动检测应用程序的/WEB-INF/lib和/WEB-INF/classes目录的变化,自动装载新的应用程序,我们可以在不重起tomcat的情况下改变应用程序。


useNaming:如果希望Catalina为该web应用使能一个JNDI InitialContext对象,设为true。该InitialialContext符合J2EE平台的约定,缺省值为true。


workDir:Context提供的临时目录的路径,用于servlet的临时读/写。利用javax.servlet.context.tempdir属性,servlet可以访问该目录。如果没有指定,使用$CATALINA_HOME/work下一个合适的目录。


swallowOutput:如果该值为true,System.out和System.err的输出被重定向到web应用的logger。如果没有指定,缺省值为false


debug:与这个Engine关联的Logger记录的调试信息的详细程度。数字越大,输出越详细。如果没有指定,缺省为0。


6.host(表示一个虚拟主机)标签

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
......
</Host>

name:指定主机名。

appBase:应用程序基本目录,即存放应用程序的目录。

unpackWARs:如果为true,则tomcat会自动将WAR文件解压,否则不解压,直接从WAR文件中运行应用程序。


7.Logger(表示日志,调试和错误信息)标签

className:指定logger使用的类名,此类必须实现org.apache.catalina.Logger接口。

prefix:指定log文件的前缀。

suffix:指定log文件的后缀。

timestamp:如果为true,则log文件名中要加入时间,如下例:localhost_log.2001-10-04.txt。


8.Realm(表示存放用户名,密码及role的数据库)标签

   <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
      </Realm>

className:指定Realm使用的类名,此类必须实现org.apache.catalina.Realm接口。

  1. Valve(功能与Logger差不多,其prefix和suffix属性解释和Logger 中的一样)标签
  <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt"/>

className:指定Valve使用的类名,如用org.apache.catalina.valves.AccessLogValve类可以记录应用程序的访问信息。

directory:指定log文件存放的位置。

pattern:有两个值,common方式记录远程主机名或ip地址,用户名,日期,第一行请求的字符串,HTTP响应代码,发送的字节数。combined方式比common方式记录的值更多。

3 配置虚拟目录

1)直接部署到webapps目录下面访问。

2)修改conf/server.xml文件。在中加入。docBase目录默认使用appBase=“webapps"这个目录。也可以是绝对路径。

配置主目录,可以将path=”"。

3)当项目没有放在webapps目录下时,可以在conf/Catalina/localhost新建一个XXX.XML文件。里面加入。

注意:这里的path属性不需要设置,设置了也不会起作用的。

也可以使用该方法建立主目录指向另一个目录,例如:命名为ROOT.xml,这样默认访问的主目录就被修改过了。


4 配置连接数

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxSpareThreads="750" maxThreads="1000"   minSpareTHreads="50" acceptCount="1000"  maxProcessors="1000"   URIEncoding="gbk" useBodyEncodingForURI="true"/> 

maxThreads:Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数。

acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。

minSpareThreads:Tomcat初始化时创建的线程数。

maxSpareThreads:一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。

enableLookups:是否反查域名,取值为:true或false。为了提高处理能力,应设置为false

connectionTimeout:网络连接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。默认可设置为20000毫秒。

web server允许的最大连接数还受制于操作系统的内核参数设置,通常Windows是2000个左右,Linux是1000个左右。


5 配置内存大小

修改bin/catalina.bat中的set CATALINA_OPTS=-Xms64m -Xmx128m。

Xms指最小内存,Xmx指最大内存。


6 安全配置

1)将SHUTDOWN修改为其他一些字符串。否则就容易被人给停止掉了。

2)对应tomcat3.1中,屏蔽目录文件自动列出

修改conf/web.xml中的

<servlet>
         <servlet-name>default</servlet-name>
         <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
         <init-param>
             <param-name>debug</param-name>
             <param-value>0</param-value>
         </init-param>
         <init-param>
             <param-name>listings</param-name>
             <param-value>true</param-value><!-- 改成false -->
         </init-param>
         <load-on-startup>1</load-on-startup>
     </servlet>

3)访问日志设置

在server.xml中加入

 <Valve className="org.apache.catalina.valves.AccessLogValve"
                  directory="logs"  prefix="localhost_access_log." suffix=".txt"
                  pattern="common" resolveHosts="false"/>

这样访问日志会记录到Logs中。


4)修改用户名、密码

conf/tomcat-users.xml


5)屏蔽后台管理入口

方法一:从控制用户和权限着手。废掉要管理权限的用户就可以了。

方法二:将conf/Catalina/localhost/manager.xml改名。


6)配置403,404,500错误页面

默认情况下,报出HTTP错误的时候会暴露tomcat版本号。如果不想暴露的话,就需要重新定义错误跳转页面。

 <error-page>
  <error-code>401</error-code>
  <location>/401.jsp</location>
 </error-page>
 <error-page>
  <error-code>404</error-code>
  <location>/404.jsp</location>
 </error-page>
 <error-page>
  <error-code>500</error-code>
  <location>/500.jsp</location>
 </error-page>

注意:在测试的时候碰到一个奇怪的现象,平时项目里面的时候测试正常的。可是今天在tomcat目录里面新建一个测试目录测试并不能跳转到指定错误页面。暂时不知道为什么。


7 配置Log4j日志记录


项目中抛出的异常,抛到tomcat中的异常会被tomcat记录下来,存放至logs/localhost.yyyy-MM-dd.log文件中。

平时我们在项目中使用的log4j记录日志跟tomcat是没有任何关系的,是独立的一个程序,记录的文件是自定义的。

我们可以在tomcat中定义一个log4j的公共日志处理方式,这样在项目中就不需要在定义log4j的配置了。

1)将log4j-1.2.15.jar加入到commonlib目录。

2)将log4j.properties加入到commonclasses目录。

内容例如:

# Output pattern : date [thread] priority category - message
 log4j.rootLogger=DEUBG, stdout, logfile
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
 log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
 log4j.appender.logfile.File=${catalina.home}/logs/tomcat_app.log
 log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
 log4j.appender.logfile.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
 #3rd party library level
 log4j.logger.org.hibernate.cache=ERROR

注意:我们项目中使用e.printStackTrace();输出的异常会在控制台输出来,但是,不会记录到tomcat日志中。 而且,也不会记录到log4j的日志中。要想记录到log4j日志中,必须使用log4j输出.


所以,实际上web项目中进行异常处理应该将e.printStackTrace();写写法多改成log4j的形式才对!

但是,实际项目中很多项目多偷懒使用了e.printStackTrace();方式输出异常。当出现异常的时候在控制台上查看一下就可以了,也不考虑实际运行时候的维护。假如有人不小心关了控制台,那么,你不就看不到异常了吗?

个人建议使用log4j的形式记入web异常!


8 Tomcat5乱码问题

Tomcat5跟Tomcat4对参数处理是不一样的,在Tomcat4中get与post的编码是一样的,所以只要在过滤器中通过request.setCharacterEncoding()设定一次就可以解决get与set的问题。然而,在Tomcat5中,get与post的处理是分开的,对get请求使用URIEncoding进行处理,对post使用request.setCharacterEncoding()处理。Tomcat5中,在server.xml的Connector元素增加了以下配置参数:

URIEncoding:用来设定通过URI传递的


以上内容参考自:


http://blog.csdn.net/zj52hm/article/details/51980194

二、Tomcat优化配置

我们平时在使用tomcat部署项目的时候,还是有必要了解一下如何进行性能优化。

1 优化内存,主要是在bin/catalina.bat/sh 配置文件中进行。linux上,在catalina.sh中添加:

JAVA_OPTS="-server -Xms1G -Xmx2G -Xss256K -Djava.awt.headless=true -Dfile.encoding=utf-8 -XX:MaxPermSize=256m -XX:PermSize=128M -XX:MaxPermSize=256M"

其中:


• -server:启用jdk的server版本。

• -Xms:虚拟机初始化时的最小堆内存。

• -Xmx:虚拟机可使用的最大堆内存。 #-Xms与-Xmx设成一样的值,避免JVM因为频繁的GC导致性能大起大落

• -XX:PermSize:设置非堆内存初始值,默认是物理内存的1/64。PermSize是JDK7以前的版本使用,若为JDK8,则得改为使用MetaspaceSize

• -XX:MaxNewSize:新生代占整个堆内存的最大值。

• -XX:MaxPermSize:Perm(俗称方法区)占整个堆内存的最大值,也称内存最大永久保留区域。MaxPermSize是JDK7以前的版本使用,若为JDK8,则得改为使用MaxMetaspaceSize


1)错误提示:java.lang.OutOfMemoryError:Java heap space


Tomcat默认可以使用的内存为128MB,在较大型的应用项目中,这点内存是不够的,有可能导致系统无法运行。常见的问题是报Tomcat内存溢出错误,Outof Memory(系统内存不足)的异常,从而导致客户端显示500错误,一般调整Tomcat的-Xms和-Xmx即可解决问题,通常将-Xms和-Xmx设置成一样,堆的最大值设置为物理可用内存的最大值的80%。


set JAVA_OPTS=-Xms512m-Xmx512m


2)错误提示:java.lang.OutOfMemoryError: PermGenspace


PermGenspace的全称是Permanent Generationspace,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGenspace中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGenspace进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行precompile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。解决方法:


setJAVA_OPTS=-XX:PermSize=128M


3)在使用-Xms和-Xmx调整tomcat的堆大小时,还需要考虑垃圾回收机制。如果系统花费很多的时间收集垃圾,请减小堆大小。一次完全的垃圾收集应该不超过3-5 秒。如果垃圾收集成为瓶颈,那么需要指定代的大小,检查垃圾收集的详细输出,研究垃圾收集参数对性能的影响。一般说来,你应该使用物理内存的 80% 作为堆大小。当增加处理器时,记得增加内存,因为分配可以并行进行,而垃圾收集不是并行的。


2 连接数优化


优化连接数,主要是在conf/server.xml配置文件中进行修改。


1)优化线程数


找到Connector port=“8080” protocol=“HTTP/1.1”,增加maxThreads和acceptCount属性(使acceptCount大于等于maxThreads),如下:

<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000" redirectPort="8443"acceptCount="500" maxThreads="400" />

• maxThreads:tomcat可用于请求处理的最大线程数,默认是200

• minSpareThreads:tomcat初始线程数,即最小空闲线程数

• maxSpareThreads:tomcat最大空闲线程数,超过的会被关闭

• acceptCount:当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理.默认100


2)使用线程池


在server.xml中增加executor节点,然后配置connector的executor属性,如下:

<Executor name="tomcatThreadPool" namePrefix="req-exec-"maxThreads="1000" minSpareThreads="50"maxIdleTime="60000"/>
<Connector port="8080" protocol="HTTP/1.1"executor="tomcatThreadPool"/>

其中:


• namePrefix:线程池中线程的命名前缀

• maxThreads:线程池的最大线程数

• minSpareThreads:线程池的最小空闲线程数

• maxIdleTime:超过最小空闲线程数时,多的线程会等待这个时间长度,然后关闭

• threadPriority:线程优先级


注:当tomcat并发用户量大的时候,单个jvm进程确实可能打开过多的文件句柄,这时会报java.net.SocketException:Too many open files错误。可使用下面步骤检查:

• ps -ef |grep tomcat 查看tomcat的进程ID,记录ID号,假设进程ID为10001

• lsof -p 10001|wc -l 查看当前进程id为10001的 文件操作数

• 使用命令:ulimit -a 查看每个用户允许打开的最大文件数


3. 禁用DNS查询

当web应用程序想要记录客户端的信息时,它也会记录客户端的IP地址或者通过域名服务器查找机器名转换为IP地址。DNS查询需要占用网络,并且包括可能从很多很远的服务器或者不起作用的服务器上去获取对应的IP的过程,这样会消耗一定的时间。为了消除DNS查询对性能的影响我们可以关闭DNS查询,方式是修改server.xml文件中的enableLookups参数值:

<Connector port="80" enableLookups="false" /> 

4 Tomcat Connector运行模式

1)同步阻塞 I/O(BIO)

20200401134307494.png

如上图所表现的那样,应用进程向内核发起 I/O 请求,发起调用的线程一直等待内核返回结果。一次完整的 I/O 请求称为BIO(Blocking IO,阻塞 I/O),所以 BIO 在实现异步操作时,只能使用多线程模型,一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。Tomcat7或以下在Linux系统中默认使用这种方式。


Tomcat7或以下在Linux系统中默认使用这种方式。


2)NIO:同步非阻塞 I/O(NIO)

20200401134307494.png

如上图所示,应用进程向内核发起 I/O 请求后不再会同步等待结果,而是会立即返回,通过轮询的方式获取请求结果。利用Java的异步IO处理,可以通过少量的线程处理大量的请求。Tomcat8在Linux系统中默认使用这种方式。Tomcat7必须修改Connector配置来启动(conf/server.xml配置文件):

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

3)APR(Apache Portable Runtime):从操作系统层面解决io阻塞问题。Linux如果安装了apr和native,Tomcat直接启动就支持apr。

4)apr模式

安装apr以及tomcat-native

yum -y install apr apr-devel

进入tomcat/bin目录,比如:

cd /opt/local/tomcat/bin/
tar xzfv tomcat-native.tar.gz
cd tomcat-native-1.1.32-src/jni/native
./configure --with-apr=/usr/bin/apr-1-config
make && make install

#注意最新版本的tomcat自带tomcat-native.war.gz,不过其版本相对于yum安装的apr过高,configure的时候会报错。


解决:yum remove apr apr-devel –y,卸载yum安装的apr和apr-devel,下载最新版本的apr源码包,编译安装;或者下载低版本的tomcat-native编译安装


安装成功后还需要对tomcat设置环境变量,方法是在catalina.sh文件中增加1行:

CATALINA_OPTS="-Djava.library.path=/usr/local/apr/lib"

apr下载地址:http://apr.apache.org/download.cgi

tomcat-native下载地址:http://tomcat.apache.org/download-native.cgi

修改8080端对应的conf/server.xml

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

PS:启动以后查看日志 显示如下表示开启 apr 模式


Sep 19, 2016 3:46:21 PM org.apache.coyote.AbstractProtocol start

INFO: Starting ProtocolHandler [“http-apr-8081”]


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
监控 Java 应用服务中间件
部署tomcat部署实战案例
本文是关于Tomcat部署实战案例的教程,包括通过yum和二进制方式部署Tomcat的详细步骤,以及如何监控Tomcat服务。
196 84
部署tomcat部署实战案例
|
3月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
|
2月前
|
应用服务中间件 Docker 容器
docker应用部署---Tomcat的部署配置
这篇文章介绍了如何使用Docker部署Tomcat服务器,包括搜索和拉取Tomcat镜像、创建容器并设置端口映射和目录映射,以及如何创建一个HTML页面并使用外部机器访问Tomcat服务器。
docker应用部署---Tomcat的部署配置
|
5月前
|
Ubuntu 前端开发 JavaScript
技术笔记:Ubuntu:一个部署好的tomcat应用(war包)怎么用Nginx实现动静分离?
技术笔记:Ubuntu:一个部署好的tomcat应用(war包)怎么用Nginx实现动静分离?
|
2月前
|
网络协议 Java 应用服务中间件
Tomcat 性能优化
Tomcat 性能优化
40 2
|
22天前
|
Java 应用服务中间件 Linux
tomcat学习二:tomcat部署多个项目:不修改端口和修改端口 两种方式详解
这篇文章详细介绍了在Tomcat服务器上部署多个项目的方法,包括不修改端口和修改端口两种方式。
71 0
|
3月前
|
应用服务中间件 Docker 容器
在服务器中使用Docker安装Tomcat、同时实现目录挂载、并且部署War包到服务器
这篇文章介绍了在Docker中安装Tomcat的过程,包括搜索Tomcat镜像、拉取镜像、目录挂载的准备、创建并挂载容器,以及如何进入容器和进行测试。文中还说明了如何将WAR包部署到Tomcat服务器并访问部署的应用。
在服务器中使用Docker安装Tomcat、同时实现目录挂载、并且部署War包到服务器
|
2月前
|
前端开发 Java 应用服务中间件
react自学(6) 部署到tomcat中
react自学(6) 部署到tomcat中
|
3月前
|
jenkins 持续交付 开发工具
"引爆效率革命!Docker+Jenkins+GIT+Tomcat:解锁持续集成魔法,一键部署Java Web应用的梦幻之旅!"
【8月更文挑战第9天】随着软件开发复杂度的增加,自动化变得至关重要。本文通过实例展示如何结合Docker、Jenkins、Git与Tomcat建立高效的持续集成(CI)流程。Docker确保应用环境一致性;Jenkins自动化处理构建、测试和部署;Git管理源代码版本;Tomcat部署Web应用。在Jenkins中配置Git插件并设置项目,集成Docker构建Tomcat应用镜像并运行容器。此外,通过自动化测试、代码质量检查、环境隔离和日志监控确保CI流程顺畅,从而显著提高开发效率和软件质量。
74 3
|
4月前
|
Java 应用服务中间件 Shell