Apache--MPMs && Nginx事件驅動

MPM全稱是多道處理模塊,咱們都知道apache是以模塊化方式設計的.那麼MPM用來決定apache如何處理用戶請求的.是經過一個進程處理一個請求,仍是一個線程處理一個請求.當前MPM有三種能夠選擇的方式:php

  • preforkcss

  • workerhtml

  • eventpython

雖然有以上三種方式,可是要注意在任什麼時候間,必須有一個,並且只能有一個MPM被使用.那麼下面就介紹一下這三種處理方式的區別.nginx

prefork

在這種工做模型下,apache進程分爲master進程跟worker進程.web服務啓動就是啓動master進程,隨之master進程會啓動若干個worker子進程.master進程的工做就是管理worker子進程.而worker子進程的工做就是處理用戶請求.當用戶發起一個請求,apache就會從空閒的子進程中選擇一個處理這個用戶請求.web

這種處理方式有如下幾點好處:shell

  • 用戶不用等到其餘進程處理完畢.由於只要有空閒子進程在就能夠處理新的請求apache

  • 若是一個worker子進程崩潰了,不會影響其餘worker進程處理請求.編程

可是worker子進程的個數限制於apache配置文件中以下幾個條目的限制後端

  • MinSpareServers 最少空閒worker進程.

  • MaxSpareServers最多空閒worker進程,超過這個數,就會有一些空閒worker進程被kill

  • MaxRequestWorkers同一時刻能夠處理的請求數,即併發量

  • MaxConnectionsPerChild每個worker子進程一輩子中能夠處理的請求,超過這個數以後就會被master進程kill

同時, 通常master進程使用root用戶啓動,這樣方便master進程監聽80端口,以及管理進程.而餘下的worker子進程則是以apache配置文件中User指令指定的用戶啓動.這樣子是爲了減小worker子進程的權限.保證安全.

root@ff1221aa94a9:~# ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   4448   676 ?        Ss   09:33   0:00 /bin/sh -c supervisord -n
root         5  0.0  0.8  60556 17172 ?        S    09:33   0:02 /usr/bin/python /usr/bin/supervisord -n
root        31  0.0  0.1  61384  3160 ?        Ss   09:33   0:00 /usr/sbin/sshd
root        32  0.0  0.8 200164 16384 ?        Ss   09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      33  0.0  0.4 200300  8392 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      34  0.0  0.3 200300  7512 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      35  0.0  0.3 200300  7512 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      36  0.0  0.3 200300  7512 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      37  0.0  0.3 200300  7512 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start

執行ps能夠看出只有一個master進程以root用戶方式啓動

worker

prefork的缺點很明顯,一個worker進程處理一個請求,併發不會高.並且進程佔用的資源太多.作的事情卻只是處理一個請求.worker針對prefork的問題進行了改進.

  • 仍然有一個master父進程啓動若干個子進程

  • 每一個子進程啓動若干個線程

  • 每一個線程處理每一個請求

這樣子,worker模型的併發性高於prefork模型.而且因爲線程的開銷小於進程,因此worker模型佔用的資源反而小於prefork.

可是worker相對於prefork存在一個問題:非線程安全.最典型的一個問題在於:若是你的apache使用了worker模型工做.可是php卻使用非線程安全的版本,那麼這二者就不能工做了.因此縱然worker有萬般好,可是碰到使用非線程安全的歷史代碼,仍是隻能乖乖使用prefork模型.

worker模型使用多線程響應請求,這樣子存在一個問題,即一個線程崩潰就會影響整個進程.因此worker使用的是多進程+多線程的混合模型.便可以提升併發性,也能夠避免一個線程崩潰致使整個整個web站點崩潰.

同prefork同樣,worker中子進程跟線程數量也收到apache配置文件的控制.有以下參數

  • MinSpareThreads最少空閒線程

  • ThreadsPerChild每一個子進程能夠建立的線程數量

  • MaxClients同時能夠處理的請求數

  • .....

其web服務調優大抵就是根據服務器配置調節這些參數.具體參數細節能夠參考Apache文檔

Event

event模型是在apache2.2以後當作試驗特性引入的,在apache2.4以後才正式支持.event模型是爲了解決長鏈接(keep-alive)問題而生的.使用worker模型,一個線程對應一個請求,當一個請求爲長鏈接的時候,線程就會保持當長鏈接狀態,等待客戶端的下一個請求.這樣子當前線程就不能處理其餘客戶端請求了.

event模型跟worker模型很像,也是多個進程+多個線程的混合模式,可是event模型下每一個進程會有一個單獨的線程來管理這些keep-alive類型的線程.當新的請求過來的時候,管理線程會把請求交給其餘的空閒線程處理.這樣子就避免了每一個線程都被keep-alive阻塞.

可是event模型並非全部狀況都通用,在https協議下會退化成worker模型.具體緣由能夠看官方文檔.

Nginx

講到Apache,不得不提起如今Nginx.相比於Apache.Nginx於2004年正式發佈.而Apache在1995就已經出現了.當時的web環境還只是簡單的展現靜態頁面,並且併發量遠沒有如今這麼高.因此當時Apache的prefork模型也能夠很好的承擔web服務需求.加之其穩定性好,沒有什麼理由不用它.

當時後來互聯網漸漸變大,網站的併發量變大,Apache就出現了一個C10K的問題.即一個物理服務器達到併發量1W的時候apache就會承受不了.後來2004年Nginx很好的解決了C10K問題.Nginx爲什麼能優於apache解決C10K問題,咱們仍是得從其處理請求模型提及.

Nginx有三個著名的特性:

  • 事件驅動編程

  • 異步

  • 非IO阻塞

正是這三種編程方式促使Nginx能夠有如此高的併發量.下面來分析下Nginx究竟是如何工做的.

一樣,Nginx的進程也分爲master進程跟worker子進程.(其實還有兩個cache有關的進程, 這裏略過).在啓動nginx以後,master進程就會隨即建立必定數量的worker子進程,而且以後worker子進程數量保持不變.而且這些worker子進程都是單線程的.當一個請求到來時,worker進程中某一個空閒進程就會去處理這個請求.乍一看到這裏nginx的工做模式跟apache沒有什麼區別.關鍵就在於nginx如何處理用戶請求.

worker子進程開始處理請求.這個請求多是訪問某個網站的靜態頁面.而html頁面都是保存在硬盤上的.站在操做系統角度來看,nginx是沒有辦法直接讀取硬盤上的文件,必須由nginx告訴操做系統須要讀取哪一個文件,而後又操做系統去讀取這個文件,讀取完畢操做系統再交給nginx.也就是說,在操做系統讀取文件的時候,nginx是空閒的.若是是apache,那這個時候apache的worker進程/線程就阻塞在這裏等待操做系統把文件讀取好再交個本身,這種就稱之爲IO阻塞.

可是nginx不同, nginx的worker進程在這個時候就會註冊一個事件,至關於告訴操做系統:你文件讀好了跟我說一下,我先去處理其餘事情.而後這個worker就能夠去處理新的用戶請求了.這裏nginx的worker進程並無因爲操做系統讀取文件而阻塞等待,這種即稱之爲非IO阻塞

當操做系統讀取好文件以後,就會通知ngixn:我文件幫你讀取好了,你過來拿走."操做系統讀取好文件"這個事件被觸發了,因而Nginx就跑回去把文件拿走,而後返回響應.這種因爲某個事件出現觸發Nginx執行操做的方式就稱爲事件驅動編程.

咱們回顧上面過程,一個用戶請求讀取文件,nginx把讀取文件這個事情通知操做系統以後就去處理下一個用戶請求,直到操做系統讀取好文件以後再返回響應.這種一個請求尚未處理完畢就去處理下一個請求的編程方式即異步編程

正是因爲nginx這種工做模型,使得nginx在保持必定量的worker進程下,也能夠獲得至關大的併發量.這點正是nginx優於apache的地方.一樣,nginx的這種請求處理模型在處理長鏈接的時候也可使用.

Use Both

那麼是否是說Nginx必定就優於Apache.Apache就藥丸了呢.也不是.必定要記住,一個後來者的出現, 沒有在它的前輩所擅長的領域戰勝它,那麼後來者是不可能徹底取代前者.頗有可能的狀況是二者並存.nginx自己並不能處理php,python等腳本語言,只能把這些動態請求經過CGI轉發給其餘程序處理.因此如今一般的架構是前臺Ngixn負責處理靜態文件諸如js,css,image文件.而碰到請求php等動態內容.就在後端多個apache服務器中選擇一個比較空閒的服務器,把這請求轉發給這個服務器處理.等apache處理好以後把返回交給nginx.nginx再返回給用戶.這是目前典型的一種設計方案.上面的流程中nginx負責兩個功能:反向代理,負載均衡.這也是nginx所擅長的兩個功能.而apache豐富的模塊能夠很好的知足一個站點的各類需求.而且通過了20+年的考驗,Apache的穩定性也是能夠保證的.

web站點架構

相關文章
相關標籤/搜索