最先的Web服務器,能夠簡單地響應瀏覽器發來的HTTP請求,並將存儲在服務器上的HTML文件返回給瀏覽器,也就是靜態html。php
隨着時間的變化,網站也愈來愈複雜,因此出現動態技術。可是服務器並不能直接運行 php,asp這樣的文件,本身不能作,外包給別人吧,可是要與第三作個約定,我給你什麼,而後你給我什麼,就是握把請求參數發送給你,而後我接收你的處 理結果給客戶端。那這個約定就是 common gateway interface,簡稱cgi。(cgi只是接口協議)html
cgi就像翻譯機,將PHP語言給服務器解釋,便於相互之間的理解和通信,最後呈現給瀏覽器查看前端
WEB服務器將根據CGI程序的類型決定數據向CGI程序的傳送方式,通常來說是經過標準輸入/輸出流和環境變量來與CGI程序間傳遞數據。 以下圖所示:python
CGI程序經過標準輸入(STDIN)和標準輸出(STDOUT)來進行輸入輸出。此外CGI程序還經過環境變量來獲得輸入,操做系統提供了許 多環境變量,它們定義了程序的執行環境,應用程序能夠存取它們。nginx
Web服務器和CGI接口又另外設置了一些環境變量,用來向CGI程序傳遞一些重要的參 數。CGI的GET方法還經過環境變量QUERY-STRING向CGI程序傳遞Form中的數據。 下面是一些經常使用的CGI環境變量:web
變量名 | 描述 |
---|---|
CONTENT_TYPE | 這個環境變量的值指示所傳遞來的信息的MIME類型。目前,環境變量CONTENT_TYPE通常都是:application/x-www-form-urlencoded,他表示數據來自於HTML表單。 |
CONTENT_LENGTH | 若是服務器與CGI程序信息的傳遞方式是POST,這個環境變量即便從標準輸入STDIN中能夠讀到的有效數據的字節數。這個環境變量在讀取所輸入的數據時必須使用。 |
HTTP_COOKIE | 客戶機內的 COOKIE 內容。 |
HTTP_USER_AGENT | 提供包含了版本數或其餘專有數據的客戶瀏覽器信息。 |
PATH_INFO | 這個環境變量的值表示緊接在CGI程序名以後的其餘路徑信息。它經常做爲CGI程序的參數出現。 |
QUERY_STRING | 若是服務器與CGI程序信息的傳遞方式是GET,這個環境變量的值即便所傳遞的信息。這個信息經跟在CGI程序名的後面,二者中間用一個問號'?'分隔。 |
REMOTE_ADDR | 這個環境變量的值是發送請求的客戶機的IP地址,例如上面的192.168.1.67。這個值老是存在的。並且它是Web客戶機須要提供給Web服務器的惟一標識,能夠在CGI程序中用它來區分不一樣的Web客戶機。 |
REMOTE_HOST | 這個環境變量的值包含發送CGI請求的客戶機的主機名。若是不支持你想查詢,則無需定義此環境變量。 |
REQUEST_METHOD | 提供腳本被調用的方法。對於使用 HTTP/1.0 協議的腳本,僅 GET 和 POST 有意義。 |
SCRIPT_FILENAME | CGI腳本的完整路徑 |
SCRIPT_NAME | CGI腳本的的名稱 |
SERVER_NAME | 這是你的 WEB 服務器的主機名、別名或IP地址。 |
SERVER_SOFTWARE | 這個環境變量的值包含了調用CGI程序的HTTP服務器的名稱和版本號。例如,上面的值爲Apache/2.2.14(Unix) |
CGI全稱是 公共網關接口(Common Gateway Interface)
,HTTP服務器與你的或其它機器上的程序進行交談的一種工具,其程序須運行在網絡服務器上。數據庫
CGI能夠用任何一種語言編寫,只要這種語言具備標準輸入、輸出和環境變量。如php,perl,tcl等。apache
CGI是HTTP Server和一個獨立的進程之間的協議,把HTTP Request的Header設置成進程的環境變量,HTTP Request的正文設置成進程的標準輸入,而進程的標準輸出就是HTTP Response包括Header和正文。瀏覽器
FastCGI像是一個常駐(long-live)型的CGI,它能夠一直執行着,只要激活後,不會每次都要花費時間去fork一次(這是CGI最爲人詬病的fork-and-execute 模式)。它還支持分佈式的運算,即 FastCGI 程序能夠在網站服務器之外的主機上執行而且接受來自其它網站服務器來的請求。安全
FastCGI是語言無關的、可伸縮架構的CGI開放擴展,其主要行爲是將CGI解釋器進程保持在內存中並所以得到較高的性能。衆所周知,CGI解釋器的反覆加載是CGI性能低下的主要緣由,若是CGI解釋器保持在內存中並接受FastCGI進程管理器調度,則能夠提供良好的性能、伸縮性、Fail- Over特性等等。
FASTCGI是和HTTP協議相似的概念。無非就是規定了在同一個TCP鏈接裏怎麼同時傳多個HTTP鏈接。這實際上致使了個問題,有個HTTP鏈接傳個大文件不願讓出FASTCGI鏈接,在同一個FASTCGI鏈接裏的其餘HTTP鏈接就傻了。因此Lighttpd? 引入了 X-SENDFILE 。
FastCGI具備語言無關性.
FastCGI在進程中的應用程序,獨立於核心web服務器運行,提供了一個比API更安全的環境。APIs把應用程序的代碼與核心的web服務器連接在一塊兒,這意味着在一個錯誤的API的應用程序可能會損壞其餘應用程序或核心服務器。 惡意的API的應用程序代碼甚至能夠竊取另外一個應用程序或核心服務器的密鑰。
FastCGI技術目前支持語言有:C/C++、Java、Perl、Tcl、Python、SmallTalk、Ruby等。相關模塊在Apache, ISS, Lighttpd等流行的服務器上也是可用的。
FastCGI的不依賴於任何Web服務器的內部架構,所以即便服務器技術的變化, FastCGI依然穩定不變。
Web Server啓動時載入FastCGI進程管理器(IIS ISAPI或Apache Module)
FastCGI進程管理器自身初始化,啓動多個CGI解釋器進程(可見多個php-cgi)並等待來自Web Server的鏈接。
當客戶端請求到達Web Server時,FastCGI進程管理器選擇並鏈接到一個CGI解釋器。Web server將CGI環境變量和標準輸入發送到FastCGI子進程php-cgi。
FastCGI子進程完成處理後將標準輸出和錯誤信息從同一鏈接返回Web Server。當FastCGI子進程關閉鏈接時,請求便告處理完成。FastCGI子進程接着等待並處理來自FastCGI進程管理器(運行在Web Server中)的下一個鏈接。 在CGI模式中,php-cgi在此便退出了。
在上述狀況中,你能夠想象CGI一般有多慢。每個Web請求PHP都必須從新解析php.ini、從新載入所有擴展並重初始化所有數據結構。使用FastCGI,全部這些都只在進程啓動時發生一次。一個額外的好處是,持續數據庫鏈接(Persistent database connection)能夠工做。
由於是多進程,因此比CGI多線程消耗更多的服務器內存,PHP-CGI解釋器每進程消耗7至25兆內存,將這個數字乘以50或100就是很大的內存數。
在web服務器方面 | 在對數據進行處理的進程方面 | |
---|---|---|
CGI | fork一個新的進程進行處理 | 讀取參數,處理數據,而後就結束生命期 |
FAST-CGI | 用tcp方式跟遠程機子上的進程或本地進程創建鏈接 | 要開啓tcp端口,進入循環,等待數據的到來,處理數據 |
舉個例子: 服務端如今有個10萬個字單詞, 客戶每次會發來一個字符串,問以這個字符串爲前綴的單詞有多少個。 那麼能夠寫一個程序,這個程序會建一棵trie樹,而後每次用戶請求過來時能夠直接到這個trie去查找。 可是若是以cgi的方式的話,此次請求結束後這課trie也就沒了,等下次再啓動該進程時,又要新建一棵trie樹,這樣的效率就過低下了。 而用fastcgi的方式的話,這課trie樹在進程啓動時創建,之後就能夠直接在trie樹上查詢指定的前綴了。
記得曾在xp 配置 apache + php ,會在apache 配置下面一段:
LoadModule php5_module C:/php/php5apache2_2.dll
當PHP須要在Apache服務器下運行時,通常來講,它能夠模塊的形式集成, 此時模塊的做用是接收Apache傳遞過來的PHP文件請求,並處理這些請求, 而後將處理後的結果返回給Apache。若是咱們在Apache啓動前在其配置文件中配置好了PHP模塊, PHP模塊經過註冊apache2的ap_hook_post_config掛鉤,在Apache啓動的時候啓動此模塊以接受PHP文件的請求。
Apache 的Hook機制是指:Apache 容許模塊(包括內部模塊和外部模塊,例如mod_php5.so,mod_perl.so等)將自定義的函數注入到請求處理循環中。 換句話說,模塊能夠在Apache的任何一個處理階段中掛接(Hook)上本身的處理函數,從而參與Apache的請求處理過程。 mod_php5.so/ php5apache2.dll就是將所包含的自定義函數,經過Hook機制注入到Apache中,在Apache處理流程的各個階段負責處理php請 求。
有人測試nginx+PHP-FPM在高併發狀況下可能會達到Apache+mod_php5的5~10倍,如今nginx+PHP-FPM使用的人愈來愈多。
CGI工做原理:每當客戶請求CGI的時候,WEB服務器就請求操做系統生成一個新的CGI解釋器進程(如php-cgi.exe),CGI 的一個進程則處理完一個請求後退出,下一個請求來時再建立新進程。固然,這樣在訪問量不多沒有併發的狀況也行。但是當訪問量增大,併發存在,這種方式就不 適合了。因而就有了fastcgi。
FastCGI像是一個常駐(long-live)型的CGI,它能夠一直執行着,只要激活後,不會每次都要花費時間去fork一次(這是CGI最爲人詬病的fork-and-execute 模式)。
通常狀況下,FastCGI的整個工做流程是這樣的:
1.Web Server啓動時載入FastCGI進程管理器(IIS ISAPI或Apache Module)
2.FastCGI進程管理器自身初始化,啓動多個CGI解釋器進程(可見多個php-cgi)並等待來自Web Server的鏈接。
3.當客戶端請求到達Web Server時,FastCGI進程管理器選擇並鏈接到一個CGI解釋器。 Web server將CGI環境變量和標準輸入發送到FastCGI子進程php-cgi。
4.FastCGI 子進程完成處理後將標準輸出和錯誤信息從同一鏈接返回Web Server。當FastCGI子進程關閉鏈接時, 請求便告處理完成。FastCGI子進程接着等待並處理來自FastCGI進程管理器(運行在Web Server中)的下一個鏈接。 在CGI模式中,php-cgi在此便退出了。
PHP-FPM與Spawn-FCGI
Spawn-FCGI是一個通用的FastCGI管理服務器,它是lighttpd中的一部份,不少人都用Lighttpd的Spawn-FCGI進行FastCGI模式下的管理工做。 可是有缺點,因而PHP-fpm就是針對於PHP的,Fastcgi的一種實現,他負責管理一個進程池,來處理來自Web服務器的請求。目前,PHP-fpm是內置於PHP的。
PHP-CGI是PHP自帶的FastCGI管理器。
PHP-CGI的不足:
php-cgi變動php.ini配置後需重啓php-cgi才能讓新的php-ini生效,不能夠平滑重啓。
直接殺死php-cgi進程,php就不能運行了。(PHP-FPM和Spawn-FCGI就沒有這個問題,守護進程會平滑重新生成新的子進程。)
php-cgi是php提供給web serve也就是http前端服務器的cgi協議接口程序,當每次接到http前端服務器的請求都會開啓一個php-cgi進程進行處理,並且開啓的php-cgi的過程當中會先要重載配置,數據結構以及初始化運行環境,若是更新了php配置,那麼就須要重啓php-cgi才能生效,例如phpstudy就是這種狀況。
PHP-FPM是一個PHP FastCGI管理器,是隻用於PHP的,能夠在 http://php-fpm.org/download下載獲得。
PHP-FPM實際上是PHP源代碼的一個補丁,旨在將FastCGI進程管理整合進PHP包中。必須將它patch到你的PHP源代碼中,在編譯安裝PHP後纔可使用。
如今咱們能夠在最新的PHP 5.3.2的源碼樹裏下載獲得直接整合了PHP-FPM的分支,聽說下個版本會融合進PHP的主分支去。相對Spawn-FCGI,PHP-FPM在CPU和內存方面的控制都更勝一籌,並且前者很容易崩潰,必須用crontab進行監控,而PHP-FPM則沒有這種煩惱。
PHP5.3.3已經集成php-fpm了,再也不是第三方的包了。PHP-FPM提供了更好的PHP進程管理方式,能夠有效控制內存和進程、能夠平滑重載PHP配置,因此被PHP官方收錄了。
PHP-FPM的使用很是方便,配置都是在PHP-FPM.ini的文件內,而啓動、重啓均可以從php/sbin/PHP-FPM中進行。更方便的是修改php.ini後能夠直接使用PHP-FPM reload進行加載,無需殺掉進程就能夠完成php.ini的修改加載
結果顯示使用PHP-FPM可使php有不小的性能提高。PHP-FPM控制的進程cpu回收的速度比較慢,內存分配的很均勻。
而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就出場了
cgi能夠理解爲一種協議or一類處理程序,就是動態去生成文件,從程序上來理解就是web服務器exec這樣一個進程,而後交給他一些輸入參數,他就慢慢的處理完後把結果返回給web服務器,那從協議層面來講cgi協議就是規範了web服務器和cgi程序的一些輸入輸出參數的含義
因此能夠有不少不一樣的cgi程序,別能夠執行php腳本的or能夠執行python腳本的,只要符合這類規範就能供web服務器調用,固然它的缺點就是每次都須要去啓動這個cgi程序,這會使得處理速度很慢
針對這種缺陷加以改進就成了fastcgi,一樣的他也能夠理解爲一種協議or一個程序,它跟cgi的不一樣就是不須要每次去exec,它會事先啓動起來,做爲一個cgi的管理服務器存在,預先啓動一系列的子進程來等待處理,而後等待web服務器發過來的請求,一旦接受到請求就交由子進程處理,這樣因爲不須要在接受到請求後啓動cgi,會快不少。
phpfpm是php對fastcgi的一種具體實現,它的啓動後會建立多個cgi子進程,而後主進程負責管理子進程,同時它對外提供一個socket,那web服務器當要轉發一個動態請求時只須要按照fastcgi協議要求的格式將數據發往這個socket的就能夠了,那phpfpm建立的子進程去爭搶這個socket鏈接,誰搶到了誰處理並將結果返回給web服務器,那phpfpm主進程幹什麼了?比方說其中一個子進程異常退出了怎麼辦,那phpfpm會去監控他一旦發現一個cgi子進程就會又啓動一個,還有其餘諸多管理功能
phpfpm做爲一個獨立的進程存在 經過socket與nginx創建鏈接,而mod_php 是做爲一個模塊被加載進了apache服務器,同時他們兩做爲cgi調度管理器,他們對其管理的方式也不同
通俗的能夠把服務器看做餐廳,用戶請求看做來用餐的顧客,服務器處理請求看做解決顧客的就餐問題(響應輸出一份飯)。
服務器上靜態資源看做已作好的飯,只要放到餐盒裏就能夠返回給顧客,動態資源須要廚房大廚現成作份再放到餐盒裏返回給顧客。
php_mod這個大廚有個特色,看見有顧客進門就點火,無論顧客要不要現作的,有點浪費資源
php_fpm這個大廚有好多小弟一直點着火(多個處理進程),等有顧客說要現作,大廚就安排小弟作份返回給客戶
cgi也是個大廚,不過他等到顧客要現作,他才點火,作飯,而後熄火。等待下一個要現作的到來
fastcgi呢就是個大廚僱了一幫小弟,專門作須要現場作的飯,大廚只管分派任務,小弟真正操鍋作飯。