tomcat优化

常见的http服务器有apache,nginx,iis,tomcat等。HTTP服务器本质上也是一种应用程序——它通常运行在服务器之上,绑定服务器的IP地址并监听某一个tcp端口来接收并处理HTTP请求,这样客户端(一般来说是IE, Firefox,Chrome这样的浏览器)就能够通过HTTP协议来获取服务器上的网页(HTML格式)、文档(PDF格式)、音频(MP4格式)、视频(MOV格式)等等资源。
  Tomcat运行在JVM之上,它和HTTP服务器一样,绑定IP地址并监听TCP端口,同时还包含以下职责:

  • 管理Servlet程序的生命周期。
  • 将URL映射到指定的Servlet进行处理。
  • 与Servlet程序合作处理HTTP请求——根据HTTP请求生成HttpServletResponse对象并传递给Servlet进行处理,将Servlet中的HttpServletResponse对象生成的内容返回给浏览器。

自己的第一门语言就是java,所以tomcat一直在用,但也基本只是在开发环境用一下,具体的参数也就改过JVM内存,没做过深入研究,主要还是因为自己工作一直没有需要去优化过tomcat。
  最近由于工作上的原因,需要对tomcat并发进行优化。在tomcat的server.xml文件中有关于请求连接的配置Connector。本文就具体属性进行一下说明。

Connector的protocol属性,三种运行模式(BIO, NIO, APR)
1)BIO:一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。Tomcat7或以下在Linux系统中默认使用这种方式。
2)NIO:利用Java的异步IO处理,可以通过少量的线程处理大量的请求。Tomcat8在Linux系统中默认使用这种方式。Tomcat7必须修改Connector配置来启动(conf/server.xml配置文件) protocol="org.apache.coyote.http11.Http11NioProtocol"
3)APR(Apache Portable Runtime):从操作系统层面解决io阻塞问题。Linux如果安装了apr和native,Tomcat直接启动就支持apr。在Tomcat.7.0.30版本开始,tomcat自带tcnative-1.dll等文件,windows上默认是运行apr模式。

linux安装apr和native

apr是比较恶心的一个东东,因为用直接用yum install apr安装apr后,当再安装其他东西需要apr环境时候 经常还是找不到,尽管已经安装它了。需要的几个环境:
  #yum -y install autoconf // 安装autoconf
  #yum -y install libtool // 安装libtool
  #yum -y install openssl openssl-devel // 安装openssl
这样的话我们只能通过下面这两个参数来指定他们的位置了
apr官网下载地址 http://apr.apache.org/download.cgi
安装apr:
  #tar xvzf apr-1.5.2.tar.gz // 解压apr-1.5.2.tar.gz
  #cd apr-1.5.2 // 进入apr-1.5.2目录
  #./configure --prefix=/usr/apr // 指定安装到/usr/apr目录
  #make & make install
安装tomcat-native:
  #cd /usr/tomcat/apache-tomcat-7.0.59/bin // 切换目录,在tomcat/bin目录下找到tomcat-native.tar.gz;
  #tar xvzf tomcat-native.tar.gz // 解压tomcat-native.tar.gz
  #cd /usr/tomcat/apache-tomcat-7.0.59/bin/tomcat-native-1.1.32-src/jni/native // 切换目录
  #./configure --with-apr=/usr/local/apr --with-java-home=/usr/java/jdk1.8.0_11 --with-ssl=/usr/bin --prefix=/usr/local/apr // 指定之前安装的目录
  #make & make install
配置APR本地库到系统共享库搜索路径中
  编辑$TOMCAT_HOME/bin/catalina.sh文件,在虚拟机启动参数JAVA_OPTS中添加java.library.path参数,指定apr库的路径
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=/usr/local/apr/lib"
  Tomcat8以下版本,需要指定运行模式,将protocol从HTTP/1.1改成org.apache.coyote.http11.Http11AprProtocol

这里重点比较一下BIO和NIO,在百度很多文章都是说BIO是一个请求一个线程,NIO可以一个线程服务多个请求。字面意思很清楚,但具体细节却不是很明白。虽然网上也有测试说明NIO在高并发的时候比BIO性能要好。我也做了一个简单的实验。

图片.png

  这里需要优化的就是网关tomcat,这里的网关tomcat主要起到的作用主要是验证请求者,然后通过http请求调用后端服务,没有复杂的业务逻辑处理。后端服务的提供者有很多,图中只举例了两个,各个服务由于业务不同,处理时间也不一样,有耗时的服务,也有快速返回的服务。网关tomcat如果按照默认的配置,则网关tomcat的服务器数量必须大于等于后端服务中并发量最大的那个服务的机器数量。这就形成了网关tomcat成为了整个系统的一个瓶颈,但网关tomcat只是起到一个网关作用,需要可以像nginx代理服务器那样可以抗大并发的能力。
  由于后端机器使用的低配置的阿里云,10秒的耗时应用的并发能力不到100,也就是两台机器通过nginx负载均衡后200的并发。这里为了测试方便把网关tomcat的maxThreads设置为50。

首先做一个测试比较protocol分别为BIO和NIO时,并发请求耗时应用的情况。

图片.png

这里测试了三种情况,分别为并发50,并发100,并发200,总请求数都是500,每种情况测试3次。通过图片数据可以看到BIO和NIO的结果没有什么区别。NIO并有像描述的那样一个线程可以处理更多的请求连接。网上也有实验数据说明NIO确实在并发处理上比BIO效果要好很多,但这个实验就不行,为什么呢?后来在知乎上的一篇文章上找到了点原因。

图片.png

这张表格引用自apache-tomcat官方网站,对于connector的三种模式有很好的对比,NIO也不是完全非阻塞(读body和写response是模拟阻塞行为)的地方用红色突出了一下,于header的处理,NIO不会阻塞,只有在body的读取时,NIO采取模拟阻塞的方式。这是由于servlet规范,tomcat要实现servlet规范所以不能最大发挥NIO的特性。在read http body 以及 response的情况下,即使tomcat选择 NIO的 connector也是模拟阻塞的行为,因为servlet规范里定义了ServletInputStream在读数据时是阻塞模式。

关于Wait for next Request
它表示的是当开启keep-alive的情况下三种模式对等待下一次请求是否阻塞。
在BIO模式下,如果请求是开启keep-alive的话,socket在请求结束后仍处于OPEN状态,下一次请求仍可以复用当前socket而不必重新创建,在 finally 块里会判断连接状况如果是keep-alive会再次封装为同样的任务提交给线程池,重复这段逻辑,相当于一个循环,只不过每次执行的线程不一定相同。如果socket上已经没有请求了,最终socket会因超时或客户端close造成的EOFException而关闭。也就是说在BIO下的keep-alive的请求,只有等到keep-alive超时或者达到maxKeepAliveRequests时才会把线程放回tomcat的线程池,服务其他请求。
在NIO和APR模式下,即使开启keep-alive,在Wait for next Request时候,这个线程也是可以服务其他请求的。

  看了上面这么多也就知道为什么会出现实验的效果了,NIO的非阻塞并不能完全解决我这个业务场景,因为即使是NIO下,在read body时也还是阻塞的,而我当前的业务场景是在serlvet中请求服务耗时。servlet的规范ServletInputStream在读数据时是阻塞模式这一特性是问题根本节点。通过调整maxThreads会是解决这种并发的一个方式。

  在查找上面BIO和NIO比较的时候,我看到有人说到了servlet3.0中有异步serlvet,可以解决serlvet阻塞的问题。于是我使用异步servlet重试了上诉实验:

图片.png

通过实验结果可以看到在NIO下使用异步serlvet确实可以达到想要的效果,tomcat网关在线程数50时也能处理并发200个请求。

AsyncContext asyncContext = request.startAsync();
asyncContext.start();//如果使用start方法,虽然把请求交给了另一个线程,但这个线程还是使用的tomcat的线程。
//这里最好使用一个线程池,为了简化测试,我直接使用new Thread
 new Thread(new AsyncRequest(asyncContext)).start();//这样就可以把tomcat的线程还回给tomcat线程池接收新请求了。

Connector的其他属性
connectionTimeout:网络连接超时,单位:毫秒。设置为0表示永不超时,通常可设置为20000毫秒。
URIEncoding:指定Tomcat 容器的URL编码格式。
enableLookups:如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名,若为false则不进行DNS查询,而是返回其ip地址。建议设置false,能提高部分性能。
maxThreads:tomcat起动的最大线程数,即同时处理的任务个数,默认值为200
acceptCount:当tomcat起动的线程数达到最大时,接受排队的请求个数,默认值为100
minSpareThreads:表示即使没有人使用也开这么多空线程等待
maxConnections:这个貌似应该是新加的参数吧,我没求证。服务器能接受和处理的最大数量,bio默认是maxThreads的值,nio默认10000,APR/native 默认是8192。
keepAliveTimeout:这个是保持长连接的时间限制,默认就是connectionTimeout设置的时间。

关于keepAlive,tomcat长连接短连接
1.WEB应用有很多,下面就两个典型的应用(管理页面和接口服务)做对比。
管理页面:多涉及到用户的登录和长时间的频繁操作处理,这些操作都集中在一个session中,建议采用长连接;
接口服务:比如常见的webservice,操作集中在很短时间内完成,不需要对session进行维护,建议采用短连接。
HTTP1.1默认采用长连接,需要去掉长连接的话,只需修改默认配置参数maxKeepAliveRequests。把maxKeepAliveRequests="5",意思是每个连接只响应5个请求,然后就shutdown连接.不用等到keepAliveTimeout就关闭这个连接

Apache优化之KeepAlive
1)KeepAlive是在HTTP1.1中定义的,用来保持客户机和服务器的长连接,通过减少建立TCP Session的次数来提高性能。
2)常用的配置参数有{KeepAlive,KeepAliveTimeout,MaxKeepAliveRequests}
KeepAlive是决定开启KeepAlive支持;
KeepAliveTimeout决定一 个KeepAlive的连接能保持多少时间,Timeout就尽快shutdown链接,若还有数据必须再建立新的连接了;
MaxKeepAliveRequests于KeepAliveTimeout相似,意思是服务多少个请求就shutdown连接。
3)对于KeepAlive的配置需要慎重,错误的参数可能导致严重的性能问题。
一个高负载的Server,如果建立的很多长连接将无法继续服 务新的连接。因此需要根据server的性质调整KeepAliveTimeout或是MaxKeepAliveRequests的值。

其他:tomcat内存优化

主要是在bin/catalina.bat或bin/catalina.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。
• -XX:MaxNewSize:新生代占整个堆内存的最大值。
• -XX:MaxPermSize:Perm(俗称方法区)占整个堆内存的最大值,也称内存最大永久保留区域。
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% 作为堆大小。当增加处理器时,记得增加内存,因为分配可以并行进行,而垃圾收集不是并行的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容