Apache的多处理模块MPM

时间:2022-09-16 23:26:16

本博文主要参数 Apache 2.2文档以及Apache模块开发指南


Apache的整个运行可以分为两个阶段:启动阶段和运行阶段。

       在启动阶段时,它以ROOT特权来启动,进行解析配置文件(一般就是httpd.conf)、加载模块和初始化一些日志文件及内存共享段等操作,在启动阶段准备结束时,apache的控制转向多处理模块MPM,此时使得MPM能够在系统特权级运行,从而管理接下来的运行阶段。因为当处于运行阶段时,程序会放弃ROOT特权,以接收并处理网络中用户的服务请求,所以MPM也是在启动阶段初始化。

一,什么是MPM

       MPM,是Multi -Processing Modules的缩写,就是多处理模块的意思,它是在Apache 2.0中引入的一个概念,共引入目标是将Apache的结构能够模块化,把核心的任务处理作为一个可插拔的模块来运行,这样就很容易根据不同的环境和应用来更有效的优化Apache的运行,它是Apache2.X中最影响其性能的,最核心的特性,因为直接决定了Apache的工作方式。这里有一个问题是:它究竟怎么样影响了Apache。

      可以这么说:它决定了Apache以什么样的方式接入外部请求,如何Apache内部怎么样处理这个请求过程,这当然是最核心的了吧,比如它可以决定在处理外部请求的时候,需不需要启动多线程,如果是用多线程,最多可以多少个线程,一个进程可以产生最多多少个线程,类似于这种配置,都来自于MPM。MPM有一些指令可以专门用于调节父进程如何产生子进程,主要是StartServers,MinSpareServers,MaxSpareServers,MaxClients等,下面会介绍这些指令是什么意思。

它提供Apache服务程序和其所在的操作系统之间的接口,这个模块的主要职责是:

  1. 根据Apache运行的操作系统平台来优化Apache。
  2. 提高Apache的效率。
  3. 保证Apache的安全。

其实MPM本身也是一个模块,它是Apache中唯一一个系统层的模块,Apache在编译的时候选定一个所要使用的MPM模块,我们先来了解一下MPM模块在系统结构中的位置

Apache的多处理模块MPM

在任何时候,一个正常的Apache都只有一个MPM模块在运行。

二,有哪些MPM可以被使用

在安装apache时,我们可以查看哪些MPM模块可以被使用。

[root@localhost httpd-2.2.11]# ./configure --help | grep mpm
--with-mpm=MPM Choose the process model for Apache to use.
MPM={beos|event|worker|prefork|mpmt_os2}

  1. beos是BEOS上的缺省MPM模块。
  2. mpmt_os2,这是专门针对OS/2优化过的混合多进程多线程多路处理模块(MPM)。
  3. event,一个标准workerMPM的实验性变种。
  4. worker,线程型的MPM,实现了一个混合的多线程多处理MPM,允许一个子进程中包含多个线程。
  5. prefork,一个非线程型的、预派生的MPM。
下面分针对这些模块进行讨论,我们怎么知道当前apache是编译了哪个MPM使用呢?
[root@localhost httpd-2.2.11]# /install/apache2/bin/httpd -l
Compiled in modules:
core.c
prefork.c
http_core.c
mod_so.c
[root@localhost httpd-2.2.11]#
这表示Apache当前的正在工作的MPM是prefork工作方式的MPM,这也是一种缺省的模块,如果需要其它的MPM模块,在编译的时候用--with-mpm指定。

三,prefork 

       Apache MPM prefork实现了一 个非线程型的、预派生的web服务器。适合于没有线程安全库,需要避免线程兼容性问题的系统。它是 要求将每个请求相互独立的情况下最好的MPM,这样若一个请求出现问题就不会影响到其他请求。这个MPM具有很强的自我调节能力,只需要很少的配置指令调整。最重要的是将MaxClients设置为一个足够大的数值以处理潜在的请求高峰,同时又不能太大,以致需要使用的内存超出物理内存的大小。
       这种MPM的工作方式是:由一个单独的控制进程(父进程)产生子进程,然后将这些子进程用于监听请求并作出应答,这些子进程在处理时并不产生线程。另外,Apache总是试图保持一些备用的(spare)或者是空闲的子进程用于迎接即将到来的请求。这样客户端就不需要在得到服务前等候子进程的产生。
可以用于配置该MPM如何工作的主要参数有:
  1. StartServers
    StartServers指令设置了服务器启动时建立的子进程数量。因为子进程数量动态的取决于负载的轻重,所有一般没有必要调整这个参数。不同的MPM默认值也不一样。对于worker默认值是"3"。对于prefork默认值是"5"。
  2. MinSpareServers
    MinSpareServers指令设置空闲子进程的最小数量。所谓空闲子进程是指没有正在处理请求的子进程。如果当前空闲子进程数少于MinSpareServers ,那么Apache将以最大每秒一个的速度产生新的子进程。只有在非常繁忙机器上才需要调整这个参数。将此参数设的太大通常是一个坏主意。。
  3. MaxSpareServersMaxSpareServers指令设置空闲子进程的最大数量。所谓空闲子进程是指没有正在处理请求的子进程。如果当前有超过MaxSpareServers数量的空闲子进程,那么父进程将杀死多余的子进程。只有在非常繁忙机器上才需要调整这个参数。将此参数设的太大通常是一个坏主意。如果你将该指令的值设置为比MinSpareServers小,Apache将会自动将其修改成"MinSpareServers+1"。
  4. MaxClientsMaxClients指令设置了允许同时伺服的最大接入请求数量。任何超过MaxClients限制的请求都将进入等候队列,直到达到ListenBacklog指令限制的最大值为止。一旦一个链接被释放,队列中的请求将得到服务。对于非线程型的MPM(也就是prefork),MaxClients表示可以用于伺服客户端请求的最大子进程数量,默认值是256。要增大这个值,你必须同时增大ServerLimit 。对于线程型或者混合型的MPM(也就是beos或worker),MaxClients表示可以用于伺服客户端请求的最大线程数量。线程型的beos的默认值是50。对于混合型的MPM默认值是16(ServerLimit)乘以25(ThreadsPerChild)的结果。因此要将MaxClients增加到超过16个进程才能提供的时候,你必须同时增加ServerLimit的值。。
  5. MaxRequestsPerChild每个子进程在其生存期内允许伺服的最大请求数量,默认为10000.到达MaxRequestsPerChild的限制后,子进程将会结束。如果 MaxRequestsPerChild为”0″,子进程将永远不会结束。将MaxRequestsPerChild设置成非零值有两个好处
    1.可以防止(偶然的)内存泄漏无限进行,从而耗尽内存。
    2.给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。
  6. ServerLimit对于prefork MPM,这个指令设置了MaxClients最大允许配置的数值。对于workerMPM,这个指令和ThreadLimit结合使用设置了MaxClients最大允许配置的数值。任何在重启期间对这个指令的改变都将被忽略,但对MaxClients的修改却会生效。
配置举例:
<IfModule prefork.c>
StartServers 4 Apache启动时开启的子进程个数
MinSpareServers 4 最小的空闲子进程
MaxSpareServers 6 最大的空闲子进程
ServerLimit 15
MaxClients 12 以免产生大量的进程占用内存,影响系统性能
MaxRequestsPerChild 1200 子进程在处理了1200个请求之后,就会被销毁,然后创建新进程。
</IfModule>

四,worker

       此多路处理模块(MPM)使网络服务器支持混合的多线程多进程。由于使用线程来处理请求,所以可以处理海量请求,而系统资源的开销小于基于进程的MPM。但是,它也使用了多进程,每个进程又有多个线程,以获得基于进程的MPM的稳定性。控制这个MPM的最重要的指令是,控制每个子进程允许建立的线程数的ThreadsPerChild指令,和控制允许建立的总线程数的MaxClients指令。

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

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

       有两个指令设置了活动子进程数量和每个子进程中线程数量的硬限制。要想改变这个硬限制必须完全停止服务器然后再启动服务器(直接重启是不行的),ServerLimit是活动子进程数量的硬限制,它必须大于或等于MaxClients除以ThreadsPerChild的值。ThreadLimit是所有服务线程总数的硬限制,它必须大于或等于ThreadsPerChild指令。这两个指令必须出现在其他workerMPM指令的前面。
在设置的活动子进程数量之外,还可能有额外的子进程处于"正在中止"的状态但是其中至少有一个服务线程仍然在处理客户端请求,直到到达MaxClients以致结束进程,虽然实际数量会很小。这个行为能够通过以下禁止特别的子进程中止的方法来避免:
  1. 将MaxRequestsPerChild设为"0"
  2. 将MaxSpareThreads和MaxClients设为相同的值
一个典型的该类型MPM配置如下:
ServerLimit 16
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
五,小结

       Prefork MPM基于非线程模型,由独立的进程创建多个子进程的方式来工作,它在所有情况下都很安全,对运行非线程安全(non-thread-safe)模式的软件如PHP,它是唯一的安全选择。另外,对于某些应用程序,包括在 Apache 1.3上非常流行的程序(如简单静态页面、CGI脚本等),Prefork MPM是最好的选择。另一方面,prefork用单独的子进程来处理不同的请求,进程之间是彼此独立的,这也使其成为最稳定的MPM之一。但是由于每一个请求都会产生一个新的进程,导致系统资源(尤其是内存)消耗的很快,一旦并发量较大的时候,大量的Apache进程会占用巨大的内存空间。 

       Worker MPM基于线程模式,具有内存消耗低(对繁忙的服务很重要)、扩展性在某些特定应用情况下比Prefork更好等优点。在这个模式下,采用的进程和线程混合的形式处理请求。由于使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的Prefork模式。
以上两种稳定的MPM方式在非常繁忙的服务器应用下都有些不足。尽管HTTP的Keepalive方式能减少TCP连接数量和网络负载,但是 Keepalive需要和服务进程或者线程绑定,这就导致一个繁忙的服务器会耗光所有的线程。