Apache2.2.14(Ubuntu)修改最大连接数

图片 4

本文是GC专家系列中的第四篇。在第一篇理解Java垃圾回收中我们学习了几种不同的GC算法的处理过程,GC的工作方式,新生代与老年代的区别。所以,你应该已经了解了JDK
7中的5种GC类型,以及每种GC对性能的影响。

网站禁止图片盗链,此文适用于Ubuntu
Linux系统。首先需要确定服务器httpd的工作模式呢,可通过执行 apachect2 -l
来查看:

  Apache是运行在Linux操作系统上的头号Web服务器。很多小地方都可以用来调整Apache的性能,并降低它对系统资源的影响。其中一个就是调整内存使用率,当然达到这一目的可能还是需要花点功夫的。

在第二篇Java垃圾回收的监控中介绍了在真实场景中JVM是如何运行GC,如何监控GC数据以及有哪些工具可用来方便进行GC监控。

图片 1

  例如,通过ps来确定httpd线程的内存使用率,可以输入下面的命令:

在第三篇GC
调优中基于真实案例介绍了可用于GC调优的最佳选项。同时也描述了如何通过降低移动到老年代中对象的数量来缩短Full
GC耗时,以及如何设置GC类型及内存大小。

可以看到有prefork.c,因此httpd是工作在prefork并发模式。

  # ps -U apache -u apache u

本文将介绍Apache的MaxClients参数的重要性以及在GC发生时对系统整体性能的显著影响。通过几个例子,你将会更清晰的理解MaxClients值所引发的问题。最后会介绍如何依据系统的可用内存来为MaxClients设置合理的数值。

打开apache2的配置文件sudo vi /etc/apache2/apache2.conf

  USERPID %CPU %MEMVSZRSS TTYSTAT START TIME COMMAND

MaxClients对系统的影响

NHN的服务运行环境中有大量的流控(Throttlevalve)选项,这些选项对系统的稳定运行具有重要作用。我们来看下Apache的MaxClients选项在Tomcat发生Full
GC时会对系统带来哪些影响。

大部分的开发人员都知道GC 发生中会伴随着”stop the
world(STW)现象”(具体详情参考理解Java垃圾回收)。尤其是NHN的Java开发人员可能都经历过在Tomcat中由GC相关问题而导致的系统崩溃。因为JVM管理内存,因此Java应用系统不可避免的会遇到GC引起的STW现象。

在你开发的线上系统中,GC每天都会发生很多次。在GC发生时,即便TTS没有发生,却依然可能会给用户503的错误响应。

apache2的并发控制模式,包括prefork和worker的部分修改为:

  apache130670.05.3 149704 54504 ?SOct071:53 /usr/sbin/httpd -f
/etc/httpd/conf/httpd.conf -DAPACHE2

系统运行环境

根据结构特点,Web服务更适合于做横向扩展而非单纯的提高单一机器的性能。所以通常根据性能需要,Web服务的服务器部署结构由一台Apache服务器和多台Tomcat服务器组成。在本文中,假设一个Apache服务和Tomcat服务部署在同一台物理主机上,如下图所示:

图片 2
图1: 本文假设的服务运行环境

作为参考,本文所述参数均是基于Apache 2.2.21(prefork MPM),Tomcat
6.0.35,jdk 1.6.0_24,并运行在CentOS 4.7.2(32位)操作系统上。

系统内存2GB,并使用ParallelOldGC垃圾回收,默认开启了AdaptiveSizePolicy选项并设置堆大小为600MB。

图片 3 

  …

STW 和 HTTP 503

假设Apache的流量为200QPS,并开启10个httpd处理进程(尽管实际场景依赖于请求的响应时间)。在这种前提下,假设full
GC导致的停顿耗时1秒,如果Tomcat发生了Full GC将会怎么样?

首先你能想到的是full
GC导致Tomcat停顿,处理中的请求将得不到响应。如果这样,Tomcat暂停,请求得不到处理,Apache将会怎么样?

即使Tomcat因Full GC而暂停处理,而请求却仍以200
req/s的速度到达Apache。在full
GC发生前,只需要10个或者稍微多一点的httpd进程就可以快速响应服务请求。但是现在Tomcat暂停了,为了处理新的请求Apache将持续创建新的httpd进程直到httpd.conf文件中定义的MaxClients阀值。因为MaxClients默认值为256,所以200
req/s的请求并不会带来太大问题。

这个时候,新创建的httpd 进程会怎么样?

Httpd
进程使用mod_jk模块管理的AJP连接池中的空闲连接把请求发送到Tomcat。如果没有空闲连接,则会要求创建新的连接。然而因为Tomcat处理暂停状态,新建连接的请求将被拒绝。所以这些请求将会放到堆积队列(backlog
queue),队列的长度是server.xml的AJP Connector中设置的。

如果请求数据超出了堆积队列的长度,Apache将会收到连接拒绝错误,并把这个错误以HTTP
503的方式返回给用户。

在本例的中,堆积队列的长度默认设置为100,而请求速度为200
req/s,因此在由full
GC导致Tomcat暂停的这1秒中,将有超过100的请求将会收到503错误。

Full
GC结束之后,堆积队列中的socket连接会被Tomcat接收并分配给工作线程(最大工作线程数由MaxThreads决定,默认值为200)来处理请求。

然后重启apache2:
sudo /etc/init.d/apache2 stop
sudo /etc/init.d/apache2 start
即完成设置。
 
注意,MaxClients默认最大为250,若要超过这个值就要显式设置ServerLimit,且ServerLimit要放在MaxClients之前,值要不小于MaxClients,不然重启时会有提示。重启apache2后,通过反复执行pgrep
httpd|wc
-l来观察连接数,可以看到连接数在达到MaxClients的设值后不再增加,但此时访问网站也很流畅,那就不用贪心再设置更高的值了,不然以后如果网站访问突增不小心就会耗光服务器内存,可根据以后访问压力趋势及内存的占用变化再逐渐调整,直到找到一个最优的设置值。

  上面这段输出显示了单个httpd进程使用了50
MB的RSS(驻留集大小)内存(或者非交换物理内存),以及149
MB的VSZ(虚拟)内存。这当然在很大程度上取决于你在Apache里加载和运行的模块数量。这决不是一个固定的数字。由于这个数字里还包含了共享库包,所以不是100%的准确。我们可以认为RSS数字的一半是httpd线程真正使用的内存数,这可能还有点保守,但是离我们的目的已经非常接近了。

MaxClients和堆积队列

在上面的场景中,如何设置才能避免给用户返回503错误?

首先我们需要知道,应该设置足够的堆积队列长度以容纳在Tomcat Full
GC导致的暂停期间流入的请求。因此堆积队列最小长度至少为200(上文中QPS为200)。

这样配置以后,是否还有其他问题?

把堆积队列长度设置为200后,我们再次重复上面的场景。结果问题却比之前更加严重。

正常情况下系统内存使用量维持在50%,而在发生Full
GC时内存使用却迅速上升到100%,引起内存交换区(swap)使用量的极剧增加。更为严重的是Full
GC导致的响应停顿由原来的1秒增加到了4秒,直接后果就是期间系统像挂掉了一样,不能响应任何请求。

在之前的场景中,只有100左右的请求会收到 503
的错误,而增加堆积队列到200后却导致了500甚至更多的请求被挂起至少3秒不能收到任何响应。

这个例子很好的证明了如果不能准备的理清配置信息之间的因果关系,可能会对系统带来极为严重的影响。

为什么会这样?

原理就是要清楚MaxClients选项的特性。

MaxClients的值不易设置过大,设置MaxClients的关键在于即便创建了MaxClients数量的httpd进程,也要需要维持应用系统的内存使用量不应超过80%。

系统交换区默认值为60,因此如果内存使用超过80%,系统将会发生频繁的内存交换。

我们再来看下为什么这个特性会导致上面所述的严重后果。

当请求的QPS为200时,Tomcat会被Full
GC暂停响应,然后把堆积列队容量设置为200。起初大约有100个额外的httpd
进程会被Apache创建,紧接着内存使用量超过了80%,引起操作系统主动的使用交换区的内存空间,而因GC存活在JVM老年代中的对象被操作系统误认为长时间未使用,从而导致这些对象被移动到交换区。

最后,当GC过程中涉及到交换区时,耗时就会迅速增加。而后httpd进程数继续增加,导致内存使用量达到了100%,从而出现了上述的严重后果。

上述案例的前后区别仅在于堆积队列的长度:100和200。但为什么在200时会出现更严重的状况?

原因是堆积队列不同的长度导致了httpd进程数的不同。当值为100时,在发生Full
GC时100个请求所要求创建的连接被置于堆积队列中。再有新的请求会被拒绝并返回503错误,所以系统的整个httpd的进程数仅超出100很少的数量。

但当队列长度设置为200时,有200个请求被接收并置于队列中。从而导致httpd进程的数量超过200,并触发了操作系统进行内存交换的阀值。

所以,如果不顾内存使用情况而一味的加大MaxClients的数值,将会导致Full
GC时httpd进程数迅速增加,引进内存交换并最终降低系统的整体性能。

所以如何设置MaxClients,如何找到当前系统的阀值?

MaxRequestsPerChild不能设置为0,可能会因内存泄露导致服务器崩溃。

  在本文里,我们假设每个httpd进程都在使用了27
MB内存。然后,你需要确定可以让httpd真正使用的内存数。根据运行在机器上的其他进程,你可能希望要求50%的物理内存都供Apache使用。在一个装有1GB内存的系统上,就有512MB的内存可以被划分为多个27MB的内存,也就是大约19个并发的httpd内存。有些人坚持认为每个httpd
线程“真正”使用大约5MB的内存,所以从理论上讲你可以把512MB的内存划分出102个并发进程供Apache使用(要记住的是,除非你的网站需要极其巨大的流量,否则这种情况是非常罕见的)。

MaxClients 取值的计算方式

如果系统总内存为2GB,设置MaxClient的值需要保证在任何时候内存的使用量不超过80%即1.6GB,从而避免因内存交换导致的性能下降。也就是说仅有1.6GB空间供Apache,
Tomcat和其他默认安装的代理程序共享和分配内存。

假如默认安装的代理程序占用200M内存;Tomcat的堆空间设置-Xmx为600M,如下图所示,Tomcat总占用量将725M
(持久代 + 本地堆空间)。Apache可使用的空间为剩下的700M。

图片 4
图 2:Top命令的截图

对于Apache的700M内存,该如何设置合理的MaxClients值?

当然这也取决于Apache加载的模块类型和数量。以NHN的Web服务为例,把Apache当作简单的代理使用,根据上图RES显示,4M空间对于每个httpd进程来说已足够使用。因此700M空间能设置的MaxClients为175。

附:常用参数解释

  在默认状态下,Apache会分配最大256个并发客户端连接,或者256个进程(每一个都对应一个请求)。按照这种设置,一个流量巨大的网站会在顷刻间崩溃(即使你假设每个进程占用5MB内存,那也需要1.3GB的内存来满足请求的数量)。如果不采取其它措施,系统会通过硬盘来尝试使用交换空间以处理它无法在物理内存中完成的任务。

总结

可靠的服务配置要能够在满载的情况下降低系统停顿时间并能够最大范围的保证成功响应用户请求。对于Java应用来说,必须要确认在Full
GC引起的SWT情况下,系统的配置是否能够提供足够可靠的服务。

如果为了应对单纯的请求增加和防止DDos攻击,在不考虑内存使用的情况下把MaxClients设置过大,那么MaxClients不但会失去作为流控的用途,反而会带来更为严重的后果。

在这个案例中,解决问题的最优途径是加大系统的内存,或者设置MaxClients为175(上面的计算结果)以保证只有QPS超过175时才会出现503错误。

<IfModule prefork.c>
#有这个参数就不必像apache1一样修改源码才能修改256客户数的限制,听讲要放到最前面才会生效,2000是这个参数的最大值
ServerLimit 2000
#指定服务器启动时建立的子进程数量,prefork默认为5。
StartServers 25
#指定空闲子进程的最小数量,默认为5。如果当前空闲子进程数少于MinSpareServers
,那么Apache将以最大每秒一个的速度产生新的子进程。此参数不要设的太大。
MinSpareServers 25
#设置空闲子进程的最大数量,默认为10。如果当前有超过MaxSpareServers数量的空闲子进程,那么父进程将杀死多余的子进程。此参数不要设的太大。如果你将该指令的值设置为比MinSpareServers小,Apache将会自动将其修改成”MinSpareServers+1″。
MaxSpareServers 50
#限定同一时间客户端最大接入请求的数量(单个进程并发线程数),默认为256。任何超过MaxClients限制的请求都将进入等候队列,一旦一个链接被释放,队列中的请求将得到服务。要增大这个值,你必须同时增大ServerLimit

MaxClients 2000
#每个子进程在其生存期内允许伺服的最大请求数量,默认为10000.到达MaxRequestsPerChild的限制后,子进程将会结束。如果MaxRequestsPerChild为”0″,子进程将永远不会结束。
MaxRequestsPerChild 10000
</IfModule>
将MaxRequestsPerChild设置成非零值有两个好处:
1.可以防止(偶然的)内存泄漏无限进行,从而耗尽内存。
2.给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。
工作方式:
一个单独的控制进程(父进程)负责产生子进程,这些子进程用于监听请求并作出应答。Apache总是试图保持一些备用的
(spare)或者是空闲的子进程用于迎接即将到来的请求。这样客户端就不需要在得到服务前等候子进程的产生。在Unix系统中,父进程通常以root身份运行以便邦定80端口,而
Apache产生的子进程通常以一个低特权的用户运行。User和Group指令用于设置子进程的低特权用户。运行子进程的用户必须要对它所服务的内容有读取的权限,但是对服务内容之外的其他资源必须拥有尽可能少的权限。
我们调优常常要查看httpd进程数(即prefork模式下Apache能够处理的并发请求数):
#ps -ef | grep httpd | wc -l
出现的结果,就是当前Apache能够处理的多少个并发请求,这个值Apache根据负载情况自动调。

  其他可以调整的项目包括KeepAlive、KeepAliveTimeout和MaxKeepAliveRequests等设置。可以放在httpd.conf文件里的推荐设置有:

相关阅读

  ServerLimit 128MaxClients 128KeepAlive OnKeepAliveTimeout
2MaxKeepAliveRequests 100

Linux下Apache与Tomcat的完全分布式集群配置(负载均衡)
http://www.linuxidc.com/Linux/2013-08/89072.htm

  通过把KeepAliveTimeout从15秒减到2秒,可以增加MaxClients命令;19太小,而128要好得多。通过减少进程存活的秒数,你可以在相同的时间内允许更多的连接。

Linux网站架构系列之Apache—-部署篇 
http://www.linuxidc.com/Linux/2013-11/92304.htm

  当然,如果没有真正的测试在背后支持,数字就是毫无意义的,这就是ab的作用之所在。使用ab对Apache配置文件(MaxClients等于
256、ServerLimit等于256、KeepAliveTimeout等于15)进行调整,使其能够满足1000个请求(100个连续请求并发产生)的调整方法如下。(在执行测试的时候要确保服务器上有一个终端打开以观察系统的负载。)

日志分析工具Awstats实战之Apache篇-多站点日志分析
http://www.linuxidc.com/Linux/2013-11/92273.htm

  $ ab -n 1000 -c 100 -k

在Ubuntu 13.10 下安装支持SSL的Apache 
http://www.linuxidc.com/Linux/2013-11/92266.htm

  现在把上面的服务器设置改为更加保守的设置,重新启动Apache,试着再次测试(总是从远程计算机上进行,而不是本机)。

Apache2(http.2.4.6) + Tomcat 7.0 集群安装与配置
http://www.linuxidc.com/Linux/2013-11/92322.htm

  在这里的测试中,不同的设置导致执行所消耗的时间产生了一倍的差距(分别为27.8s和16.8s),但是负载的平均值为0.03和0.30。这可能会使得你的网站变得稍慢,但是会确保它不会在高负载的情况下崩溃。还要记住的是,你把需要进行多次测试,以便取得一个平均值。

更多Ubuntu相关信息见Ubuntu 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=2

  使用ab是测试调整Apache配置的一个极佳方法,应该在你每次做出影响性能的更改时使用它。图片 5

图片 6

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图