1. 程式人生 > >CGI,FastCGI, php-fpm , php_mod

CGI,FastCGI, php-fpm , php_mod

CGI:common gateway interface,通用閘道器介面。

最初的伺服器只能展示靜態內容,靜態的html,圖片等等。隨著需求發展,網站變得複雜,需要’動態語言’支援,但是伺服器不能直接執行動態指令碼(asp,php,python,java等等),這時候需要把動態指令碼交給動態語言的直譯器或者編譯器去執行,然後拿到執行結果,返回給瀏覽器。但是動態語言眾多,伺服器軟體和直譯器/編譯器之間不能每個都做定製化的資料傳輸規定,所以要做一套標準的協議,這就是CGI,它是一種協議,依照CGI協議去編寫的程式即為CGI程式/應用/指令碼。 

CGI介面標準包括標準輸入、環境變數、標準輸出三部分。
1.標準輸入
  CGI程式像其他可執行程式一樣,可通過標準輸入(stdin)從Web伺服器得到輸入資訊,如Form中的資料,這就是所謂的向CGI程式傳遞資料的POST方法。這意味著在作業系統命令列狀態可執行CGI程式,對CGI程式進行除錯。POST方法是常用的方法。
2.環境變數
  作業系統提供了許多環境變數,它們定義了程式的執行環境,應用程式可以存取它們。Web伺服器和CGI介面又另外設定了自己的一些環境變數,用來向CGI程式傳遞一些重要的引數。CGI的GET方法還通過環境變數QUERY-STRING向CGI程式傳遞Form中的資料。
3.標準輸出
  CGI程式通過標準輸出(stdout)將輸出資訊傳送給Web伺服器。傳送給Web伺服器的資訊可以用各種格式,通常是以純文字或者HTML文字的形式,這樣我們就可以在命令列狀態除錯CGI程式,並且得到它們的輸出。

這裡寫圖片描述

伺服器通過標準輸入把資料傳給CGI程式,CGI程式通過標準輸出把資料返回給伺服器,並且CGI程式執行期間可以使用一些系統環境變數,這些標準輸入(STDIN)和標準輸出(STDOUT)以及環境變數,都是遵循CGI協議。

這裡寫圖片描述

有了CGI協議和CGI指令碼,那指令碼需要有個執行模式

正常情況下,伺服器接受一個請求,產生一個CGI程式的直譯器程序,直譯器執行指令碼,返回結果給伺服器,程序關閉,伺服器把結果返回給瀏覽器。

如果訪問量增大,程序的建立和關閉將會耗費巨大的系統資源,顯然普通的執行模式不能滿足高訪問的需求。

FastCGI應需求而生
以PHP為例,PHP解析器會解析php.ini檔案,初始化執行環境。普通的執行模式下,伺服器對每個請求都會執行這些步驟,所以處理每個時間的時間會比較長。
相比普通的CGI程式執行模式,FastCGI會提高效能
首先,Fastcgi會先啟一個master,解析配置檔案,初始化執行環境,然後再啟動多個worker。當請求過來時,master會傳遞給一個worker,然後立即可以接受下一個請求。這樣就避免了重複的勞動,效率自然是高。而且當worker不夠用時,master可以根據配置預先啟動幾個worker等著;當然空閒worker太多時,也會停掉一些,這樣就提高了效能,也節約了資源。這就是fastcgi的對程序的管理。

至此以上皆為,協議或者模式,與指令碼語言無關,但是最終協議/模式的實現需要載體。

PHP-FPM即為實現fastCGI的程序
Nginx和PHP-fpm是一對好基友,使用過的同學都知道,如果要在Nginx下執行PHP,除了要開啟Nginx服務,還要開啟一個php-fpm服務。並且在開啟兩個服務前需要配置Nginx,其中Nginx中有幾行配置:

location ~ .php$ {
    root html;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name; include fastcgi_params; }

Nginx不支援對外部程式的直接呼叫或者解析,所有的外部程式(包括PHP)必須通過FastCGI介面來呼叫。FastCGI介面在Linux下是socket,(這個socket可以是檔案socket,也可以是ip socket)。

fastcgi_pass 127.0.0.1:9000;

註明了socket介面的地址。而在php-fpm中配置了,php-fpm的程序埠即為9000。
二者埠一樣,Nginx和php-fpm就綁定了,之後所有的動態指令碼都會去轉給9000埠即php-fpm處理。
當開啟php-fpm的時候,通過ps -ef |grep fpm
這裡寫圖片描述
emmmm、和前面介紹的fastCGI一毛一樣。

Nginx是把動態請求轉給第三方(php-fpm)處理,而Apache可以把第三方’收入囊中’,這就是php_mod
Apache的配置檔案中有‘載入模組’的配置,如果要執行PHP,那必不可少的一行配置是
win下:

LoadModule php5_module C:/php/php5apache2_2.dll

linux下:

LoadModule php5_module modules/libphp5.so

這裡的配置項即為,將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請求。

Apache一般會採用多程序模式, Apache啟動後會fork出多個子程序,每個程序的記憶體空間獨立,每個子程序都會經過開始和結束環節, 不過每個程序的開始階段只在程序fork出來以來後進行,在整個程序的生命週期內可能會處理多個請求。 只有在Apache關閉或者程序被結束之後才會進行關閉階段,在這兩個階段之間會隨著每個請求重複請求開始-請求關閉的環節。
這裡寫圖片描述
多執行緒模式和多程序中的某個程序類似,不同的是在整個程序的生命週期內會並行的重複著 請求開始-請求關閉的環節.
在這種模式下,只有一個伺服器程序在執行著,但會同時執行很多執行緒,這樣可以減少一些資源開銷,向Module init和Module shutdown就只需要執行一遍就行了,一些全域性變數也只需要初始化一次,因為執行緒獨具的特質,使得各個請求之間方便的共享一些資料成為可能。
多執行緒工作方式如下圖
這裡寫圖片描述
Apache一般使用多程序模式prefork
在linux下使用#http –l 命令可以檢視當前使用的工作模式。也可以使用#apachectl -l命令。
看到的prefork.c,說明使用的prefork工作模式。
prefork 程序池模型,用在 UNIX 和類似的系統上比較多,主要是由於寫起來方便,也容易移植,還不容易出問題。要知道,如果採用執行緒模型的話,使用者執行緒、核心執行緒和混合型執行緒有不同的特性,移植起來就麻煩。prefork 模型,即預先 fork() 出來一些子程序緩衝一下,用一個鎖來控制同步,連線到來了就放行一個子程序,讓它去處理。
prefork MPM 使用多個子程序,每個子程序只有一個執行緒。每個程序在某個確定的時間只能維持一個連線。在大多數平臺上,Prefork MPM在效率上要比Worker MPM要高,但是記憶體使用大得多。prefork的無執行緒設計在某些情況下將比worker更有優勢:他能夠使用那些沒有處理好執行緒安全的第三方模組,並 且對於那些執行緒除錯困難的平臺而言,他也更容易除錯一些。
無論那種模式,其本質都是和fastCGI的目的一樣,一次性載入,多個程序常駐。
相關連結:
http://blog.csdn.net/chuanzhilong/article/details/52868737
https://segmentfault.com/a/1190000007322358
https://www.cnblogs.com/liuzhang/p/3929198.html
http://blog.csdn.net/hguisu/article/details/7377520