一、多道处理模块 MPM

    Apache HTTP 服务器被设计为一个功能强大,并且灵活的 web 服务器, 可以在很多平台与环境中工作。不同平台和不同的环境往往需要不同的特性,或可能以不同的方式实现相同的特性最有效率。Apache 通过模块化的设计来适应各种环境。这种设计允许网站管理员通过在编译时或运行时,选择哪些模块将会加载在服务器中,来选择服务器特性。        

    Apache 2.0 扩展此模块化设计到最基本的 web 服务器功能。 它提供了可以选择的多处理模块(MPM),用来绑定到网络端口上,接受请求, 以及调度子进程处理请求。

     MPM的设计,带来两个重要的好处:

  • Apache 能更优雅,更高效率的支持不同的平台。

  • Apache 能更好的为有特殊要求的站点定制。例如,要求更高伸缩性的站点可以选择使用线程的 MPM,即 worker 或 event;需要可靠性或者与旧软件兼容的站点可以使用 prefork

    在用户看来,MPM 很像其它 Apache 模块。主要是区别是,在任何时间, 必须有一个,而且只有一个 MPM 加载到服务器中。


二、选择 MPM

    MPM 必须在编译前,./configure 配置时指定,然后编译到服务器程序中。 仅当编译器知道使用了线程时,它才有能力优化许多函数。

    为了使用指定的 MPM,请在执行 configure 时,使用参数 --with-mpm=NAMENAME 是指定的 MPM 名称,我们只可以指定其中一个MPM模块。编译完成后,可以使用 ./httpd -l 来确定选择的 MPM。 此命令会列出编译到服务器程序中的所有模块,包括 MPM。 Unix/Linux支持三种MPM, Prefork, worker, event,其中event模型在apache2.2版本是测试版,不建议在生产环境中使用,到apache2.4,event模型是稳定版。

  • prefork    多进程模型

    预先生成进程,一个请求用一个进程处理。优点:稳定可靠,任何一个进程崩溃都不会影响其他进程;缺点:性能差,特别是并发量非常大时,非常消耗内存资源,会有大量的进程切换。

  • worker    多线程模型

    基于线程,启动多个进程,每个进程中生成多个线程。进程负责响应请求,而线程负责处理请求。因为linux不是原生支持线程,线程同步模型复杂,必须处理锁争用的问题,所以在Linux上不建议。测试发现,在linux系统上,worker 的效率并没有 prefork 高。这是默认不是worker的原因。

  • event    IO多路复用,基于事件驱动的模型。一个进程处理多个套接字,一个进程同时处理多个请求。在httpd 2.2 版本中属于测试版,在apache 2.4 之后是稳定版,强烈推荐。


    

    可以使用 httpd -l 来确定当前选择的 MPM。 此命令会列出静态编译到服务器程序(modules compiled into the server)中的所有模块,包括 MPM。

# -l Output a list of moudles compiled into the server. This will not list dynamically l# oaded modules included using the LoadModule directive.
[root@localhost ~]# httpd -l
Compiled in modules:
  core.c           # 核心
  prefork.c         # 编译到httpd服务器的MPM模块
  http_core.c
  mod_so.c          # 支持DSO动态模块加载


三、prefork

    prefork的工作原理是:控制进程在最初建立“StartServers”个子进程后,为了满足MinSpareServers设置的需要创建一个进程,等待一秒钟,继续创建两个,再等待一秒钟,继续创建四个……如此按指数级增加创建的进程数,最多达到每秒32个,直到满足 MinSpareServers设置的值为止。这就是预派生(prefork)的由来。这种模式可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。   

    prefork 为多路模块MPM 实现了一个进程模型,非线程型的,预派生 的web服务器。prefork 适用于没有线程安全库,需要避免线程兼容性问题的系统。它是要求将每个请求相互独立的情况下最好的MPM,这样一个请求出现问题,不至于影响其他的请求。

      prefork模式使用多个子进程,每个子进程在某个确定的时间只能维持一个连接。在大多数平台上,Prefork MPM在效率上要比Worker MPM 要高,但是内存使用大的多。prefork在Linux下工作,比worker更有优势。

    一个单独的控制进程(父进程)负责生产子进程,这些子进程用于监听请求并作出应答。apache 总是试图保持一个备用的(spare)或是空闲的子进程用于迎接即将到来的请求。这样客户端就无需在得到服务前等候子进程的产生。在unix系统中,父进程通常是以root 身份运行以便绑定80端口,而apache生产的子进程通常一个低特权的用户运行。User和Group指令用于配置配置子进程的低特权用户。运行子进程的用户必须要对他所服务的内容用读取的权限,但是对服务内容之外的其他资源必须拥有尽可能少的权限。

    当httpd服务启动之后,会启动一个主进程(master process),它负责监听用户请求,以及派生和销毁子进程。它并不处理用户请求,一旦请求来了之后,调度其子进程(work process)来响应,然后继续监听其他请求。

    需要考虑的是:刚启动的时候,创建多少空闲进程呢?为了快速响应用户请求,会创建几个空闲进程,当请求来了,可以快速的响应。如果请求太多,那么则会派生更多的进程来响应请求,但是假设到了晚上,访问量不大时,我们应该把多余的空闲进程回收,以免占用资源。

master process的主要作用:

1、启动服务时绑定特权端口

2、派发和回收子进程

3、读取分析主配置文件

4、监听用户请求并且调度子进程来响应


配置:编辑主配置文件 /etc/httpd/conf/httpd.conf

# prefork MPM
<IfModule prefork.c>         # 判断是否有prefork.c这个模块,有就生效,否则无效
StartServers      8          # 服务初始化的工作进程数(work process)
MinSpareServers    5         # 保持的最少空闲进程数
MaxSpareServers     20       # 保持的最大空闲进程数
ServerLimit      256         # 保持的最大活动进程数,设定MaxClients的上限值
MaxClients       256         # 最大并发连接数
MaxRequestsPerChild  4000    # 每个子进程在生命周期能服务的最大请求数
</IfModule>

    IfModule 指令,意为判断模块是否存在,如果存在那么参数则生效,反之如果不存在此模块,参数将不会生效。

StartServer 8

   指定服务器启动是建立的子进程的数量,prefork 默认为5。为了满足MinSpareServers设置的需要创建一个进程, 等待一秒钟,继续创建两个,再等待一秒钟,继续创建四个……如此按指数级增加创建的进程数,最多达到每秒32个,直到满足 MinSpareServers设置的值为止。这就是预派生 (prefork)的由来。这种模式可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。

MinSpareServers 5 

     指定维持空闲子进程的最小数量,默认为5。假如当前空闲子进程数少于MinSpareServers,那么apache 将以每秒一个的速度产生新的子进程。此参数不要设置的太大。举个例子:MinSpareServers 限定为5个,当有4个请求来了之后, 8 - 4 还剩4个,那么为了维持5个MinSpareServers, 就必须再创建一个子进程。

MaxSpareServers 20

      设置保持空闲进程的最大数量,默认为20。如果当前有超过MaxSpareServers数量的空闲子进程,那么父进程将杀死(kill)多余的子进程。此参数不要设置过大。如果该参数设置比MinSpareServers小,apache将会自动将其修改成"MinSpareServers+1”。如果站点负载较大,可考虑同时加大MinSpareServers和MaxSpareServers。

MaxClients 256

       限定同一时间客户端最大接入的数量(单个进程并发线程数)。默认为256,任何超过MaxClients限制的请求都会进入等候队列,一旦一个链接被释放,队列中的请求将得到服务。MaxClients的值不能超过 ServerLimit, 如果要增大这个值,必须同时增加ServerLimit.理论上来说这个值越大,性能就越好。最重要的值是MaxClients允许足够多的工作进程,同时又不会导致服务器当机。

    可通过查看httpd进程数:# ps -ef | grep httpd | wc -l,选择高峰期,结合当时服务器资源使用情况,来设置MaxClients。

ServerLimit 256

   默认的MaxClient最大是256个进程,假如想设置更大的值,就需要加上ServerLimit这个数。 200000是ServerLimit这个参数的最大值。假如需要更大,则必须编译apache,此前都是无需重新编译apache。生效前提是,必须放在其他指令的前面。

   要调整ServerLimit的值,首先必须关闭httpd服务,调整后再重启httpd。

MaxRequestsPerChild

       每个子进程在其生存期内允许伺服的最大请求数量(每一个子进程最多响应多少次请求)。默认为10000到达MaxRequestsPerChild的限制后,子进程将会结束。

       如果MaxRequestsPerChild 为0,子进程将永远不会结束。将MaxRequestsPerChild 设置成非零值有两个好处:

  1. 可以防止(偶然的)内存泄漏无限进行,从而耗尽内存。

  2. 给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。

    对于KeepAlive链接,只有第一个请求会被计数。事实上,它改变了每个子进程限制最大链接数量的行为。


    MaxClients是这些指令中最为重要的一个,设定的是Apache可以同时处理的请求,是对Apache性能影响最大的参数。其缺省值 256 是远远不够的,如果请求总数已达到这个值(可通过 ps -ef|grep http|wc -l 来确认),那么后面的请求就要排队,直到某个已处理请求完毕。这就是系统资源还剩下很多而HTTP访问却很慢的主要原因。系统管理员可以根据硬件配置 和负载情况来动态调整这个值。理论上这个值越大,可以处理的请求就越多。


我们看看httpd进程:

[root@localhost ~]# ps -ef | grep httpd
root     10692     1  0 20:17 ?        00:00:00 /usr/sbin/httpd    # master process
apache   10786 10692  0 21:39 ?        00:00:00 /usr/sbin/httpd
apache   10787 10692  0 21:39 ?        00:00:00 /usr/sbin/httpd
apache   10788 10692  0 21:39 ?        00:00:00 /usr/sbin/httpd
apache   10789 10692  0 21:39 ?        00:00:00 /usr/sbin/httpd
apache   10790 10692  0 21:39 ?        00:00:00 /usr/sbin/httpd
apache   10791 10692  0 21:39 ?        00:00:00 /usr/sbin/httpd
apache   10792 10692  0 21:39 ?        00:00:00 /usr/sbin/httpd
apache   10793 10692  0 21:39 ?        00:00:00 /usr/sbin/httpd

    Prefork是一个进程处理一个请求,在启动httpd的时候,如果选择的是这种模式,会首先创建一个主进程(控制进程)和StartServers个子进程,可以看到StartServers为8个.由于进程和进程之间是独享内存的,所以一个进程崩溃了不会影响到其他的进程,所以Prefork模式的稳定性比较好,但是进程多了消耗的内存会比较大.

    主进程在创建了StartServers个子进程后,为了满足MinSpareServer的设置需求,会先创建一个进程,等待一秒,创建二个进程,再等待一秒,创建四个进程....以几何数增加创建的进程,最多达到每秒创建32个,直到满足MinSpareServer的设置(可以看到以下的MinSpareServer为5),这就是预派生(Prefork)的由来,这样不必等到有请求到来时才花时间创建新的进程,提高了系统响应速度以增加性能.




四、worker

  worker MPM 使用多个子进程,每个子进程有多个线程。每个线程在每个确定的时间只能维持一个连接。通常来说,在一个高流量的HTTP服务器上,Worker MPM 是个比较好的选择,因为Worker MPM 的内存使用比Prefork MPM 要低的多。但是worker MPM 也有缺陷。如果一个线程崩溃,整个进程就会连同其任何线程一起“死掉”,由于线程共享内存空间,所以一个程序在运行时必须被系统识别为 “每个线程都是安全的”。

    当第一个用户请求到达的时候线程发现需要复制文件,通过内核将文件复制给其进程,所以第二个用户请求同一个文件,对于第二个线程来说这个文件已存在,因为是公用同一个空间,所以速度得到提升;

    其缺点:线程很有可能产生资源争用,并不是全状态并行。所以一个进程里不能启动太多线程,所以可启动多个进程从其启动的进程再启多个线程,但无论如何每个线程也都是一个独立的执行实体(执行必须给cpu资源)

更改apache的MPM为woker模式

 我们是通过yum安装的httpd,它默认已经编译了prefork, worker两个MPM,所以我们可以切换。如果是手动编译的话, 我们仅能指定一个 --with-mpm=NAME

/etc/init.d/httpd 是 httpd 服务的启动脚本,此脚本的配置文件为: /etc/sysconfig/httpd, 那么我们可以编辑配置文件/etc/sysconfig/httpd:

# vi /etc/sysconfig/httd
# 把下面这一行的注释去掉
HTTPD=/usr/sbin/httpd.worker

# 切换模式必须重启服务
# service httpd restart

worker默认的配置:

<IfModule worker.c> 如果有这个模块就启用
StartServers       4         # 初始化的子进程数
MaxClients        300        # 并发请求最大数
MinSpareThreads     25         # 最小空闲线程数total=所有进程的线程数加起来
MaxSpareThreads     75         # 最大空闲线程数 total
ThreadsPerChild     25         # 每个子进程可生成的线程数
MaxRequestsPerChild    0         # 每个子进程可服务的最大请求数,0表示不限制
[root@localhost ~]# ps -ef | grep httpd
root      2395   1   0 15:36 ?       00:00:00 /usr/sbin/httpd.worker 
apache    2397  2395  0 15:36 ?      00:00:00 /usr/sbin/httpd.worker
apache    2398  2395  0 15:36 ?      00:00:00 /usr/sbin/httpd.worker
apache    2399  2395  0 15:36 ?      00:00:00 /usr/sbin/httpd.worker

 worker的工作原理是,由主控制进程生成“StartServers”个子进程,每个子进程中包含固定的ThreadsPerChild线程数,每个线程处理一个请求,线程是共享内存空间的,所以一个线程崩溃会导致在这个进程下的所有线程都崩溃,所以他的稳定性没有Prefork好,但是内存使用率比Prefork低。同样,为了不在请求到来时再生成线程,MinSpareThreads和MaxSpareThreads设置了最少和最多的空闲线程数;而MaxClients设置了所有子进程中的线程总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程。

参数:
–StartServer:服务器启动时一次性建立的子进程数量
–MaxClients:设定apache同一时间处理的最大请求数量,这里是指最大线程数量,大小仍受ServerLimit限制且必须是ThreadsPerChild的倍数。
–MinSpareThreads:设置最少的空闲线程数
–MaxSpareServers:设置最大的空闲线程数,必须大于等于MinSpareThreads加上ThreadsPerChild的和(因为每个子进程拥有的线程数是固定的)
–ThreadsPerChild:每个子进程建立的常驻线程,之后不会再创建新的线程。大小受ThreadLimit限制。
–MaxRequestsPerChild:每个子进程最多处理的请求数量,同prefork的一样
–ServerLimit:服务器允许配置的进程数上限,和ThreadLimit共同限制MaxClients(MaxClients <= ServerLimit *ThreadsPerChild)。
–ThreadLimit:TreadsPerChild可以配置的线程数上限,默认为64。


根据网上一些测试数据,实际情况下: Linux系统还是选prefork工作模式较好。


  MinSpareThreads和MaxSpareThreads的最大缺省值分别是25和75。这两个参数对Apache的性能影响并不大,可以按照实际情况相应调节。
MinSpareThreads,MaxSpareThreads  是总体的,所有进程所派生出来的线程数总数加起来

    ThreadsPerChild是worker 中影响性能最重要的一个指标,Worker模式下所能同时处理的请求总数是由StartServers总数乘以ThreadsPerChild的值决定的,应该大于等于MaxClients


五、优化的方向

1、KeepAlive On、 MaxKeepAliveRequests (80 - 120)、 KeepAliveTimeout (2s - 5s)

2、ServerLimit 、 MaxClients

比较重要的一个值。ServerLimit通常应该等于MaxClients。MaxClients决定了最大的httpd进程数,如果超过
了MaxClients的httpd服务数,你的网站就拒绝正常访问了。但MaxClients的大小受内存的限制,因此Apache2的默认值是256,并加上了ServerLimit参数作限制,如果想设大MaxClients,必须同时扩大ServerLimit,但MaxClient不
应超过ServerLimit。 ServerLimit 必须放到 MaxClient 指令之前。

3、HostnameLookup Off



总结:

  这些参数,如何设置才更合理呢? 没有绝对的说法,我们必须根据实际需求进行配置,通过压力测试来调整,根据实际web服务器的压力进行动态调整,以取得一个良好的折中。

压力测试工具:

  • LoadRunner

  • ab        ab -c 100 -n 10000 http://localhost/index.html


ab 进行压力测试

# ab -c 100 -n 1000  http://localhost/index.html

其中 -n 表示请求数, -c 表示并发数

你可以适当调节-c 和-n大小来测试服务器性能,借助htop指令来直观的查看机器的负载情况。

 ab也可以运行在windows平台下,如果在windows下安装apache,就可以在bin下找到ab.exe, 直接就可以使用,不用依赖其他的dll。


查看 httpd 进程数(prefork模式下apache能够处理的并发请求数)

#ps -ef | grep httpd | wc -l

这个值Apache可根据负载情况自动调整

查看系统 TCP 连接状态

# netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’



参考:

http://blog.chinaunix.net/uid-20441206-id-3360689.html

http://blog.chinaunix.net/uid-17238776-id-4353851.html

http://www.cnblogs.com/ghj1976/archive/2011/01/11/1932764.html