1)CGI(通用網關接口 / Common Gateway Interface)
2)FastCGI(常駐型CGI / Long-Live CGI)
3)CLI(命令行運行 / Command Line Interface)
4)Web模塊模式(Apache等Web服務器運行的模式)
5)ISAPI(Internet Server Application Program Interface)
備注:在PHP5.3以後,PHP不再有ISAPI模式
CGI是個協議,跟進程什麼的沒關系。那fastcgi又是什麼呢?Fastcgi是用來提高CGI程序性能的。
PHP的CGI實現本質是是以socket編程實現一個TCP或UDP協議的服務器,當啟動時,創建TCP/UDP協議的服務器的socket監聽, 並接收相關請求進行處理。這只是請求的處理,在此基礎上添加模塊初始化,sapi初始化,模塊關閉,sapi關閉等就構成了整個CGI的生命周期。
CGI全稱是“通用網關接口”(Common Gateway Interface), 它可以讓一個客戶端,從網頁浏覽器向執行在Web服務器上的程序請求數據。
CGI描述了客戶端和這個程序之間傳輸數據的一種標准。
CGI的一個目的是要獨立於任何語言的,所以CGI可以用任何一種語言編寫,只要這種語言具有標准輸入、輸出和環境變量。如php,perl,tcl等
CGI已經是比較老的模式了,這幾年都很少用了。
每有一個用戶請求,都會先要創建CGI的子進程,然後處理請求,處理完後結束這個子進程,這就是Fork-And-Execute模式。 當用戶請求數量非常多時,會大量擠占系統的資源如內存,CPU時間等,造成效能低下。 所以用CGI方式的服務器有多少連接請求就會有多少CGI子進程,子進程反復加載是CGI性能低下的主要原因。當web server收到/index.php這個請求後,會啟動對應的CGI程序,這裡就是PHP的解析器。接下來PHP解析器會解析php.ini文件,初始化執行環境,然後處理請求,再以規定CGI規定的格式返回處理後的結果,退出進程。web server再把結果返回給浏覽器。
fast-cgi 是cgi的升級版本,FastCGI 像是一個常駐 (long-live) 型的 CGI,它可以一直執行著,只要激活後,不會每次都要花費時間去 fork 一次 (這是 CGI 最為人诟病的 fork-and-execute 模式)。
備注:PHP的FastCGI進程管理器是PHP-FPM(PHP-FastCGI Process Manager)
因為是多進程,所以比CGI多線程消耗更多的服務器內存,PHP-CGI解釋器每進程消耗7至25兆內存,將這個數字乘以50或100就是很大的內存數。
Nginx 0.8.46+PHP 5.2.14(FastCGI)服務器在3萬並發連接下,開啟的10個Nginx進程消耗150M內存(15M*10=150M),開啟的64個php-cgi進程消耗1280M內存(20M*64=1280M),加上系統自身消耗的內存,總共消耗不到2GB內存。如果服務器內存較小,完全可以只開啟25個php-cgi進程,這樣php-cgi消耗的總內存數才500M。
上面的數據摘自Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建勝過Apache十倍的Web服務器(第6版)
PHP-CLI是PHP Command Line Interface的簡稱,就是PHP在命令行運行的接口,區別於在Web服務器上運行的PHP環境(PHP-CGI,ISAPI等)。
也就是說,PHP不單可以寫前台網頁,它還可以用來寫後台的程序。 PHP的CLI Shell腳本適用於所有的PHP優勢,使創建要麼支持腳本或系統甚至與GUI應用程序的服務端,在Windows和Linux下都是支持PHP-CLI模式的。我們在Linux下經常使用”php –m”查找PHP安裝了那些擴展就是PHP命令行運行模式;
PHP開始執行以後會經過兩個主要的階段:處理請求之前的開始階段和請求之後的結束階段。
在整個SAPI生命周期內(例如Apache啟動以後的整個生命周期內或者命令行程序整個執行過程中), 該過程只進行一次。
啟動Apache後,PHP解釋程序也隨之啟動;
PHP調用各個擴展(模塊)的MINIT方法,從而使這些擴展切換到可用狀態。
PHP_MINIT_FUNCTION(myphpextension)
{
// 注冊常量或者類等初始化操作
return SUCCESS;
}
該過程發生在請求階段, 例如通過url請求某個頁面,則在每次請求之前都會進行模塊激活(RINIT請求開始)。
請求到達之後,SAPI層將控制權交給PHP層,PHP初始化本次請求執行腳本所需的環境變量例如是Session模塊的RINIT,如果在php.ini中啟用了Session 模塊,那在調用該模塊的RINIT時就會初始化$_SESSION變量,並將相關內容讀入; 然後PHP會調用所有模塊RINIT函數,即“請求初始化”。
在這個階段各個模塊也可以執行一些相關的操作, 模塊的RINIT函數和MINIT函數類似 ,RINIT方法可以看作是一個准備過程,在程序執行之前就會自動啟動。
請求處理完後就進入了結束階段, 一般腳本執行到末尾或者通過調用exit()或者die()函數,PHP都將進入結束階段. 和開始階段對應,結束階段也分為兩個環節,一個在請求結束後(RSHUWDOWN),一個在SAPI生命周期結束時(MSHUTDOWN).
請求處理完後就進入了結束階段,PHP就會啟動清理程序。
它會按順序調用各個模塊的RSHUTDOWN方法。
RSHUTDOWN用以清除程序運行時產生的符號表,也就是對每個變量調用unset函數。
最後,所有的請求都已處理完畢
SAPI也准備關閉了
PHP調用每個擴展的MSHUTDOWN方法
這時各個模塊最後一次釋放內存的機會。
(這個是對於CGI和CLI等SAPI,沒有“下一個請求”,所以SAPI立刻開始關閉。)
整個PHP生命周期就結束了。要注意的是,只有在服務器沒有請求的情況下才會執行“啟動第一步”和“關閉第二步”。
模塊初始化階段(Module init)
即調用每個拓展源碼中的的PHP_MINIT_FUNCTION中的方法初始化模塊,進行一些模塊所需變量的申請,內存分配等。
請求初始化階段(Request init)
即接受到客戶端的請求後調用每個拓展的PHP_RINIT_FUNCTION中的方法,初始化PHP腳本的執行環境。
執行PHP腳本
請求結束(Request Shutdown)
這時候調用每個拓展的PHP_RSHUTDOWN_FUNCTION方法清理請求現場,並且ZE開始回收變量和內存
關閉模塊(Module shutdown)
Web服務器退出或者命令行腳本執行完畢退出會調用拓展源碼中的PHP_MSHUTDOWN_FUNCTION 方法
CLI/CGI模式的PHP屬於單進程的SAPI模式。這類的請求在處理一次請求後就關閉。
也就是只會經過如下幾個環節: 開始 - 請求開始 - 請求關閉 - 結束 SAPI接口實現就完成了其生命周期。
多線程模式和多進程中的某個進程類似,不同的是在整個進程的生命周期內會並行的重復著 請求開始-請求關閉的環節.
在這種模式下,只有一個服務器進程在運行著,但會同時運行很多線程,這樣可以減少一些資源開銷,向Module init和Module shutdown就只需要運行一遍就行了,一些全局變量也只需要初始化一次,因為線程獨具的特質,使得各個請求之間方便的共享一些數據成為可能。