一、MPM模块简介

多路处理模块,Multi-Processing Modules,MPM。负责绑定本机网络端口、接受请求,并调度子进程来处理请求。

二、MPM模块的类型

  • prefork 一个非线程型的、预派生的MPM
  • worker 线程型的MPM,实现了一个混合的多线程多处理MPM,允许一个子进程中包含多个线程。
  • event 一个标准workerMPM的实验性变种
  • mpm_winnt 用于Windows NT/windows 2000/Windows XP/windows 2003 系列的MPM
  • mpm_netware Novell NetWare优化过的线程化的多路处理模块(MPM)
  • mpmt_os2 专门针对OS/2优化过的混合多进程多线程多路处理模块(MPM)
  • beos 专门针对BeOS优化过的多路处理模块(MPM)

其中我们在linux下比较常用的是prefork和worker ,windows平台比较常用的是mpm_winnt 。BeOS是由Be公司开发的一种多媒体操作系统;netware是Novell NetWare公司的unix产品;OS/2是由微软和IBM公司共同创造,后来由IBM单独开发的一套操作系统,目前已经寿终正寝,不过不排除开源再新生的可能。这些我们都不大会用到的。

三、Preforking MPM

概述

一个非线程型的、预派生的MPM 。这个多路处理模块(MPM)实现了一个非线程型的、预派生的web服务器,它的工作方式类似于Apache 1.3。它适合于没有线程安全库,需要避免线程兼容性问题的系统。它是要求将每个请求相互独立的情况下最好的MPM,这样若一个请求出现问题就不会影响到其他请求。

这个MPM具有很强的自我调节能力,只需要很少的配置指令调整。最重要的是将MaxClients设置为一个足够大的数值以处理潜在的请求高峰,同时又不能太大,以致需要使用的内存超出物理内存的大小。

工作方式

一个单独的控制进程(父进程)负责产生子进程,这些子进程用于监听请求并作出应答。Apache总是试图保持一些备用的(spare)或者是空闲的子进程用于迎接即将到来的请求。这样客户端就不需要在得到服务前等候子进程的产生。

StartServers, MinSpareServers, MaxSpareServers, MaxClients指令用于调节父进程如何产生子进程。通常情况下Apache具有很强的自我调节能力,所以一般的网站不需要调整这些指令的默认值。可能需要处理最大超过256个并发请求的服务器可能需要增加MaxClients的值。内存比较小的机器则需要减少MaxClients的值以保证服务器不会崩溃。更多关于调整进程产生的问题请参见性能方面的提示。

在Unix系统中,父进程通常以root身份运行以便邦定80端口,而Apache产生的子进程通常以一个低特权的用户运行。User和Group指令用于设置子进程的低特权用户。运行子进程的用户必须要对它所服务的内容有读取的权限,但是对服务内容之外的其他资源必须拥有尽可能少的权限。

MaxRequestsPerChild指令控制服务器杀死旧进程产生新进程的频率。

四、worker mpm

概述

此多路处理模块(MPM)使网络服务器支持混合的多线程多进程。由于使用线程来处理请求,所以可以处理海量请求,而系统资源的开销小于基于进程的MPM。但是,它也使用了多进程,每个进程又有多个线程,以获得基于进程的MPM的稳定性。

控制这个MPM的最重要的指令是,控制每个子进程允许建立的线程数的ThreadsPerChild指令,和控制允许建立的总线程数的MaxClients指令。

工作方式

每个进程可以拥有的线程数量是固定的。服务器会根据负载情况增加或减少进程数量。一个单独的控制进程(父进程)负责子进程的建立。每个子进程可以建立ThreadsPerChild数量的服务线程和一个监听线程,该监听线程监听接入请求并将其传递给服务线程处理和应答。

Apache总是试图维持一个备用(spare)或是空闲的服务线程池。这样,客户端无须等待新线程或新进程的建立即可得到处理。初始化时建立的进程数量由StartServers指令决定。随后父进程检测所有子进程中空闲线程的总数,并新建或结束子进程使空闲线程的总数维持在MinSpareThreads和MaxSpareThreads所指定的范围内。由于这个过程是自动调整的,几乎没有必要修改这些指令的缺省值。可以并行处理的客户端的最大数量取决于MaxClients指令。活动子进程的最大数量取决于MaxClients除以ThreadsPerChild的值。

有两个指令设置了活动子进程数量和每个子进程中线程数量的硬限制。要想改变这个硬限制必须完全停止服务器然后再启动服务器(直接重启是不行的),ServerLimit是活动子进程数量的硬限制,它必须大于或等于MaxClients除以ThreadsPerChild的值。ThreadLimit是所有服务线程总数的硬限制,它必须大于或等于ThreadsPerChild指令。这两个指令必须出现在其他workerMPM指令的前面。

在设置的活动子进程数量之外,还可能有额外的子进程处于”正在中止”的状态但是其中至少有一个服务线程仍然在处理客户端请求,直到到达MaxClients以致结束进程,虽然实际数量会很小。这个行为能够通过以下禁止特别的子进程中止的方法来避免:

* 将MaxRequestsPerChild设为”0″
* 将MaxSpareThreads和MaxClients设为相同的值

一个典型的针对workerMPM的配置如下:

1ServerLimit 16
2StartServers 2
3MaxClients 150
4MinSpareThreads 25
5MaxSpareThreads 75
6ThreadsPerChild 25

在Unix中,为了能够绑定80端口,父进程一般都是以root身份启动,随后,Apache以较低权限的用户建立子进程和线程。User和Group指令用于设置Apache子进程的权限。虽然子进程必须对其提供的内容拥有读权限,但应该尽可能给予它较少的特权。另外,除非使用了suexec ,否则,这些指令设置的权限将被CGI脚本所继承。

MaxRequestsPerChild指令用于控制服务器建立新进程和结束旧进程的频率。

五、MPM常用指令

StartServers 指令

StartServers指令设置了服务器启动时建立的子进程数量。

因为子进程数量动态的取决于负载的轻重,所有一般没有必要调整这个参数。

MinSpareServers 指令

MinSpareServers指令设置空闲子进程的最小数量。

所谓空闲子进程是指没有正在处理请求的子进程。如果当前空闲子进程数少于MinSpareServers ,那么Apache将以最大每秒一个的速度产生新的子进程。

只有在非常繁忙机器上才需要调整这个参数。将此参数设的太大通常是一个坏主意。

MaxSpareServers 指令

MaxSpareServers指令设置空闲子进程的最大数量。

所谓空闲子进程是指没有正在处理请求的子进程。如果当前有超过MaxSpareServers数量的空闲子进程,那么父进程将杀死多余的子进程。

只有在非常繁忙机器上才需要调整这个参数。将此参数设的太大通常是一个坏主意。如果将该指令的值设置为比MinSpareServers小,Apache将会自动将其修改成”MinSpareServers+1″。

MaxClients 指令

MaxClients指令设置了允许同时伺服的最大接入请求数量。

任何超过MaxClients限制的请求都将进入等候队列,直到达到ListenBacklog指令限制的最大值为止。一旦一个链接被释放,队列中的请求将得到服务。

对于非线程型的MPM(也就是prefork),MaxClients表示可以用于伺服客户端请求的最大子进程数量,默认值是256。要增大这个值,必须同时增大ServerLimit 。

对于线程型或者混合型的MPM(也就是beos或worker),MaxClients表示可以用于伺服客户端请求的最大线程数量。线程型的beos的默认值是50。对于混合型的MPM默认值是16(ServerLimit)乘以25(ThreadsPerChild)的结果。因此要将MaxClients增加到超过16个进程才能提供的时候,必须同时增加ServerLimit的值。

MaxRequestsPerChild 指令

MaxRequestsPerChild指令设置每个子进程在其生存期内允许伺服的最大请求数量。到达MaxRequestsPerChild的限制后,子进程将会结束。如果MaxRequestsPerChild为”0″,子进程将永远不会结束。

不同的默认值

在mpm_netware和mpm_winnt上的默认值是”0″。

将MaxRequestsPerChild设置成非零值有两个好处:

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

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

注意:

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

ThreadsPerChild 指令

这个指令设置了每个子进程建立的线程数。

子进程在启动时建立这些线程后就不再建立新的线程了。如果使用一个类似于mpm_winnt只有一个子进程的MPM,这个数值要足够大,以便可以处理可能的请求高峰。如果使用一个类似于worker有多个子进程的MPM,每个子进程所拥有的所有线程的总数要足够大,以便可以处理可能的请求高峰。

对于mpm_winnt,ThreadsPerChild的默认值是64;对于其他MPM是25。

ThreadLimit 指令

这个指令设置了每个子进程可配置的线程数ThreadsPerChild上限。

任何在重启期间对这个指令的改变都将被忽略,但对ThreadsPerChild的修改却会生效。

使用这个指令时要特别当心。如果将ThreadLimit设置成一个高出ThreadsPerChild实际需要很多的值,将会有过多的共享内存被分配。如果将ThreadLimit和ThreadsPerChild设置成超过系统的处理能力,Apache可能无法启动,或者系统将变得不稳定。该指令的值应当和ThreadsPerChild可能达到的最大值保持一致。

对于mpm_winnt,ThreadLimit的默认值是1920;对于其他MPM这个值是64。

注意:

Apache在编译时内部有一个硬性的限制”ThreadLimit 20000″(对于mpm_winnt是”ThreadLimit 15000″),不能超越这个限制。

ServerLimit 指令

对于preforkMPM,这个指令设置了MaxClients最大允许配置的数值。

对于workerMPM,这个指令和ThreadLimit结合使用设置了MaxClients最大允许配置的数值。任何在重启期间对这个指令的改变都将被忽略,但对MaxClients的修改却会生效。

使用这个指令时要特别当心。如果将ServerLimit设置成一个高出实际需要许多的值,将会有过多的共享内存被分配。如果将ServerLimit和MaxClients设置成超过系统的处理能力,Apache可能无法启动,或者系统将变得不稳定。

对于preforkMPM,只有在需要将MaxClients设置成高于默认值256的时候才需要使用这个指令。要将此指令的值保持和MaxClients一样。

对于workerMPM,只有在需要将MaxClients和ThreadsPerChild设置成需要超过默认值16个子进程的时候才需要使用这个指令。不要将该指令的值设置的比MaxClients 和ThreadsPerChild需要的子进程数量高。

注意:

Apache在编译时内部有一个硬限制”ServerLimit 20000″(对于preforkMPM为”ServerLimit 200000″)。不能超越这个限制。

五、总结

如果站点需要更好伸缩性可以选择worker或event线程化的MPM,而需要更好的稳定性和兼容性以适应一些旧的软件的站点可以用prefork 。目前最的apache版本2.4中已经对event的性能做了很多优化。所以其已经从一个实验性变种变成了一真正可用性的模式。因此如无特殊的需要,建议使用event模式。而且apache2.4中默认的也是event模式。