成为Java GC专家(4)—Apache的MaxClients参数详解及其在Tomcat执行FullGC时的影响
下面我们看一下Apache的 MaxClients
参数在Full GC 发生时是如何影响系统的。
大部分开发人员都知道在由于GC发生而导致的”停止世界现象(STW) “(详细请参见Understanding Java Garbage Collection)。尤其是,NHN的Java开发人员经常会遇到由于GC原因导致的Tomcat报错。由于Java 虚拟机 (JVM)管理着内存,以Java为基础的程序无法摆脱GC导致的STW现象。假如在某一个时间,当你正在操作你开发的应用时,GC开始执行。即使TTS错误没有发生,你的服务也会给客户展现未预期的503错误。
服务执行环境
由于架构本身的特点,相比较而言纵向扩展,Web服务更适合横向扩展(译者注:增加服务器的数量,而不是提高件配置)。因此,总体来讲,物理设备会根据性能要求被配置成1台Apache+n台Tomcat。但是本文假设我们的环境是1台Apache+一台Tomcat同时安装在一台主机行,如下图所示。
图1:本文假射的服务执行环境
仅供参考,本文描述的参数基于Apache 2.2.21 (prefork MPM),Tomcat 6.0.35,CentOS 4.72 (32-bit),jdk 1.6.0_24。
系统可用内存2GB,垃圾收集器使用ParallelOldGC,AdaptiveSizePolicy采用默认的设置true,堆内存空间600M
STW 和HTTP 503
让我们假设访问Apache的请求为 200 req/s且有10个httpd进程在运行,另外我们暂时不考虑每个请求的响应时间。在这种前提下,我们假设由于full GC导致的暂停时间为1秒。当Full GC发生的时候Tomcat会怎样?
第一件进入你脑海的事情应该是Tomcat会因为full GC而停止响应任何请求。在这种情况下,当Tomcat暂停相应请求时Apache会发生什么?
当Tomcat暂停时,请求会以200 req/s的速度不断的涌入Apache。一般来说,在Full GC发生之前,请求的响应可以快速地被10个或更多的httpd进程处理掉。但是,因为Tomcat暂停了,httpd进程会被不停地创建以相应新进请求。直到超过httpd.conf 文件中定义 MaxClients
为止。由于默认值为256,Apache不会在乎请求以200 req/s的速度涌入。
这时,新创建的httpd线程将如何呢?
Httpd进程通过mod_jk 模块所管理的空闲的AJP连接,将请求转发给Tomcat。如果没有空闲连接,他会申请创建新的连接。但是,因为Tomcat暂停了,创建新连接的请求会被拒绝。因此这些请求会被存储在backlog队列中,数量的多少取决于server.xml中关于AJP Connector的设置。一旦请求数量超过backlog队列的空间限制。Apache就会返回拒绝连接错误。并且返回HTTP 503 错误给用户。
在这种假设条件下,默认的backlog队列空间是100,而请求到达速度是200 req/s。因此,full GC导致的一秒钟的暂停会使得超过100个请求返回503错误。
这样,当Full GC结束后,backlog队列中存储的内容会被Tomcat接受并在通过工作线程处理,线程的最大数量取决于MaxThreads
的值(默认200)。
MaxClients 与backlog
在这种情况下,设定哪个参数可以避免返回给用户503错误呢?
首先,我们应该知道backlog的值要够大,以至于能够容纳所有因为Full GC导致暂停期间涌入的请求。换句话说太应该不小于200。
那么,这么设置之后会不会产生新的问题呢?
让我们假设将backlog设置为200后再重复一下上面的过程。得到的结果比之前更加严重。系统内存使用量一般情况下为50%,但是,在发生Full GC时快速增加到100%,同时导致交换内存空间快速增加,更为严重的是导致Full GC的暂停时间从1秒变成了4秒甚至更多,系统在此期间完全宕机,不能响应任何请求。
在第一种情况下,只有100或更多的请求返回503错误。但是,当我们把backlog调整到200后,超过500个请求会挂起3秒甚至更多地时间无法得到应答
上面这个例子可以很好的说明当你没有完全理解各个设置之间的内在关系时(例如,对于系统的影响),盲目修改系统会导致什么后果。
那么,为什么会产生这个现象呢?
问题的根源在于 MaxClients
参数的特性。
将MaxClients
设置为一个很大的值本身没有问题,但最重要的是在设定MaxClients
参数时,你要确保即使等同于MaxClients
数量的httpd进程被同时创建,内存使用量也不会超过80%。
系统的内存交换参数一般被设定为60(默认)。因此,当内存使用量超过80%时,就会进行内存交换。
让我们再来看一下为什么这个特性会导致上面那个严重的问题。当请求以200 req/s的速度涌向Tomcat时,Tomcat由于full GC暂停了。此时backlog被设置为200。Apache大约创建100个httpd进程。在这种情况下,一旦内存使用量超过80%,操作系统会激活交换内存区域,并且由于系统认为JVM的老年代中的对象在很长一段时间内未被使用,而将他们移动到交换区域。
最终的结果是,GC使用了内存交换空间,暂停时间剧增。因此httpd进程数进一步增加。从而导致上面描述的内存使用量达到100%的情况。
这两个场合的唯一区别就是backlog的值:100 vs.200。为什么只在200的情况下发生?
两者不同的原因在于创建的httpd进程的数量。当backlog设置为100时并且Full GC发生时,会创建100个请求的连接并保存在backlog队列中。其他请求得到拒绝连接错误信息并发挥503错误。因此,总的httpd 进程数量仅仅会略高于100。而当backlog被设置为200时,200个请求会创建连接,因此。总的httpd进程数会多于200。这样超过阀值,从而导致内存交换的发生。紧接着,不考虑内存使用量而的设定 MaxClients
参数,Full GC导致httpd进程数量暴增,引发内存交换,降低系统性能。
MaxClients参数的计算公式
如果系统的内存使2GB,MaxClients
的值在任何情况下都不应该超过内存的80%(1.6GB),以避免由于内存交换导致的性能下降。换句话说。1.6GB的内存应该共享和分配给Apache,Tomcat以及那些默认被安装的代理程序。
让我们假设代理程序被默认安装在系统,并占用了200m内存,对于Tomcat堆内存的-Xmx
被设定为 600m。因此根据top命令的结果,Tomcat会一直占用725m(Perm Gen + Native Heap Area)。最终Apache可以使用700m内存空间。如下所示。
图2:测试系统的top截屏
如上所述,我们将内存设为700m后MaxClients
应该是多少呢?
这要取决于加载模块的数量,对于NHN Web服务来说。Apache只是个简单的代理转发,每个httpd线程4m内存(根据top命令的结果)足以(参见图2)。因此。700m内存对应的 MaxClients
应该是175。
总结
一个健壮的服务配置至少应该能够降低在服务过载时宕机的时间,在合理的范围内成功的应答请求。针对基于Java的Web服务。你必须检查你的服务在Full GC导致的STW时间内能否稳定的响应请求。
为了响应更多的用户请求和应对DDoS攻击,在没有全面考虑系统内存等因素的情况下,贸然地将 MaxClients
设置为一个很大的值,那么它将失去作为阀值的功能,而导致系统出现更严重的问题。
本文提到的情况只会持续3-5秒,因此绝大多数传统的监控工具都无法及时的发现。
成为Java GC专家(4)—Apache的MaxClients参数详解及其在Tomcat执行FullGC时的影响的更多相关文章
- apache httpd.conf 参数详解
由于网站需要,需要配置多个虚拟主机,但是apache主机的参数太多,记不住,下面做一下总结 归纳: ServerRoot:apache安装位置 Listen:服务器监听的端口号 LoadModule: ...
- Apache之AllowOverride参数详解
通常利用Apache的rewrite模块对 URL 进行重写的时候, rewrite规则会写在 .htaccess 文件里.但要使 apache 能够正常的读取.htaccess 文件的内容,就必须对 ...
- 【原创】Apache ab结果参数详解
解释如下: Server Software 服务器软件软件名称. Server Hostname 被测服务器的主机名. Server Port 被测试的Web服务器的监听端口. SSL/TLS Pro ...
- Java GC专家系列4:Apache的MaxClients设置及其对Tomcat Full GC的影响
本文是GC专家系列中的第四篇.在第一篇理解Java垃圾回收中我们学习了几种不同的GC算法的处理过程,GC的工作方式,新生代与老年代的区别.所以,你应该已经了解了JDK 7中的5种GC类型,以及每种GC ...
- Java GC专家系列1:理解Java垃圾回收
了解Java的垃圾回收(GC)原理能给我们带来什么好处?对于软件工程师来说,满足技术好奇心可算是一个,但重要的是理解GC能帮忙我们更好的编写Java应用程序. 上面是我个人的主观的看法,但我相信熟练掌 ...
- 零拷贝详解 Java NIO学习笔记四(零拷贝详解)
转 https://blog.csdn.net/u013096088/article/details/79122671 Java NIO学习笔记四(零拷贝详解) 2018年01月21日 20:20:5 ...
- apache的prefork的详解
apache的prefork的参数详解:ServerLimit 2000 这是最大进程数的阀值StartServers 25 启动时建立的子进程MinSpareServers 25 最小空闲进程Ma ...
- java实现excel的导入导出(poi详解)[转]
java实现excel的导入导出(poi详解) 博客分类: java技术 excel导出poijava 经过两天的研究,现在对excel导出有点心得了.我们使用的excel导出的jar包是poi这个 ...
- JAVA命令参数详解
JAVA命令参数详解 JAVA命令详解 结构 说明 Java 和 OldJava JIT 选项 另请参阅 结构 java [ options ] class [ argument ... ] java ...
随机推荐
- CSS 之 清除 float 常用的方法
大多数前端使用.clearfix:after{ .....} 和 .clearit{....}的组合来清除浮动. 前端开发经常用到浮动 float:left; float:right; 有浮动就需要 ...
- React Editor 应用编辑器(1) - 拖拽功能剖析
这是可视化编辑器 Gaea-Editor 的第一篇连载分析文章,希望我能在有限的篇幅讲清楚制作这个网页编辑器的动机,以及可能带来的美好使用前景(画大饼).它会具有如下几个特征: 运行在网页 文档流布局 ...
- 利用android studio gsonformat插件快速解析复杂json
在android开发过程中,难免会遇到json解析,在这篇文章中为你快速解析复杂的json. 首先,在android studio中安装gsonformat插件. 点击File->Setting ...
- [引]LINQ to XML 类概述
本文转自:http://msdn.microsoft.com/zh-cn/library/bb387023.aspx 本主题提供 System.Xml.Linq 命名空间中 LINQ to XML 类 ...
- RPC之Thrift学习实战
关于Thrift的学习实战请参考:http://blog.csdn.net/column/details/slimina-thrift.html
- React组件生命周期过程说明【转】
实例化 首次实例化 getDefaultProps getInitialState componentWillMount render componentDidMount 实例化完成后的更新 getI ...
- h2database源码浅析:MVTable与MVIndex
Database包含一个Store:MVTableEngine.Store getMvStore() MVTableEngine.Store可以获取各tables:java.util.HashMap& ...
- js中的null与undefined
null undefined
- zookeeper实现商品秒杀抢购
package com.test; import java.io.IOException; import java.util.List; import java.util.concurrent.Cyc ...
- asp.net 备份和恢复数据库
观看了Insus的视频写下来的,代码可能有点冗长,如有好的想法的,可以多交流. 前台: <form id="form1" runat="server"&g ...