在整個網站架構中,Web Server(如Apache)只是內容的分發者。舉個栗子,若是客戶端請求的是 index.html,那麼Web Server會去文件系統中找到這個文件,發送給瀏覽器,這裏分發的是靜態數據。php
若是請求的是 index.php,根據配置文件,Web Server知道這個不是靜態文件,須要去找 PHP 解析器來處理,那麼他會把這個請求簡單處理,而後交給PHP解析器。html
當Web Server收到 index.php 這個請求後,會啓動對應的 CGI 程序,這裏就是PHP的解析器。接下來PHP解析器會解析php.ini文件,初始化執行環境,而後處理請求,再以規定CGI規定的格式返回處理後的結果,退出進程,Web server再把結果返回給瀏覽器。這就是一個完整的動態PHP Web訪問流程,接下來再引出這些概念,就好理解多了,前端
WEB 中,mysql
在瞭解 CGI 以前,咱們先了解一下Web server 傳遞數據的另一種方法:PHP Module加載方式。以 Apache 爲例,在PHP Module方式中,是否是在 Apache 的配置文件 httpd.conf 中加上這樣幾句:linux
# 加入如下2句
LoadModule php5_module D:/php/php5apache2_2.dll AddType application/x-httpd-php .php # 修改以下內容 <IfModule dir_module> DirectoryIndex index.php index.html </IfModule>
上面是 Windows 下安裝php和apache環境後手動配置,在linux下源碼安裝大體是這樣配置的:nginx
# ./configure --with-mysql=/usr/local --with-apache=/usr/local/apache --enable-track-vars
因此,這種方式,他們的共同本質都是用 LoadModule 來加載 php5_module,就是把php做爲apache的一個子模塊來運行。當經過web訪問php文件時,apache就會調用php5_module來解析php代碼。web
那麼php5_module是怎麼來將數據傳給php解析器來解析php代碼的呢?答案是經過sapi。sql
咱們再來看一張圖,詳細的說說apache 與 php 與 sapi的關係:數據庫
從上面圖中,咱們看出了sapi就是這樣的一箇中間過程,SAPI提供了一個和外部通訊的接口,有點相似於socket,使得PHP能夠和其餘應用進行交互數據(apache,nginx等)。php默認提供了不少種SAPI,常見的提供給apache和nginx的php5_module、CGI、FastCGI,給IIS的ISAPI,以及Shell的CLI。apache
因此,以上的apache調用php執行的過程以下:
apache -> httpd -> php5_module -> sapi -> php
好了。apache與php經過php5_module的方式就搞清楚了吧!
這種模式將php模塊安裝到apache中,因此每一次apache結束請求,都會產生一條進程,這個進程就完整的包括php的各類運算計算等操做。
在上圖中,咱們很清晰的能夠看到,apache每接收一個請求,都會產生一個進程來鏈接php經過sapi來完成請求,可想而知,若是一旦用戶過多,併發數過多,服務器就會承受不住了。
並且,把mod_php編進apache時,出問題時很難定位是php的問題仍是apache的問題。
CGI(Common Gateway Interface)全稱是「通用網關接口」,WEB 服務器與PHP應用進行「交談」的一種工具,其程序須運行在網絡服務器上。CGI能夠用任何一種語言編寫,只要這種語言具備標準輸入、輸出和環境變量。如php、perl、tcl等。
WEB服務器會傳哪些數據給PHP解析器呢?URL、查詢字符串、POST數據、HTTP header都會有。因此,CGI就是規定要傳哪些數據,以什麼樣的格式傳遞給後方處理這個請求的協議。仔細想一想,你在PHP代碼中使用的用戶從哪裏來的。
也就是說,CGI就是專門用來和 web 服務器打交道的。web服務器收到用戶請求,就會把請求提交給cgi程序(如php-cgi),cgi程序根據請求提交的參數做應處理(解析php),而後輸出標準的html語句,返回給web服服務器,WEB服務器再返回給客戶端,這就是普通cgi的工做原理。
CGI的好處就是徹底獨立於任何服務器,僅僅是作爲中間分子。提供接口給apache和php。他們經過cgi搭線來完成數據傳遞。這樣作的好處了儘可能減小2個的關聯,使他們2變得更獨立。
可是CGI有個蛋疼的地方,就是每一次web請求都會有啓動和退出過程,也就是最爲人詬病的fork-and-execute模式,這樣一在大規模併發下,就死翹翹了。
從根本上來講,FastCGI是用來提升CGI程序性能的。相似於CGI,FastCGI也能夠說是一種協議。
FastCGI像是一個常駐(long-live)型的CGI,它能夠一直執行着,只要激活後,不會每次都要花費時間去fork一次。它還支持分佈式的運算, 即 FastCGI 程序能夠在網站服務器之外的主機上執行,而且接受來自其它網站服務器來的請求。
FastCGI是語言無關的、可伸縮架構的CGI開放擴展,其主要行爲是將CGI解釋器進程保持在內存中,並所以得到較高的性能。衆所周知,CGI解釋器的反覆加載是CGI性能低下的主要緣由,若是CGI解釋器保持在內存中,並接受FastCGI進程管理器調度,則能夠提供良好的性能、伸縮性、Fail- Over特性等等。
FastCGI接口方式採用C/S結構,能夠將HTTP服務器和腳本解析服務器分開,同時在腳本解析服務器上啓動一個或者多個腳本解析守護進程。當HTTP服務器每次遇到動態程序時,能夠將其直接交付給FastCGI進程來執行,而後將獲得的結果返回給瀏覽器。這種方式可讓HTTP服務器專注地處理靜態請求,或者將動態腳本服務器的結果返回給客戶端,這在很大程度上提升了整個應用系統的性能。
FastCGI與CGI特色:
要了解PHP-FPM,就得先說說PHP-CGI。
PHP-CGI就是PHP實現的自帶的FastCGI管理器。 雖然是php官方出品,可是這丫的卻一點也不給力,性能太差,並且也很麻煩不人性化,主要體如今:
上面2個問題,一直讓不少人病垢了好久,因此不少人一直仍是在用 Module 方式。 直到 2004年一個叫 Andrei Nigmatulin的屌絲髮明瞭PHP-FPM ,這神器的出現就完全打破了這種局面,這是一個PHP專用的 fastcgi 管理器,它很爽的克服了上面2個問題,並且,還表如今其餘方面更表現強勁。
也就是說,PHP-FPM 是對於 FastCGI 協議的具體實現,他負責管理一個進程池,來處理來自Web服務器的請求。目前,PHP5.3版本以後,PHP-FPM是內置於PHP的。
由於PHP-CGI只是個CGI程序,他本身自己只能解析請求,返回結果,不會進程管理。因此就出現了一些可以調度 php-cgi 進程的程序,好比說由lighthttpd分離出來的spawn-fcgi。一樣,PHP-FPM也是用於調度管理PHP解析器php-cgi的管理程序。
PHP-FPM經過生成新的子進程能夠實現php.ini修改後的平滑重啓。
最後,咱們來總結一下,這些技術通過不斷的升級,能夠解決什麼問題(否則也不會升級嘛)。
因此,若是要搭建一個高性能的PHP WEB服務器,目前最佳的方式是Apache/Nginx + FastCGI + PHP-FPM(+PHP-CGI)方式了,不要再使用 Module加載或者 CGI 方式啦:)
(cite:https://www.awaimai.com/371.html)
CGI:
CGI的英文是(COMMON GATEWAY INTERFACE)公共網關接口,它的做用就是幫助服務器與語言通訊,這裏就是nginx和php進行通訊,由於nginx和php的語言不通,所以須要一個溝通轉換的過程,而CGI就是這個溝通的協議。
nginx服務器在接受到瀏覽器傳遞過來的數據後,若是請求的是靜態的頁面或者圖片等無需動態處理的則會直接根據請求的url找到其位置而後返回給瀏覽器,這裏無需php參與,可是若是是一個動態的頁面請求,這個時候nginx就必須與php通訊,這個時候就會須要用到cgi協議,將請求數據轉換成php能理解的信息,而後php根據這些信息返回的信息也要經過cgi協議轉換成nginx能夠理解的信息,最後nginx接到這些信息再返回給瀏覽器。
fast-cgi:
傳統的cgi協議在每次鏈接請求時,會開啓一個進程進行處理,處理完畢會關閉該進程,所以下次鏈接,又要再次開啓一個進程進行處理,所以有多少個鏈接就有多少個cgi進程,這也就是爲何傳統的cgi會顯得緩慢的緣由,所以過多的進程會消耗資源和內存。
而fast-cgi則是一個進程能夠處理多個請求,和上面的cgi協議徹底不同,cgi是一個進程只能處理一個請求,這樣就會致使大量的cgi程序,所以會給服務器帶來負擔。
php-cgi:
php-cgi是php提供給web serve也就是http前端服務器的cgi協議接口程序,當每次接到http前端服務器的請求都會開啓一個php-cgi進程進行處理,並且開啓的php-cgi的過程當中會先要重載配置,數據結構以及初始化運行環境,若是更新了php配置,那麼就須要重啓php-cgi才能生效,例如phpstudy就是這種狀況。
php-fpm:
php-fpm是php提供給web serve也就是http前端服務器的fastcgi協議接口程序,它不會像php-cgi同樣每次鏈接都會從新開啓一個進程,處理完請求又關閉這個進程,而是容許一個進程對多個鏈接進行處理,而不會當即關閉這個進程,而是會接着處理下一個鏈接。它能夠說是php-cgi的一個管理程序,是對php-cgi的改進。
php-fpm會開啓多個php-cgi程序,而且php-fpm常駐內存,每次web serve服務器發送鏈接過來的時候,php-fpm將鏈接信息分配給下面其中的一個子程序php-cgi進行處理,處理完畢這個php-cgi並不會關閉,而是繼續等待下一個鏈接,這也是fast-cgi加速的原理,可是因爲php-fpm是多進程的,而一個php-cgi基本消耗7-25M內存,所以若是鏈接過多就會致使內存消耗過大,引起一些問題,例如nginx裏的502錯誤。
同時php-fpm還附帶一些其餘的功能:
例如平滑過渡配置更改,普通的php-cgi在每次更改配置後,須要從新啓動才能初始化新的配置,而php-fpm是不須要,php-fpm分將新的鏈接發送給新的子程序php-cgi,這個時候加載的是新的配置,而原先正在運行的php-cgi仍是使用的原先的配置,等到這個鏈接後下一次鏈接的時候會使用新的配置初始化,這就是平滑過渡。
可能上面文字敘述很難理解,下面用圖形來簡要的說明瀏覽器請求web服務器的過程、cgi以及fastcgi,以及php-cgi和php-fpm之間的區別和聯繫:
上面是使用php-fpm的動態頁面的過程,下面補充沒有普通cgi協議的狀況;
這裏的web server能夠是nginx,也能夠是IIS和apache等http服務器,也能夠成爲網站服務器或者前端服務器。--------------------- 做者:貝倫醬 來源:CSDN 原文:https://blog.csdn.net/belen_xue/article/details/65950658 版權聲明:本文爲博主原創文章,轉載請附上博文連接!