在搭建 LAMP/LNMP 服務器時,會常常遇到 PHP-FPM、FastCGI和CGI 這幾個概念。若是對它們只知其一;不知其二,很難搭建出高性能的服務器。php
在網站的總體架構中,Web Server(如nginx,apache)只是內容的分發者,對客戶端的請求進行應答。html
若是客戶端請求的是index.html這類靜態頁面,那麼Web Server就去文件系統中找對應的文件,找到返回給客戶端(通常是瀏覽器),在這裏Web Server分發的就是是靜態數據。linux
整個過程以下圖:nginx
對於像index.php這類的動態頁面請求,Web Server根據配置文件知道這個不是靜態文件,則會調用PHP 解析器進行處理而後將返回的數據轉發給客戶端(瀏覽器)。c++
整個過程以下圖:web
在這個過程當中,Web Server並不能直接處理靜態或者動態請求,對於靜態請求是直接查找而後返回數據或者報錯信息,對於動態數據也是交付給其餘的工具(這裏的PHP解析器)進行處理。apache
那麼Web Server和處理工具(這裏的php-fpm)是怎樣進行交互的呢?傳輸的是那些數據呢?這些數據的格式又是怎樣的呢?windows
由此便引出了今天的主角:CGIapi
1)CGI(Common Gateway Interface)全稱是「通用網關接口」,是一種讓客戶端(web瀏覽器)與Web服務器(nginx等)程序進行通訊(數據傳輸)的協議。瀏覽器
用來規範web服務器傳輸到php解釋器中的數據類型以及數據格式,包括URL、查詢字符串、POST數據、HTTP header等,也就是爲了保證web server傳遞過來的數據是標準格式的。
2)CGI能夠用任何一種具備標準輸入、輸出和環境變量的語言編寫,如php、perl、tcl等。
不一樣類型語言寫的程序只要符合cgi標準,就能做爲一個cgi程序與web服務器交互,早期的cgi大多都是c或c++編寫的。
3)通常說的CGI指的是用各類語言編寫的能實現該功能的程序。
1)每次當web server收到index.php這種類型的動態請求後,會啓動對應的CGI程序(PHP的解析器);
2)PHP解析器會解析php.ini配置文件,初始化運行環境,而後處理請求,處理完成後將數據按照CGI規定的格式返回給web server而後退出進程;
3)最後web server再把結果返回給瀏覽器。
1)高併發時的性能較差:
CGI程序的每一次web請求都會有啓動和退出過程,也就是最爲人詬病的fork-and-execute模式(每次HTTP服務器遇到動態請求時都須要從新啓動腳本解析器來解析php.ini,從新載入所有DLL擴展並重初始化所有數據結構,而後把結果返回給HTTP服務器),很明顯,這樣的接口方式會致使php的性能不好,在處理高併發訪問時,幾乎是不可用的。
2)傳統的CGI接口方式安全性較差
3)CGI對php.ini的配置很敏感,在開發和調試的時候至關方便
由於CGI爲每一次請求增長一個進程,效率很低,因此基本已經不在生產部署時採用。但因爲CGI對php配置的敏感性,一般被用在開發和調試階段
經過CGI程序的工做原理能夠看出:CGI程序性能較差,安全性較低,爲了解決這些問題產生了FastCGI。
1)FastCGI(Fast Common Gateway Interface)全稱是「快速通用網關接口」
是通用網關接口(CGI)的加強版本,由CGI發展改進而來,主要用來提升CGI程序性能,
相似於CGI,FastCGI也是一種讓交互程序與Web服務器通訊的協議
2)FastCGI致力於減小網頁服務器與CGI程序之間互動的開銷,從而使服務器能夠同時處理更多的網頁請求(提升併發訪問)。
3)一樣的,通常說的FastCGI指的也是用各類語言編寫的能實現該功能的程序。
1)Web Server啓動同時,加載FastCGI進程管理器(nginx的php-fpm或者IIS的ISAPI或Apache的Module)
2)FastCGI進程管理器讀取php.ini配置文件,對自身進行初始化,啓動多個CGI解釋器進程(php-cgi),等待來自Web Server的鏈接。
3)當Web Server接收到客戶端請求時,FastCGI進程管理器選擇並鏈接到一個CGI解釋器。Web server會將相關環境變量和標準輸入發送到FastCGI子進程php-cgi進行處理
4)FastCGI子進程完成處理後將數據按照CGI規定的格式返回給Web Server,而後關閉FastCGI子進程或者等待下一次請求。
Fastcgi會先啓一個master,解析配置文件,初始化執行環境,而後再啓動多個worker。當請求過來時,master會傳遞給一個worker,而後當即能夠接受下一個請求。這樣就避免了重複的勞動,效率天然提升。並且當worker不夠用時,master能夠根據配置預先啓動幾個worker等着;固然空閒worker太多時,也會停掉一些,這樣就提升了性能,也節約了資源。這就是fastcgi的對進程的管理。
1)FastCGI具備語言無關性,支持用大多數語言進行編寫,對應的程序也支持大多數主流的web服務器
FastCGI技術目前支持語言有:C/C++,Java,PHP,Perl,Tcl,Python,SmallTalk,Ruby等。
支持FastCGI技術的主流web服務器有:Apache,Nginx,lighttpd等
2)FastCGI程序的接口方式採用C/S結構,能夠將web服務器和腳本解析服務器分開,獨立於web服務器運行,提升web服務器的併發性能和安全性:
提升性能:這種方式支持多個web分發服務器和多個腳本解析服務器的分佈式架構,同時能夠在腳本解析服務器上啓動一個或者多個腳本解析守護進程來處理動態請求,可讓web服務器專注地處理靜態請求或者將動態腳本服務器的結果返回給客戶端,這在很大程度上提升了整個應用系統的性能。
提升安全性:API方式把應用程序的代碼與核心的web服務器連接在一塊兒,這時一個錯誤的API的應用程序可能會損壞其餘應用程序或核心服務器,惡意的API的應用程序代碼甚至能夠竊取另外一個應用程序或核心服務器的密鑰,採用這種方式能夠在很大程度上避免這個問題
3)FastCGI的不依賴於任何Web服務器的內部架構,所以即便服務器技術的變化, FastCGI依然穩定不變
4)FastCGI程序在修改php.ini配置時能夠進行平滑重啓加載新配置
全部的配置加載都只在FastCGI進程啓動時發生一次,每次修改php.ini配置文件,只須要重啓FastCGI程序(php-fpm等)便可完成平滑加載新配置,已有的動態請求會繼續處理,處理完成關閉進程,新來的請求使用新加載的配置和變量進行處理
5)FAST-CGI是較新的標準,架構上和CGI大爲不一樣,是用一個駐留內存的服務進程向網站服務器提供腳本服務。像是一個常駐(long-live)型的CGI,維護的是一個進程池,它能夠一直執行着,只要激活後,不會每次都要花費時間去fork一次(這是CGI最爲人詬病的fork-and-execute 模式),速度和效率比CGI大爲提升,是目前的主流部署方式。
6)FastCGI的不足:
由於是在內存中同時運行多進程,因此會比CGI方式消耗更多的服務器內存,每一個PHP-CGI進程消耗7至25兆內存,在進行優化配置php-cgi進程池的數量時要注意系統內存,防止過量
生產環境的主流部署方式
1)CGI 和 FastCGI 都只是一種通訊協議規範,不是一個實體,通常說的CGI指的是用各類語言編寫的能實現該功能的程序
2)CGI 程序和FastCGI程序,是指實現這兩個協議的程序,能夠是任何語言實現這個協議的。(PHP-CGI 和 PHP-FPM就是實現FastCGI的程序)
3)CGI程序和FastCGI程序的區別:
關於CGI程序:
CGI使外部程序與Web服務器之間交互成爲可能。CGI程序運行在獨立的進程中,並對每一個Web請求創建一個進程,這種方法很是容易實現,但效率不好,難以擴展。面對大量請求,進程的大量創建和消亡使操做系統性能大大降低。此外,因爲地址空間沒法共享,也限制了資源重用。
關於FastCGI程序:
與CGI程序爲每一個請求建立一個新的進程不一樣,FastCGI使用持續的進程(master)來處理一連串的請求。這些進程由FastCGI服務器管理,而不是web服務器。 當進來一個請求時,web服務器把環境變量和這個頁面請求經過一個socket或者一個TCP connection傳遞給FastCGI進程。
不少地方說:PHP-CGI是PHP自帶的FastCGI管理器,目前還沒找到最原始的出處,以個人理解和經驗來看這話有點毛病,我認爲應該是:使用php實現CGI協議的CGI程序,能夠用來管理php解釋器,若是有異議能夠和我探討下。。。
使用以下命令能夠啓動PHP-CGI:
php-cgi -b 127.0.0.1:9000
php-cgi的特色:
1)php-cgi變動php.ini配置後需重啓php-cgi才能讓新的配置生效,不能夠平滑重啓
2)直接殺死php-cgi進程php就不能運行了
PHP-FPM(FastCGI Process Manager)
針對PHP-CGI的不足,PHP-FPM和Spawn-FCGI應運而生,它們的守護進程會平滑重新生成新的子進程。
1)PHP-FPM使用PHP編寫的PHP-FastCGI管理器,管理對象是PHP-CGI程序,不能說php-fpm是fastcgi進程的管理器,由於前面說了fastcgi是個協議
下載地址:http://php-fpm.org/download
早期的PHP-FPM是做爲PHP源碼的補丁而使用的,在PHP的5.3.2版本中直接整合到了PHP-FPM分支,目前主流的PHP5.5,PHP5.6,PHP5.7已經集成了該功能(被官方收錄)
在配置時使用--enable-fpm參數便可開啓PHP-FPM
2)修改php.ini以後,php-cgi進程的確是沒辦法平滑重啓的。php-fpm對此的處理機制是新的worker用新的配置,已經存在的worker處理完手上的活就能夠歇着了,經過這種機制來平滑過分。
1)Spawn-FCGI是一個通用的FastCGI管理服務器,它是lighttpd中的一部份,不少人都用Lighttpd的Spawn-FCGI進行FastCGI模式下的管理工做
2)Spawn-FCGI目前已經獨成爲一個項目,更加穩定一些,也給不少Web 站點的配置帶來便利。已經有很多站點將它與nginx搭配來解決動態網頁。
Spawn-FCGI的下載地址是http://redmine.lighttpd.net/projects/spawn-fcgi,目前(20190114)最新版本爲1.6.4,在4年前更新的,有點涼涼的意思。。。
1)PHP-FPM的配置都是在php-fpm.ini的文件內,早些時候重啓能夠經過/usr/local/php/sbin/php-fpm reload進行,無需殺掉進程就能夠完成php.ini的修改加載,被php官方收錄之後須要指定參數進行重載配置,能夠本身建立腳本進行管理
2)PHP-FPM控制的進程cpu回收的速度比較慢,內存分配的很均勻,比Spawn-FCGI要好,能夠有效控制內存和進程,且不容易崩潰,很優秀
3)Spawn-FCGI控制的進程CPU降低的很快,而內存分配的比較不均勻。有不少進程彷佛未分配到,而另一些卻佔用很高。多是因爲進程任務分配的不均勻致使的。而這也致使了整體響應速度的降低。而PHP-FPM合理的分配,致使整體響應的提到以及任務的平均。
(摘錄的,暫未實際驗證)
php目前比較常見的五大運行模式:包括cli、cgi 、fast-cgi、isapi、apache模塊的DLL
cli模式就是php的命令行運行模式,
例如:在linux下常用 「php -m」查找PHP安裝了那些擴展就是PHP命令行運行模式
其餘的能夠輸入php -h查看下
比較經典的使用方法,使用CGI程序將瀏覽器,web服務器,php解釋器鏈接起來進行數據交換的工具,目前主要用來作開發或調試
CGI方式在遇到鏈接請求(用戶 請求)先要建立cgi的子進程,激活一個CGI進程,而後處理請求,處理完後結束這個子進程。這就是fork-and-execute模式。因此用cgi方式的服務器有多少鏈接請求就會有多少cgi子進程,子進程反覆加載是cgi性能低下的主要緣由。都會當用戶請求數量很是多時,會大量擠佔系統的資源如內 存,CPU時間等,形成效能低下。
目前主流的使用方式,比CGI模式的工具效率高不少,大量用於分佈式高併發的環境中
在Linux中,nginx加php-fpm是最主流的使用方式
ISAPI即Internet Server Application Program Interface,是微軟提供的一套面向Internet服務的API接口,一個ISAPI的DLL,能夠在被用戶請求激活後長駐內存,等待用戶的另外一個請求,還能夠在一個DLL裏設置多個用戶請求處理函數,此外,ISAPI的DLL應用程序和WWW服務器處於同一個進程中,效率要顯著高於CGI。(因爲微軟的排他性,只能運行於windows環境)
此運行模式能夠在Linux和windows環境下使用Apache,他們的共同點都是用 LoadModule 來加載相關模塊,有兩種類型
Apache調用php的相關模塊(php5_module),也就是把php做爲apache的一個子模塊來運行
當經過web訪問php文件時,apache就會調用php5_module經過sapi將數據傳給php解析器來解析php代碼,整個過程以下圖:
從上面圖中,能夠看出:
1)sapi就是這樣的一箇中間過程,SAPI提供了一個和外部通訊的接口,有點相似於socket,使得PHP能夠和其餘應用進行交互數據(apache,nginx等)。
php默認提供了不少種SAPI,常見的提供給apache和nginx的php5_module、CGI、FastCGI,給IIS的ISAPI,以及Shell的CLI。
因此,以上的apache調用php執行的過程以下:
apache -> httpd -> php5_module -> sapi -> php
2)apache每接收一個請求,都會產生一個進程來鏈接php經過sapi來完成請求,若是用戶過多,併發數過多,服務器就會承受不住了。
3)把mod_php編進apache時,出問題時很難定位是php的問題仍是apache的問題,並且PHP是與Web服務器一塊兒啓動並運行的,當php模塊出現問題可能會致使Apache一同掛掉
在此種模式中Apache啓動加載mod_cgi模塊,使用CGI調用管理動態的php請求
更高級的是mod_fcgid模塊,是apache的fastcgi實現,性能提升,在apache的2.4之後的版本中獲得支持。
總結:
1)mod_php是apache的內置php解釋模塊,使用prefork方式,不須要額外的進程來作通信和應用解釋,顯然mod_php比mod_cgi這樣方式性能要好得多
2)缺點是把應用和HTTP服務器綁定在了一塊兒,當php模塊出現問題可能會致使Apache一同掛掉
3)另外每一個Apache進程都須要加載mod_php而不論這個請求是處理靜態內容仍是動態內容,這樣致使浪費內存,效率降低,
4)php.ini文件的變動須要從新啓動apache服務器才能生效,這使得沒法進行平滑配置變動。
隨着技術的不斷升級,單純的Apache加php模塊的方式已再也不主流,而是替換爲Apache加php_cgi,以及後來的php_fcgi和nginx加php-fpm的方法,能夠看下圖:
CGI、FastCGI和PHP-FPM關係圖解:https://www.awaimai.com/371.html
關於CGI 和 PHP-FPM須要弄清的:http://www.cleey.com/blog/single/id/848.html
淺談PHP fastcgi和php-fpm:https://www.jianshu.com/p/d095cbcbcf1b
php五大運行模式CGI,FAST-CGI,CLI,ISAPI,APACHE模式淺談:http://www.javashuo.com/article/p-nxopduuv-cd.html
==== 完畢,呵呵呵呵 ====