书写目的
Tomcat为我司短信平台标准服务器,为了规范安装步骤、优化性能以及安全加固的相关配置,特制订以下规范。
1 Tomcat性能优化
1.1 JVM的优化
Tomcat的启动参数位于Tomcat的安装目录\bin目录下,如果你是Linux操作系统就是catalina.sh文件,如果你是Windows操作系统那么你需要改动的就是catalina.bat文件。本文以linux环境为例来讲解,打开该文件,一般该文件头部是一堆的由##包裹着的注释文字,找到注释文字的最后一段。
加入如下的参数:
export JAVA_OPTS="-server -Xms1400M -Xmx1400M-Xss512k
-XX:+AggressiveOpts -XX:+UseBiasedLocking-XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=31
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC-XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection-XX:LargePageSizeInBytes=128m
-XX:+UseFastAccessorMethods-XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true "
各个参数的简单解释以及个别参数的获得办法:
1.1.1 -server
Tomcat以server模式运行时将拥有:更大、更高的并发处理能力,更快更强捷的JVM垃圾回收机制,可以获得更多的负载与吞吐量。
1.1.2 -Xms–Xmx
把Xms与Xmx两个值设成一样是最优的做法,而且设置为最大化参数。获得最大参数具体值的方法:在设这个最大内存即Xmx值时请先打开一个命令行,键入如下的命令:
如果是在32位系统下,我们试试2G内存行不行:
试试1700m
连1700m都不可以,更不要说2048m了,2048m只是一个理论数值。这个跟机器也有关,有的能到1700m。
1.1.3 -Xss
是指设定每个线程的堆栈大小。这个就要依据你的程序,看一个线程大约需要占用多少内存,可能会有多少线程同时运行等。一般不易设置超过1M,要不然容易出现outofmemory。
1.1.4 -XX:+AggressiveOpts
启用一个优化了的线程锁,在我们的appServer,每个http请求就是一个线程,有的请求短有的请求长,就会有请求排队的现象,甚至还会出现线程阻塞,这个优化了的线程锁使得你的appServer内对线程处理自动进行最优调配。
1.1.5 -XX:PermSize=128M-XX:MaxPermSize=256M
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;
在数据量的很大的文件导出时,一定要把这两个值设置上,否则会出现内存溢出的错误。
由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
那么,如果是物理内存4GB,那么64分之一就是64MB,这就是PermSize默认值,也就是永生代内存初始大小;
四分之一是1024MB,这就是MaxPermSize默认大小。
1.1.6 -XX:+DisableExplicitGC
在程序代码中不允许有显示的调用”System.gc()”。
1.1.7 -XX:+UseParNewGC
对年轻代采用多线程并行回收,这样收得快。
1.1.8 -XX:+UseConcMarkSweepGC
即CMS GC,这一特性只有jdk1.5即后续版本才具有的功能,它使用的是GC估算触发和heap占用触发。使用了CMS GC后可以在GC次数增多的情况下,每次GC的响应时间却很短。
1.1.9 -XX:MaxTenuringThreshold
如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。
1.1.10 -XX:+CMSParallelRemarkEnabled
在使用UseParNewGC 的情况下, 尽量减少mark 的时间。
1.1.11 -XX:+UseCMSCompactAtFullCollection
在使用concurrent gc 的情况下, 防止memoryfragmention, 对live object 进行整理, 使 memory 碎片减少。
1.1.12 -XX:LargePageSizeInBytes
指定 Java heap的分页页面大小。
1.1.13 -XX:+UseFastAccessorMethods
get,set 方法转成本地代码。
1.1.14 -XX:+UseCMSInitiatingOccupancyOnly
指示只有在 oldgeneration 在使用了初始化的比例后concurrentcollector 启动收集。
-XX:CMSInitiatingOccupancyFraction=70 CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就不会出现promotion failed。在我的应用中Xmx是6000,Xmn是512,那么Xmx-Xmn是5488兆,也就是年老代有5488 兆,CMSInitiatingOccupancyFraction=90说明年老代到90%满的时候开始执行对年老代的并发垃圾回收(CMS),这时还剩10%的空间是5488*10%=548兆,所以即使Xmn(也就是年轻代共512兆)里所有对象都搬到年老代里,548兆的空间也足够了,所以只要满足上面的公式,就不会出现垃圾回收时的promotion failed;因此这个参数的设置必须与Xmn关联在一起。
1.1.15 -Djava.awt.headless=true
这个参数一般我们都是放在最后使用的,这全参数的作用是这样的,有时我们会在我们的J2EE工程中使用一些图表工具如:jfreechart,用于在web网页输出GIF/JPG等流,在winodws环境下,一般我们的app server在输出图形时不会碰到什么问题,但是在linux/unix环境下经常会碰到一个exception导致你在winodws开发环境下图片显示的好好可是在linux/unix下却显示不出来,因此加上这个参数以免避这样的情况出现。
上述这样的配置,基本上可以达到:
1.系统响应增快
2. JVM回收速度增快同时又不影响系统的响应率
3. JVM内存最大化利用
4. 线程阻塞情况最小化
1.2 Tomcat容器内的优化
前面对Tomcat启动时的命令进行了优化,增加了系统的JVM可使用数、垃圾回收效率与线程阻塞情况、增加了系统响应效率等还有一个很重要的指标,我们没有去做优化,就是吞吐量。
打开Tomcat安装目录\conf\server.xml文件,定位到这一行:
<Connectorport="8080" protocol=”HTTP/1.1” redirectPort=”8443”/> 即下图:
这一行就是我们的Tomcat容器性能参数设置的地方,它一般都会有一个默认值,这些默认值是远远不够我们的使用的,我们来看经过更改后的这一段的配置
<Connector port="8080" protocol=”HTTP/1.1”URIEncoding=”UTF-8”
maxSpareThreads=”75”minSpareThreads=”25”
enableLookups=”false” connectionTimeout=”20000”
maxThreads=”300”acceptCount=”300”maxProcessors=”1000”minProcessors=”5” useURIValidationHack=”false” enableLookups=”false”
disableUploadTimeout=”true”compression="on"compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml"
redirectPort=”8443”/>
如下图:
各个参数作用:
1.2.1 maxSpareThreads
空闲状态的线程数多于设置的数目,则将这些线程中止,减少这个池中的线程总数。
1.2.2 minSpareThreads
最小备用线程数,Tomcat启动时的初始化的线程数。
1.2.3 enableLookups
这个功效和Apache中的HostnameLookups一样,设为关闭。
1.2.4 connectionTimeout
网络连接超时时间毫秒数。
1.2.5 maxThreads
Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数,即最大并发数。
1.2.6 acceptCount
当线程数达到maxThreads后,后续请求会被放入一个等待队列,这个acceptCount是这个队列的大小,如果这个队列也满了,就直接refuse connection。
1.2.7 maxProcessors与minProcessors
在 Java中线程是程序运行时的路径,是在一个程序中与其它控制线程无关的、能够独立运行的代码段。它们共享相同的地址空间。多线程帮助程序员写出CPU最 大利用率的高效程序,使空闲时间保持最低,从而接受更多的请求。通常Windows是1000个左右,Linux是2000个左右。
1.2.8 useURIValidationHack
useURIValidationHack设成"false",可以减少它对一些url的不必要的检查从而减省开销。
1.2.9 enableLookups=”false”
为了消除DNS查询对性能的影响我们可以关闭DNS查询。
1.2.10 disableUploadTimeout
类似于Apache中的keeyalive一样。
1.2.11 Tomcat配置gzip压缩(HTTP压缩)功能
compression=”on” compressionMinSize=”2048” compressableMimeType=”text/html,text/xml,text/javascript,text/css,text/plain”
HTTP 压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求网页后,从服务器端将网页文件压缩,再下载到客户端,由客户端的浏览器负责解压缩并浏览。相对于普通的浏览过程HTML,CSS,Javascript , Text ,它可以节省40%左右的流量。更为重要的是,它可以对动态生成的,包括CGI、PHP , JSP , ASP ,Servlet,SHTML等输出的网页也能进行压缩,压缩效率惊人。
1)compression="on"打开压缩功能
2)compressionMinSize="2048"启用压缩的输出内容大小,这里面默认为2KB
3)noCompressionUserAgents="gozilla, traviata"对于以下的浏览器,不启用压缩
4)compressableMimeType="text/html,text/xml" 压缩类型
最后要把8443端口的地方也加上同样的配置,如果我们走https协议的话,我们将会用到8443端口这个段的配置,参数跟以上一样。
Tomcat优化完成了,这样做下来,优化过的Tomcat要比未经过优化的,性能提高20~60倍。
2 Tomcat安全性配置
2.1 首次安装完成后立即删除webapps下面的所有代码
rm -rf /Tomcat/webapps/*
2.2 注释或删除 Tomcat-users.xml 所有用户权限,需要注释节点如下:
# vi conf/Tomcat-users.xml
<?xml version='1.0' encoding='utf-8'?>
<Tomcat-users>
</Tomcat-users>
2.3 隐藏Tomcat版本信息
vim $CATALINA_HOME/conf/server.xml
<Connector port="80"protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="8192"
minSpareThreads="64"
maxSpareThreads="128"
acceptCount="128"
enableLookups="false"
server="Neo App Srv 1.0"/>
其中红字为添加的参数配置,“”中为修改的服务器信息,使用以下命令查看当前服务器版本信息:
# curl -I http://localhost:8080/
HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Date: Thu, 20 Oct 2011 09:51:55 GMT
Connection: close
Server: Neo App Srv 1.0
服务器信息已经被改为Server: Neo App Srv 1.0
2.4 启动用户与端口
不要使用root用户启动Tomcat,Java程序与C程序不同。nginx,httpd 使用root用户启动守护80端口,子进程/线程会通过setuid(),setgid()两个函数切换到普通用户。即父进程所有者是root用户,子进程与多线程所有者是一个非root用户,这个用户没有shell,无法通过ssh与控制台登陆系统,Java 的JVM 是与系统无关的,是建立在OS之上的,你使用什么用户启动Tomcat,那麽Tomcat 就会继承该所有者的权限。
这造成了一个问题,Linux系统小于1024的端口只有root可以使用,这也是为什么Tomcat默认端口是8080。如果你想使用80端口只能使用root启动Tomcat。这有带来了很多安全问题。
解决办法:
创建一个不同用户,如:
groupadd -g 80 daemon
adduser -o --home /daemon --shell/sbin/nologin --uid 80 --gid 80 -c "Web Server" daemon
接下来解决80端口问题, 思路就是80去调用8080,或者映射端口。
下面是影射方案,80 跳转 8080
iptables -t nat -A PREROUTING -p tcp --dport80 -j REDIRECT --to-port 8080
取消跳转
iptables -t nat -D PREROUTING -p tcp --dport80 -j REDIRECT --to-port 8080
查看规则
iptables -t nat -L
另一个就是从80请求去调用8080的方案
这个方案可以在 Tomcat 前段增加反向代理,例如:Nginx,Apache,Squid,Varnish或者F5, Array这类设备等等
2.5 关闭war自动部署
<Host name="localhost" appBase="" unpackWARs="false" autoDeploy="false">
应用程序部署与Tomcat启动,不能使用同一个用户。
我的Tomcat 安装在 /srv目录下,Tomcat启动用户为daemon; 应用程序放在/www目录下www所有者是www用户。这样的目的是一旦Tomcat被植入web shell程序,它将不能创建或编辑/www目录下面的任何内容。
adduser --home /www -c "WebApplication" www
2.6 删除管理界面(webapps下面的所有代码已经被删除,此项安全问题已经不大,设置上为多一层保险)
在server.xml中,在HOST容器中有一个配置,如
unpackWARs="true"
xmlValidation="false"xmlNamespaceAware="false">
。。。。。
;
将appBase=修改成你的应用所在的目录,比如appBase=/home/mc/mobilePlat
这样修改以后,系统自动启动的时候就不会加载webapps中的默认程序了,包括admin和manager等,只会启动htdocs目录中带xml配置参数的应用,当然如果你htdocs下面就直接是程序了,建议配置如下:
unpackWARs="true"
xmlValidation="false"xmlNamespaceAware="false">
2.7 屏蔽目录文件自动列出的方法
在Tomcat的conf/web.xml文件里把listings值改为false
如:
<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>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
2.8 打印访问日志
默认情况下Tomcat并不记录访问日志文件(access log): Catalina/conf/server.xml;将文件中这一段的注释去掉,然后将pattern的值改为combined ,这个模式下记录的日志比较详细。
<!--
<ValveclassName="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="localhost_access_log."suffix=".txt"
pattern="combined" resolveHosts="false"/>
-->
重新启动一下Tomcat
2.9 错误页面
如果找不到网页即出现404错误,会显示服务器版本号,服务器配置也一目了然,为了避免这种情况,在Tomcat的web.xml文件中,根元素下配置:(自定义错误页面)
<error-page>
<error-code>错误代码(404....)</error-code>
<location>错误页面地址</location>
</error-page>
还可以对出现的异常进行统一的错误处理
<error-page>
<exception-type>异常类型</exception-type>
<location>错误页面地址</location>
</error-page>
2.10 Tomcat Session过期时间
Tomcat采用数据库连接池技术,当用户在一定时间不对数据库有操作时间后,就自动关闭这个连接,这是为了更好的利用资源,防止浪费宝贵的数据库连接资源。
可以采用如下三种方式,设置这个连接(Session)的过期时间:
修改Tomcat的配置文件conf
1)在server.xml中定义context时采用如下定义:
xml 代码
<Context path="/livsorder"docBase="/home/httpd/html/livsorder"
defaultSessionTimeOut="3600"isWARExpanded="true"
isWARValidated="false" isInvokerEnabled="true"
isWorkDirPersistent="false"/>
3600秒=1小时
2)Tomcat,我在web.xml中配置了session超时的时间 如下: <session-config> <session-timeout>30</session-timeout> </session-config>
这里是以分钟为单位的,默认是30分;
3)webapp级别
在webapp中的 WEB-INF/web.xml
Xml代码
<!-- 配置Session失效时间 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
也是以min为单位;
2.11 关闭服务器端口:
server.xml默认有下面一行:
<Server port="8005" shutdown="SHUTDOWN">
这样允许任何人只要telnet到服务器的8005端口,输入"SHUTDOWN",然后回车,服务器立即就被关掉了。 从安全的角度上考虑,我们需要把这个shutdown指令改成一个别人不容易猜测的字符串,可以同时把端口也改了。 例如修改如下:
<Server port="8005" shutdown="c1gstudio">
这样就只有在telnet到8005,并且输入"c1gstudio"才能够关闭Tomcat. 注意:这个修改不影响shutdown.bat的执行。运行shutdown.bat一样可以关闭服务器。
2.12 OutOfMemory异常时获取堆栈快照
1.打开/Tomcat_home/bin/catalina.sh文件
2.加上:JAVA_OPTS="$JAVA_OPTS -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heapdump"
如下图位置:
注:其中不设-XX:HeapDumpPath时,dump出的文件在/Tomcat_home/bin目录下