比較CGI,FastCGI,PHP-CGI與PHP-FPM的區別

最早的Web服務器,可以簡單地響應瀏覽器發來的HTTP請求,並將存儲在服務器上的HTML文件返回給瀏覽器,也就是靜態html。

隨著時間的變化,網站也越來越複雜,所以出現動態技術。但是服務器並不能直接運行 php,asp這樣的文件,自己不能做,外包給別人吧,但是要與第三做個約定,我給你什麼,然後你給我什麼,就是握把請求參數發送給你,然後我接收你的處 理結果給客戶端。那這個約定就是 common gateway interface,簡稱cgi(cgi只是接口協議)

比較CGI,FastCGI,PHP-CGI與PHP-FPM的區別

image.png

cgi就像翻譯機,將PHP語言給服務器解釋,便於相互之間的理解和通訊,最後呈現給瀏覽器查看

比較CGI,FastCGI,PHP-CGI與PHP-FPM的區別

請求的動態頁面模型.jpg

WEB服務器將根據CGI程序的類型決定數據向CGI程序的傳送方式,一般來講是通過標準輸入/輸出流和環境變量來與CGI程序間傳遞數據。 如下圖所示:

比較CGI,FastCGI,PHP-CGI與PHP-FPM的區別

image.png

CGI程序通過標準輸入(STDIN)和標準輸出(STDOUT)來進行輸入輸出。此外CGI程序還通過環境變量來得到輸入,操作系統提供了許 多環境變量,它們定義了程序的執行環境,應用程序可以存取它們。

Web服務器和CGI接口又另外設置了一些環境變量,用來向CGI程序傳遞一些重要的參 數。CGI的GET方法還通過環境變量QUERY-STRING向CGI程序傳遞Form中的數據。 下面是一些常用的CGI環境變量:

變量名 描述 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

CGI全稱是 公共網關接口(Common Gateway Interface),HTTP服務器與你的或其它機器上的程序進行交談的一種工具,其程序須運行在網絡服務器上。

CGI可以用任何一種語言編寫,只要這種語言具有標準輸入、輸出和環境變量。如php,perl,tcl等。

CGI是HTTP Server和一個獨立的進程之間的協議,把HTTP Request的Header設置成進程的環境變量,HTTP Request的正文設置成進程的標準輸入,而進程的標準輸出就是HTTP Response包括Header和正文。

FastCGI

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具有語言無關性.

FastCGI在進程中的應用程序,獨立於核心web服務器運行,提供了一個比API更安全的環境。APIs把應用程序的代碼與核心的web服務器鏈接在一起,這意味著在一個錯誤的API的應用程序可能會損壞其他應用程序或核心服務器。 惡意的API的應用程序代碼甚至可以竊取另一個應用程序或核心服務器的密鑰。

FastCGI技術目前支持語言有:C/C++、Java、Perl、Tcl、Python、SmallTalk、Ruby等。相關模塊在Apache, ISS, Lighttpd等流行的服務器上也是可用的。

FastCGI的不依賴於任何Web服務器的內部架構,因此即使服務器技術的變化, FastCGI依然穩定不變。

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)可以工作。

FastCGI的不足

因為是多進程,所以比CGI多線程消耗更多的服務器內存,PHP-CGI解釋器每進程消耗7至25兆內存,將這個數字乘以50或100就是很大的內存數。

fastcgi跟cgi的區別是:​

在web服務器方面 在對數據進行處理的進程方面 CGI fork一個新的進程進行處理 讀取參數,處理數據,然後就結束生命期 FAST-CGI 用tcp方式跟遠程機子上的進程或本地進程建立連接 要開啟tcp端口,進入循環,等待數據的到來,處理數據 舉個例子: 服務端現在有個10萬個字單詞, 客戶每次會發來一個字符串,問以這個字符串為前綴的單詞有多少個。 那麼可以寫一個程序,這個程序會建一棵trie樹,然後每次用戶請求過來時可以直接到這個trie去查找。 但是如果以cgi的方式的話,這次請求結束後這課trie也就沒了,等下次再啟動該進程時,又要新建一棵trie樹,這樣的效率就太低下了。 而用fastcgi的方式的話,這課trie樹在進程啟動時建立,以後就可以直接在trie樹上查詢指定的前綴了。

apache 模塊方式

記得曾在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 與 fastcgi

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-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-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還是使用的原先的配置,等到這個連接後下一次連接的時候會使用新的配置初始化,這就是平滑過渡。

使用場景

  1. 一般web服務器接受到瀏覽器的請求時,如果是靜態資源的話就直接將其返回給瀏覽器,如果是動態資源的話那就沒有現成的資源返回了,那這個時候cgi就出場了
  2. cgi可以理解為一種協議or一類處理程序,就是動態去生成文件,從程序上來理解就是web服務器exec這樣一個進程,然後交給他一些輸入參數,他就慢慢的處理完後把結果返回給web服務器,那從協議層面來說cgi協議就是規範了web服務器和cgi程序的一些輸入輸出參數的含義
  3. 所以可以有很多不同的cgi程序,別可以執行php腳本的or可以執行python腳本的,只要符合這類規範就能供web服務器調用,當然它的缺點就是每次都需要去啟動這個cgi程序,這會使得處理速度很慢
  4. 針對這種缺陷加以改進就成了fastcgi,同樣的他也可以理解為一種協議or一個程序,它跟cgi的不同就是不需要每次去exec,它會事先啟動起來,作為一個cgi的管理服務器存在,預先啟動一系列的子進程來等待處理,然後等待web服務器發過來的請求,一旦接受到請求就交由子進程處理,這樣由於不需要在接受到請求後啟動cgi,會快很多。
  5. phpfpm是php對fastcgi的一種具體實現,它的啟動後會創建多個cgi子進程,然後主進程負責管理子進程,同時它對外提供一個socket,那web服務器當要轉發一個動態請求時只需要按照fastcgi協議要求的格式將數據發往這個socket的就可以了,那phpfpm創建的子進程去爭搶這個socket連接,誰搶到了誰處理並將結果返回給web服務器,那phpfpm主進程幹什麼了?比方說其中一個子進程異常退出了怎麼辦,那phpfpm會去監控他一旦發現一個cgi子進程就會又啟動一個,還有其他諸多管理功能
  6. phpfpm作為一個獨立的進程存在 通過socket與nginx建立連接,而mod_php 是作為一個模塊被加載進了apache服務器,同時他們兩作為cgi調度管理器,他們對其管理的方式也不一樣

通俗的可以把服務器看作餐廳,用戶請求看作來用餐的顧客,服務器處理請求看作解決顧客的就餐問題(響應輸出一份飯)。

服務器上靜態資源看作已做好的飯,只要放到餐盒裡就可以返回給顧客,動態資源需要廚房大廚現成做份再放到餐盒裡返回給顧客。

php_mod這個大廚有個特點,看見有顧客進門就點火,不管顧客要不要現做的,有點浪費資源

php_fpm這個大廚有好多小弟一直點著火(多個處理進程),等有顧客說要現做,大廚就安排小弟做份返回給客戶

cgi也是個大廚,不過他等到顧客要現做,他才點火,做飯,然後熄火。等待下一個要現做的到來

fastcgi呢就是個大廚僱了一幫小弟,專門做需要現場做的飯,大廚只管分派任務,小弟真正操鍋做飯。

鏈接:https://www.jianshu.com/p/80e46a80fdbd


分享到:


相關文章: