Apache常用的两种MPM
讨论这个问题时,有必要先界定Apache运行时到底load的是哪个MPM,prefork和worker毕竟运行时在Server端的资源消耗有一些差别。
- prefork:典型的“一连接一进程”模式(每个进程内部就启动一个系统线程),在相同的并发连接情况下,显然要比worker模式消耗更多系统资源(最主要消耗的就是Server的RAM,其实很多时候,调优关注的焦点也是如何合理的利用RAM以控制不会因为过多进程存在而导致频繁使用swap)。不过正是因为他没有线程共享上下文的顾虑,很多时候使用他是最安全最方便的,因为你也不用操心你load的其他module里面是不是有啥线程不安全的主儿了。在RedHat下,这个模式也是Apache的defalut MPM模式。prefork模式下,常用的设置参数有如下几个:
- StartServers:启动Apache是默认启动服务进程数,这个设置和下面的worker是相同的,下面不在赘述。
- MaxClients:这个是真正控制单台host上Apache真正能控制的最大并发连接数。这个参数很重要,是你计算系统峰值时消耗系统资源的主要依据,也是Apache自己在worker模式下计算最多能开启多少个活动子进程的依据(MaxClients/ThreadsPerChild)。这个设置和下面的worker是相同的,下面不在赘述。
- MinSpareServers:这个配置我觉得把名字改成MinIdleServers也行,意思看看字面就明白了,就是最少要保证Server这边有几个空闲进程在那里随时待命。也就是说,你启动Apache之后,最少会有这些个子进程一直在那里开着。这个是最空闲状态,就是根本没有请求进来的时候,通常的Apache子进程数量都会大于这个数字。
- MaxSpareServers:和上一个指令对应的一个指令,用于控制空闲进程的上边界。不多说了。
- MaxRequestPerChild:这个指令是我觉得最容易让人模糊的一个。字面意思就是单个子进程最多服务多少个请求。为啥一个进程还有服务请求数量的限制啊?其实按Apache官方的设计思路来说,就是说,就算Server再忙,当一个子进程已经处理了这些个请求之后,你也得“退休”了。因为年纪大了吗,总有些眼神儿不好使,反应迟钝之类的问题了嘛。。。但是这个时候子进程不是被辞退,而是被无情的kill掉。其实这种实现方式也是不无道理的,简单暴力的防止内存泄露。有一点需要注意的是如果这个参数被设置为了0的话,那么恭喜Apache子进程,他们将获得终身成就奖,永远活着那里了。。。这个设置和下面的worker是相同的,下面不在赘述。
- worker:和prefork相比,这个应该算是“一连接一线程”了。每个有Apache主进程fork出来的子进程都会自己启动N个自己的内部线程,用来提供对外部请求的服务。至于这个N到底是多少,就看你的ThreadsPerChild参数设置成几了。常用参数有下面几个:
- StartServers:上面提到的。
- MaxClients:上面提到的。
- MaxRequestPerChild:上面提到的。
- ThreadPerChild:上面提到的。
- MinSpareThreads:对比一下prefork模式下的MinSpareServers,这个就好理解了,只是这个设置成Thread级别的数量限制了。
- MaxSpareThreads:类比同上。
KeepAlive or Not?
KeepAlive这个词应该平时听到比较高的,这个玩意也更好理解一些,就是client和Server之间保持一个http的长连接。随便用chrome打开一下亚马逊或者淘宝的首页,打开开发者工具,看一下网络请求的header部分,你就看到connection那一项写的是这个了。
为啥要开启这个长连接?因为通常情况下client一次有好多request发给server,如果不开启这个设置,那么有多少次request,就得重新建立多少次http连接——因为http是无状态的。所以,这个设置其实在一些静态缓存资源的服务器上格外有用。比如你的某个页面,有50个js的link,50css的link,对于一个现代网页来说,这个假设并不夸张。如果你开启了KeepAlive,那么一个browser访问这个网页的时候,只要跟你的Server建立一次连接就可以了,虽然browser照样要请求100次。但是根据KeepAlive的协议,browser知道他可以和server复用这个已经创建的连接。
KeepAlive常用的设置参数包括下面几个:
- KeepAlive:on or off,这个不用解释了吧。
- MaxKeepAliveRequests:这个参数很重要,通常一个http的长连接,并不是因为有更多的请求可以复用而可以无休止的使用的。他有一个最多可以复用request通道的上限,这个上限就在这里设置。
- KeepAliveTimeout:这个表示在已经建立的connection上最多等待多长时间有新的请求进来,单位是秒。这个配置项的默认值是15秒,通常的应用场景这个值都太长了,所以一般当你开启了KeepAlive之后,这个值都得手动重新设置,推荐的值是小于5秒。否则,如果时间太长,当你的网站同时访问的用户很多时,你的server很可能就杯具了。。。另外,请不要把这个参数和Apache的另一个参数Timeout搞混了,这个纯粹的Timeout表示的语义要远比这个KeepAliveTimeout复杂,总的来说是一次http请求过程中,Apache最长愿意block在那里的时间。比如,你的web server处理个页面半天处理不完,他timeout;Apache等待浏览器传输个数据,他因为网络延迟半天不过来,他timeout;Apache往浏览器传输response数据,自己的send buffer都满了,可是因为网络延迟或者丢包啥原因的,browser就是不鸟你,他timeout。。。
到底选择哪个?
仔细分析一下,MPM和KeepAlive其实是从两个不同的维度进行优化,前者是配置Server端的worker的数量(不管是进程还是线程),后者则是关注提高每次好不容易建立起来的http连接的利用效率。两者并不矛盾,所以通常的调优两者可以并行。但是关于具体每个Apache指令到底设置成啥,这个经验值其实未必都可以复用。网上可以搜到一坨坨的示例配置,但是他到底适不适用你的网站,其实这个直接跟你访问量、访问类型都直接相关,没有一个绝对值。而且这点很难通过压测得到真正合理的配置,因为压测本身容易模拟高并发,但却未必能轻易能模拟你的真是业务场景。
一种靠谱的方法就是先找一个差不多可以用的经验配置值,然后在真是的生产环境,观察你机器load、memory消耗、网络连接等指标,再根据这些指标作出微调。通常情况下,在linux下,这些数据可以通过top、free、netstat之类命令就可以直接获得了。
PS:以上总结仅仅是普通青年Apache调优关注的常见的几个参数,所以题目才说是三板斧。如果你是文艺青年,需要进阶更高境界,那么你得进入更深层次了。
?