最近有一个需求是调整 tomcat 的参数,因为服务器比较多,就使用 fabric 来批量处理了。
tomcat 需要调整的参数为 acceptCount
。
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8444"
URIEncoding="UTF-8"
useBodyEncodingForURI="true"
maxThreads="1024"
minSpareThreads="200"
maxSpareThreads="600"
acceptCount="800"
enableLookups="false"
compression="on"
compressionMinSize="2048"
noCompressionUserAgents="gozilla,traviata"
- maxThreads:tomcat 启动的最大线程数,即同时处理的任务个数,默认值为200
- acceptCount:当tomcat起动的线程数达到最大时,接受排队的请求个数,默认值为100
该参数值的作用的讲解请参照 baibaluo 博文 tomcat的maxThreads、acceptCount(最大线程数、最大排队数)
为了自己看方便,我直接贴出来
这两个值如何起作用,请看下面三种情况
情况1:接受一个请求,此时tomcat起动的线程数没有到达maxThreads,tomcat会起动一个线程来处理此请求。
情况2:接受一个请求,此时tomcat起动的线程数已经到达maxThreads,tomcat会把此请求放入等待队列,等待空闲线程。
情况3:接受一个请求,此时tomcat起动的线程数已经到达maxThreads,等待队列中的请求个数也达到了acceptCount,此时tomcat会直接拒绝此次请求,返回connection refused
maxThreads如何配置
一般的服务器操作都包括量方面:
1、计算(主要消耗cpu)
2、等待(io、数据库等)
第一种极端情况,如果我们的操作是纯粹的计算,那么系统响应时间的主要限制就是 cpu 的运算能力,此时 maxThreads 应该尽量设的小,降低同一时间内争抢 cpu 的线程个数,可以提高计算效率,提高系统的整体处理能力。
第二种极端情况,如果我们的操作纯粹是IO或者数据库,那么响应时间的主要限制就变为等待外部资源,此时 maxThreads 应该尽量设的大,这样才能提高同时处理请求的个数,从而提高系统整体的处理能力。此情况下因为 tomcat 同时处理的请求量会比较大,所以需要关注一下 tomcat 的虚拟机内存设置和 linux 的 open file 限制。
我在测试时遇到一个问题,maxThreads 我设置的比较大比如 3000,当服务的线程数大到一定程度时,一般是2000出头,单次请求的响应时间就会急剧的增加,
百思不得其解这是为什么,四处寻求答案无果,最后我总结的原因可能是cpu在线程切换时消耗的时间随着线程数量的增加越来越大,
cpu 把大多数时间都用来在这 2000 多个线程直接切换上了,当然 cpu 就没有时间来处理我们的程序了。
以前一直简单的认为多线程=高效率。。其实多线程本身并不能提高cpu效率,线程过多反而会降低cpu效率。
当 "cpu核心数<线程数" 时,cpu就需要在多个线程直接来回切换,以保证每个线程都会获得cpu时间,即通常我们说的并发执行。
所以 maxThreads 的配置绝对不是越大越好。
现实应用中,我们的操作都会包含以上两种类型(计算、等待),所以 maxThreads 的配置并没有一个最优值,一定要根据具体情况来配置。
最好的做法是:在不断测试的基础上,不断调整、优化,才能得到最合理的配置。
acceptCount 的配置,我一般是设置的跟 maxThreads 一样大,这个值应该是主要根据应用的访问峰值与平均值来权衡配置的。
如果设的较小,可以保证接受的请求较快相应,但是超出的请求可能就直接被拒绝
如果设的较大,可能就会出现大量的请求超时的情况,因为我们系统的处理能力是一定的。
Fabric 的脚本编写
@roles('user-api')
def bacup_tomcat_server_xml():
run('cp -av /opt/apps/tomcat/conf/server.xml /opt/apps/tomcat/conf/server.xml.2014-07-31')
@roles('user-api')
def rollback_tomcat_server_xml():
run('cp -av /opt/apps/tomcat/conf/server.xml.2014-07-31 /opt/apps/tomcat/conf/server.xml')
@roles('user-api')
def modify_tomcat_server_xml():
run("sed -i '/acceptCount/s/800/1024/' /opt/apps/tomcat/conf/server.xml")
#@roles('user-api')
def stop_tomcat():
run("ps -ef |grep tomcat |grep -v grep |awk -F\" \" '{print $2}' |xargs kill -9 ")
@roles('user-api')
def start_tomcat():
with cd('/opt/sh'):
run("./tomcat start")
@roles('user-api')
def reload_tomcat_nginx():
run('sudo /opt/nginx/sbin/nginx -s quit')
run("ps -ef |grep tomcat |grep -v grep |awk -F\" \" '{print $2}' |xargs kill -9 && sleep 5")
run('/opt/sh/tomcat.sh start')
run("sudo /opt/sh/nginx.sh start")
@parallel
def execute_modify_tomcat_conf():
execute(bacup_tomcat_server_xml)
execute(modify_tomcat_server_xml)
然后执行命令,为了安全稳妥起见,先执行其中一台
fab reload_tomcat_nginx -H 192.168.0.1
执行后,发现出现问题一个问题,在启动 tomcat 的时候出现问题,启动不起来,最后 google ,在 stackoverflow 上发现一个解答 how-to-start-tomcat-by-fabric-with-sudo-as-another-user
因此按照这个修改下,主要修改了 run('/opt/sh/tomcat.sh start')
这个步骤,
run('set -m;/apps/sh/tomcat.sh start')
只需要加一个 set -m
即可,该命令的作用是
"set -m" turns on job control, you can run processes in a separate process group.
我的理解是在一个独立的进程组里面运行我们的进程。
修改完毕后,再次测试,成功。