httpd 服務器的三大引擎 prefork、worker、event分析

概述:html

     httpd 2.2以前(2.2也包含在內),不支持動態切換MPM。且在編譯時候,只能指定使用哪一種MPM。若是,提供了 prefork、worker、event ,要改變MPM,只能在啓動httpd服務器程序的時候,指定使用:linux

  /usr/sbin/httpd
  /usr/sbin/httpd.event
  /usr/sbin/httpd.worker

中的那一個二進制程序。web

     httpd 2.4就支持動態切換MPM,在配置文件中使用【LoadModule】指令就能夠實現MPM的切換了。條件:咱們編譯httpd時,要把:prefork、worker、event都編譯成模塊。apache

1、httpd服務器工做在 prefork 模型是一個進程服務響應一個用戶請求windows

 啓動httpd服務緩存

[root@stu13 httpd-2.4]# ./bin/apachectl start
[root@stu13 httpd-2.4]# pstree | grep httpd
     |-httpd---5*[httpd]

查看httpd服務器工做的MPM是什麼?安全

[root@stu13 httpd-2.4]# ./bin/httpd -M | grep mpm
 mpm_prefork_module (shared)

說明:bash

    從【pstree】命令的顯示結果,能夠看到啓動httpd服務器時就啓動5個httpd服務進程用來準備接收web請求。服務器

    固然這5個進程都是由會話領導進程(該進程的全部者是root管理員)fork()而來。主進程管理子進程,如:回收子進程、建立子進程等。而響應用戶訪問請求的則是子進程。網絡

    當用戶向httpd服務器,發起訪問資源鏈接請求的時候,

httpd服務器會根據<IfModule mpm_prefork_module>指令定義的參數維護進程池中的進程。

當用戶向httpd服務器發起鏈接請求的時候,httpd的主進程就會從進程池中派一個子進程來負責響應用戶的請求,若是該服務器的併發請求量爲100的話,一會兒就使用完,進程池中空閒進程數(咱們定義了進程池中最小空閒進程數爲5),90個用戶的鏈接請求只好等待。這時主進程fork()出子進程,而後才能響應處於等待90個用戶的鏈接請求。雖然是一個進程負責響應一個用戶的請求,當該進程完成了用戶的請求以後,會話領導進程並不會立刻kill掉該進程。而是使用了重用的機制。意思是在進程的生命週期內它響應完負責的用戶請求後,還能夠響應後續的用戶請求。這是爲了減小消耗在建立進程上面的時間。實現快速地響應用戶請求的一種機制。假如過了一會,咱們的httpd服務器已經處理完這100個併發用戶的請求了。根據後續用戶的併發用戶數目有三種狀況:

(1)、後續的併發用戶數小於10的話:

     領導會話進程,爲了響應這100個併發請求的用戶,而fork()出的子進程,除了用來響應後面的

     用戶鏈接請求的進程以外,其它空閒進程通通被kill掉。只保留必定數目的空閒進程。如最小空      閒進程數爲:5( MinSpareServers          5)、最大空閒進程數爲:10(MaxSpareServers         10)

(2)、後續的併發用戶數大於10而小於150的話:

     響應100個併發用戶鏈接請求的進程都獲得了重用,但因爲在處理過程當中進程要不斷申請和釋放      內存,次數(處理用戶的請求次數)多了就會形成一些內存垃圾,就會影響系統的穩定性且影響了

     系統的有效利用,因此會話進程的生命週期是有限的,會話管理進程要kill掉一些進程。而在進

     程的生命週期內,可以處理的用戶請求數量是能夠

     設置的。httpd 2.2 版本和httpd 2.4版本的設置以下:

     httpd 2.2     MaxRequestsPerChild    4000
     httpd 2.4     MaxConnectionsPerChild   0

 因此,領導進程fork()子進程是不免的。意思是說:消耗在建立進程和銷燬進程中的時間是不免的。

     若是,咱們的服務器性能很好的話,能夠增長進程能夠處理的用戶請求的數量,可是可能會影響

     系統的穩定,產生一些內存垃圾。可是減小了fork()進程和kill進程的時間。在必定的程序上,

     提升了響應用戶鏈接請求的速度。

     若是,不調整進程的生命週期內能夠處理多少個用戶的鏈接請求數的話,就要花費大量的時間

     (若是咱們的服務器比較繁忙的話)fork()進程,kill進程.會在必定程度上影響響應用戶請求的

     速度的。

(3)、後續的併發用戶請求數大於150的話;

     有可能會出現,有可能會出現鏈接請求超時的狀況。若是咱們的接收鏈接的緩存不夠大的話,

     有些用戶的請求鏈接都沒法接收下來。無論服務器是否可以處理,都應該把請求接收下來再說。咱們能夠調大該緩存:

     [root@stu13 ~]# cat /proc/sys/net/ipv4/tcp_mem
     46368   61824   92736
     [root@stu13 ~]# cat /proc/sys/net/ipv4/tcp_rmem
     4096    87380   1978368
     [root@stu13 ~]# cat /proc/sys/net/ipv4/tcp_wmem
     4096    16384   1978368

 固然,若是服務器的性能很好的話,咱們能夠調大處理的併發用戶數量,httpd 2.2 與 httpd 2.4中定義以下:

    httpd 2.2     MaxClients             300  
    httpd 2.4     MaxRequestWorkers      150

    可是,若是調大了併發用戶數(服務器的性能條件下),雖然一次性能夠處理的用戶請求數增長了,可是在服務器上進程的切換的次數也增長了。由於進程的切換是浪費CPU時間週期的。因此,咱們要爲服務器定作一個黃金比例。既能處理更多的用戶併發請求,浪費在進程間切換的時間又很合理。

prefork模型的配置以下:

<IfModule mpm_prefork_module>
    StartServers             5      服務器啓動時就fork()出5個進程,等待用戶鏈接請求
    MinSpareServers          5      服務器在等待客戶端鏈接請求的最小空閒進程數。
    MaxSpareServers         10      服務器在等待客戶端鏈接請求的最大空閒進程數。
    MaxRequestWorkers      150      容許最大的用戶併發請求數。
    MaxConnectionsPerChild   0      在進程的生命週期內,它能夠服務多少個請求。
</IfModule>

httpd服務器剛啓動沒有接收客戶端鏈接請求時候,所佔據常駐物理內存大小爲

[root@stu13 ~]./test/test.sh
Date: 2014/08/10_16:30:05
user     pid     vsz      rss      comm
root     19506   5252     2196     httpd
daemon   19507   5252     1684     httpd
daemon   19508   5252     1684     httpd
daemon   19509   5252     1684     httpd
daemon   19510   5252     1684     httpd
daemon   19511   5252     1684     httpd
--------------------total_Rss---------------------
10616

說明:

    httpd服務器全部進程佔據的常駐物理內存集約爲:10M.


二、對該httpd進行壓力測試,併發用戶數爲:100,共發起3000個請求。暫停2秒。共測試40次。

[root@stu13 httpd-2.4]# declare -i num=40
[root@stu13 httpd-2.4]# while [ "$num" -gt 0 ]; do ab -c 100 -n 3000 http://192.168.60.99/index.html; sleep 2 ; let num--; done
.....
Date: 2014/08/10_16:33:02
user     pid     vsz      rss      comm
root     19506   5252     2216     httpd
daemon   19509   5384     2264     httpd
daemon   20311   5384     2244     httpd
daemon   20459   5384     2244     httpd
daemon   20519   5384     2244     httpd
daemon   20555   5384     2244     httpd
daemon   20615   5384     2244     httpd
daemon   20856   5384     2244     httpd
daemon   20944   5384     2244     httpd
daemon   21036   5384     2244     httpd
daemon   21089   5384     2244     httpd
--------------------total_Rss---------------------
24676

Date: 2014/08/10_16:33:03
user     pid     vsz      rss      comm
root     19506   5252     2216     httpd
daemon   19509   5384     2264     httpd
daemon   20311   5384     2244     httpd
daemon   20459   5384     2244     httpd
daemon   20519   5384     2244     httpd
daemon   20555   5384     2244     httpd
daemon   20615   5384     2244     httpd
daemon   20856   5384     2244     httpd
daemon   20944   5384     2244     httpd
daemon   21036   5384     2244     httpd
daemon   21089   5384     2244     httpd
--------------------total_Rss---------------------
24676

說明:

   進行壓力測試後,httpd服務器常駐內存集大小爲:24675,約爲:24M.

prefork模式,使用一個進程服務一個用戶請求。因爲進程打開的資源是獨享,若是,用戶訪問的資源相同也要打開屢次的。可是,比較穩定的。

   因爲prefork模型的,服務用戶請求的會話進程要不斷建立、銷燬。也就是進程號PID不斷髮生變化,因此很難作到把會話進程綁定在CPU上(使用進程號作綁定)。若是咱們的服務器,有多顆CUP的話,可使用指定的CPU處理中斷請求。

    prefork 工做模式,負責監聽/響應的是主進程(屬主爲root的httpd會話領導進程)是基於 select/poll 實現網絡IO利復的。這樣服務器就能夠實現併發了。但因爲 select/poll自己的侷限性,理論上併發能力上限爲:1024。

2、worker 工做模型是

    一個線程服務一個用戶的鏈接請求。線程比進程更輕量級,建立和消耗的速度比進程的建立和消耗要快得多。線程之間還能夠共享資源,如:打開的文件描述符等。這樣若是:兩個客戶端請求的是同一個文件,就不須要從磁盤上加載兩次了,速度要比基於進程的響應速度快。但線程的管理要比進程複雜得多。線程之間不少資源是共享的,因此它沒有prefork模型,一個進程服務一個服務請求那麼安全穩定。何況,linux不是真線程的操做系統,worker 與 prefork 這兩種模型,在linux上的表現幾乎都同樣。一般使用prefork模型。windows 是真線程的操做系統,它對線程的支持就很好。

 啓動httpd服務器

[root@stu13 httpd-2.4]# ./bin/apachectl start
[root@stu13 httpd-2.4]# pstree | grep httpd
     |-httpd---2*[httpd---26*[{httpd}]]

查看當前httpd服務器使用的MPM是什麼?

[root@stu13 httpd-2.4]# ./bin/httpd -M | grep mpm
 mpm_worker_module (shared)

說明:

    從【pstree】的顯示結果能夠看出,httpd服務器剛起動就建立了2個子進程,且這2個子進程又建立了25個線程用來等待服務客戶端的鏈接請求的。剛啓動httpd服務器時(沒有接收客戶端鏈接請求),

worker 的模型以下:分析評估應用,能夠調節下述的參數來調節httpd服務器的併發能力的。

<IfModule mpm_worker_module>
    StartServers             2         服務器剛啓動的時候就啓動兩個進程,這兩個進程共生
                                        成25個線程用來等待客戶端的鏈接請求的。
    MinSpareThreads         25         最少保持25個線程處於空閒狀態
    MaxSpareThreads         75         最多保持75個純程處於空閒狀態
    ThreadsPerChild         25         每一個進程最多容許生成25個線程
    MaxRequestWorkers      150         併發數爲150
    MaxConnectionsPerChild   0         在線程的生命週期內,
                                        線程容許服務的客戶端鏈接的個數。
</IfModule>

一、httpd服務器剛啓動沒有接收客戶端鏈接請求時候,所佔據常駐物理內存大小爲

[root@stu13 ~]./test/test.sh
Date: 2014/08/10_16:40:34
user     pid     vsz      rss      comm
root     23955   5428     2372     httpd
daemon   23956   283160   2092     httpd
daemon   23957   283160   2096     httpd
--------------------total_Rss---------------------
6560

二、對該httpd進行壓力測試,

[root@stu13 httpd-2.4]# declare -i num=40
[root@stu13 httpd-2.4]# while [ "$num" -gt 0 ]; do ab -c 100 -n 3000 http://192.168.60.99/index.html; sleep 2 ; let num--; done
.....
Date: 2014/08/10_16:59:37
user     pid     vsz      rss      comm
root     28920   5428     2384     httpd
daemon   28921   285476   3740     httpd
daemon   28922   285476   3752     httpd
daemon   29110   285476   3720     httpd
daemon   30774   285476   3712     httpd
--------------------total_Rss---------------------
17308

Date: 2014/08/10_16:59:38
user     pid     vsz      rss      comm
root     28920   5428     2384     httpd
daemon   28921   285476   3740     httpd
daemon   28922   285476   3752     httpd
daemon   29110   285476   3720     httpd
--------------------total_Rss---------------------
13596

說明:

    由於,線程池中定義了,每一個進程最多能夠生成25個線程, 假如:此時,httpd服務器共有4個進程,每一個進程都產生了25個線程,4個進程都滿負荷運轉了,

    可是,仍是有不少用戶在等待,這時候主進程(會話領導進程),又會fork()出進程,子進程又生成線程來服務客戶端的鏈接請求的。進程的線程在不斷服務鏈接請求,會不斷申請內存釋放內存,次數多了,不免會產生內存垃圾的。影響系統的穩定。因此,httpd服務器要不斷使用新的進程替換老的進程。、


3、event:

   是基於信號驅動I/O 通知機制。工做方式是:使用每線程服務N個用戶請求。event的工做模型要優於prefork和worker.

啓動httpd服務

[root@stu13 httpd-2.4]# ./bin/apachectl start
[root@stu13 httpd-2.4]# pstree | grep httpd
     |-httpd---2*[httpd---26*[{httpd}]]

一、查看 httpd服務器的工用模型

[root@stu13 httpd-2.4]# ./bin/httpd  -M | grep mpm
 mpm_event_module (shared)

httpd服務器工做在event模式下線程池的控制。也worker的線程池很類似,但event的工做方式是:一個線程服務N個用戶請求。

<IfModule mpm_event_module>
    StartServers             2         服務器啓動的時候就生成2個子進程,
                                       該子進程共生成25個線程等待客戶端的鏈接請求
    MinSpareThreads         25         線程池中保持最少25個空閒線程。
    MaxSpareThreads         75         線程池中保持最多75個空閒線程。
    ThreadsPerChild         25         每一個進程最多能夠生成25個線程。
    MaxRequestWorkers      150         最大併發用戶數爲:150
    MaxConnectionsPerChild   0          線程可以服務的用戶請求數據。 0 表示不作限定。
</IfModule>

httpd服務器沒有服務用戶請求時,所佔據常駐物理集大小爲

[root@stu13 ~]# test/test.sh
Date: 2014/08/10_17:04:58
user     pid     vsz      rss      comm
root     30948   5436     2352     httpd
daemon   30949   283168   2084     httpd
daemon   30950   283168   2088     httpd
--------------------total_Rss---------------------
6524

二、對該httpd進行壓力測試,

[root@stu13 httpd-2.4]# declare -i num=40
[root@stu13 httpd-2.4]# while [ "$num" -gt 0 ]; do ab -c 100 -n 3000 http://192.168.60.99/index.html; sleep 2 ; let num--; done
.....
Date: 2014/08/10_17:08:26
user     pid     vsz      rss      comm
root     30948   5436     2352     httpd
daemon   30949   287172   6076     httpd
daemon   30950   288372   6704     httpd
--------------------total_Rss---------------------
15132

Date: 2014/08/10_17:08:27
user     pid     vsz      rss      comm
root     30948   5436     2352     httpd
daemon   30949   287172   6076     httpd
daemon   30950   288372   6704     httpd
--------------------total_Rss---------------------
15132

說明:

    經過併發測試後,進程的進程號並無改變。則工做在 worker模型下的,壓力測試後,進程號已經發生了改變。

    event 和 worker的線程池的配置都同樣,因爲 event 是基於信號驅動I/O 通知機制,每一個進程能夠服務N個用戶請求。

    而worker是一個線程服務一個請求。在請求沒有完成以前,該線程是與它服務的請求綁定的。

worker須要大量的建立進程生成線程,銷燬線程,殺死進程的過程。而event則不須要頻繁的建立銷燬。

相關文章
相關標籤/搜索