什麼是FastCGI
FastCGI :Fast Common Gateway Interface(快速通用網關接口),它是CGI的增強版。FastCGI是一個快速、開放和安全的web server接口,解決了傳統CGI的性能問題,卻又沒有帶來編程的複雜性。老的CGI程序可以很輕易的移植成FastCGI程序。
FastCGI的技術原理
如果想了解FastCGI的技術原理就要了解何為"短生存期應用程序",何為"長生存期應用程序"。
先從CGI技術開刀,以下是CGI技術的理論:每次當客户請求一個CGI的時候,Web服務器就請求操作系統生成一個新的CGI進程。當CGI滿足要求後,服務器就殺死這個進程。服務器對客户端的每個請求都要重複這樣的過程。
而FastCGI技術的理論為:FastCGI程序一旦產生後,他可以持續工作,足夠滿足客户的請求直到被明確的終止。如果你希望通過協同處理來提高程序的性能,你可以請求Web服務器運行多個FastCGI 應用程序的副本。 CGI就是所謂的短生存期應用程序,FastCGI就是所謂的長生存期應用程序。
由於FastCGI程序並不需要不斷的產生新進程,可以大大降低服務器的壓力。並且產生較高的應用效率。
FastCGI的特點
- 打破傳統頁面處理技術
傳統的頁面處理技術,程序必須與Web服務器或Application服務器處於同一台服務器中。這種歷史已經早N年被FastCGI技術所打破,FastCGI技術的應用程序可以被安裝在服務器羣中的任何一台服務器,而通過TCP/IP協議與Web服務器通訊,這樣做既適合開發大型分佈式Web羣,也適合高效數據庫控制。
- 明確的請求模式
CGI技術沒有一個明確的角色,在FastCGI程序中,程序被賦予明確的角色(響應器角色(Responder)、認證器角色(Authorizer)、過濾器角色(Filter))。
- 獨立性
架構獨立性:FastCGI接口並不綁定特定的應用服務器架構,應用既可以是單線程的也可是多線程的。
進程獨立性:FastCGI進程是獨立於服務器的進程,對FastCGI進程的調試不影響服務器。同理,FastCGI進程的崩潰也不至於服務器崩潰。
語言獨立性:FastCGI技術目前支持語言有:C/C++、Java、Perl、Tcl、Python、SmallTalk、Ruby等。
如何開發FastCGI程序
實現細節
先來看看傳統CGI是怎麼做的,如下圖:
圖一:CGI的數據流
CGI應用是通過標準的POSIX流(stdin, stdout, stderr和環境變量)加上環境變量,來與HTTP服務器進行通信。
與CGI類似,FastCGI採用的方法是:在HTTP進程和FastCGI進程之間創建一個全雙工的連接,數據報通過FastCGI協議封裝在兩個進程之間傳遞。
stdin和環境變量被封裝在連接的輸入部分;stdout和stderr被封裝在連接的輸出部分。
因此,作為輸入端,FastCGI程序從連接上接收數據,解包,分離出stdin和環境變量,然後調用應用處理邏輯。作為輸出端,FastCGI用FastCGI協議打包stdout和stderr,發送給HTTP服務器處理。
由於FastCGI應用不要求和HTTP服務器運行在同一個節點上,因此,FastCGI支持兩種形式的連接:1)流管道,用於在同一個節點上的通信;2)TCP流,用於不同節點上的通信。
下圖是FastCGI應用和HTTP服務器不在同一個機器上的數據流圖:
圖二:FastCGI和HTTP不在同一節點的數據流
程序框架
不同於CGI程序的單次執行特性,FastCGI的主程序框架有一個循環,如下:
Initialize application;
while(FCGI_Accept() >= 0) {
Process request;
}
初始化部分,只執行一次,所以常常把一些耗時的工作放在此處理,如:打開和連接數據庫,計算表和位圖值等。
另外初始化部分,還完成環境變量初始化等工作。
然後,程序阻塞在FCGI_Accep()調用上,一旦有連接上了就處理,否則就阻塞。
一個簡單的FastCGI程序實例:
#include "fcgi_stdio.h" /* fcgi library; put it first*/
#include <stdlib.h>
int count;
void initialize(void)
{
count=0;
}
void main(void)
{
/* Initialization. */
initialize();
/* Response loop. */
while (FCGI_Accept() >= 0) {
printf("Content-type: text/html\r\n"
"\r\n"
"<title>FastCGI Hello! (C, fcgi_stdio library)</title>"
"<h1>FastCGI Hello! (C, fcgi_stdio library)</h1>"
"Request number %d running on host <i>%s</i>\n",
++count, getenv("SERVER_HOSTNAME"));
}
}
另外一個例子,是從stdin和環境變量獲取表單參數的例子,由於代碼過長,以附件形式給出:
附錄:CGI常用環境變量
|
環境變量 |
説明 |
|
ALL_HTTP |
未包括在本表格中給出的變量內的所有HTTP標題,如:這個變量來自表格HTTP_<標題欄名稱> |
|
QUERY_STRING |
傳遞給程式的 query 信息,即:在指向URL中跟在問號(?)後的信息 |
|
REMOTE_HOST |
使用者發出 request 的遠端 host 名稱 |
|
REMOTE_ADDR |
使用者發出 request 的遠端 IP 位址 |
|
AUTH_TYPE |
用來確定使用者合法性的監定方法 |
|
REMOTE_USER |
使用者的合法名稱 |
|
REMOTE_IDENT |
發出 request 的使用者 |
|
CONTENT_TYPE |
query 信息中的 MIME 類型 |
|
CONTENT_LENGTH |
以字節為單位的從客户端接收來的腳步長度 |
|
HTTP_FORM |
使用者發出 request 的電子郵件訊息 |
|
HTTP_ACCEPT |
client 可以接受的 MIME 類型列表 |
|
HTTP_COOKIE |
與你站點打交道的客户的任何cookie(存儲片)集合 |
|
HTTP_USER_AGENT |
client 用來發出 request 的瀏覽器 |
|
GATEWAY_INTERFACE |
Server 使用的 CGI 版本 |
|
SERVER_NAME |
Server 的 host 名稱或 IP 位址 |
|
SERVER_SOFTWARE |
迴應 client request 的 Server 軟體名稱和版本 |
|
SERVER_PROTOCOL |
傳遞資訊所用的協定名稱或版本 |
|
SERVER_PORT |
Server 正在執行的 port number |
|
SERVER_PORT_SECURE |
值為0或1,值1表示請求出現在加密端口 |
|
URL |
請求的URL地址 |
|
REQUEST_METHOD |
發出 request 的方法 |
|
PATH_INFO |
傳遞給 CGI 程式的額外路徑 |
|
PATH_TRANSLATED |
存在 PATH_INFO 中的給定路徑的傳遞版本 |
|
SCRIPT_NAME |
程式執行時的 virtual path |
|
DOCUMENT_ROOT |
網路提供的文件服務所在路徑 |
|
HTTP_REFERER |
在讀取 CGI 程式前,client 所指的文件 URL |
這個模塊允許nginx同FastCGI協同工作,並且控制哪些參數將被安全傳遞。
例:
location /
{
fastcgi_pass localhost:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/www/scripts/php$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
}
一個在緩存中的實例:
http
{
fastcgi_cache_path /path/to/cache
levels=1:2 keys_zone=NAME:10m inactive=5m clean_time=2h00m;
server
{
location /
{
fastcgi_pass http://127.0.0.1;
fastcgi_cache NAME;
fastcgi_cache_valid 200 302 1h;
fastcgi_cache_valid 301 1d;
fastcgi_cache_valid any 1m;
fastcgi_cache_min_uses 1;
fastcgi_cache_use_stale error timeout invalid_header http_500;
}
}
}
0.7.48以後,緩存遵循後端服務器的Cache-Control, Expires等。
fastcgi_buffers
語法:fastcgi_buffers the_number is_size;
默認值:fastcgi_buffers 8 4k/8k;
使用字段:http, server, location
這個參數指定了從FastCGI服務器到來的應答,本地將用多少和多大的緩衝區讀取,默認這個參數等於分頁大小,根據環境的不同可能是4K, 8K或16K。
fastcgi_buffer_size
語法:fastcgi_buffer_size the_size ;
默認值:fastcgi_buffer_size 4k/8k ;
使用字段:http, server, location
這個參數指定將用多大的緩衝區來讀取從FastCGI服務器到來應答的第一部分。
通常來説在這個部分中包含一個小的應答頭。
默認這個值為fastcgi_buffers指令中的每塊大小,可以將這個值設置更小。
fastcgi_cache
語法:fastcgi_cache zone;
默認值:off
使用字段:http, server, location
為緩存實際使用的共享內存指定一個區域,相同的區域可以用在不同的地方。
fastcgi_cache_key
語法:fastcgi_cache_key line ;
默認值:none
使用字段:http, server, location
設置緩存的關鍵字,如:
fastcgi_cache_key localhost: 9000 $ request_uri;
fastcgi_cache_methods
語法:fastcgi_cache_methods [GET HEAD POST];
默認值:fastcgi_cache_methods GET HEAD;
使用字段:main,http,location
無法禁用GET/HEAD ,即使你只是這樣設置:
fastcgi_cache_methods POST;
fastcgi_cache_min_uses
語法:fastcgi_cache_min_uses n
默認值:fastcgi_cache_min_uses 1
使用字段:http, server, location
fastcgi_cache_path
語法:fastcgi_cache_path /path/to/cache [levels=m:n keys_zone=name:time inactive=time clean_time=time]
默認值:none
使用字段:http, server, location
fastcgi_cache_use_stale
語法:fastcgi_cache_use_stale [updating|error|timeout|invalid_header|http_500]
默認值:fastcgi_cache_use_stale off;
使用字段:http, server, location
fastcgi_cache_valid
語法:fastcgi_cache_valid [http_error_code|time]
默認值:none
使用字段:http, server, location
fastcgi_index
語法:fastcgi_index file
默認值:none
使用字段:http, server, location
如果URI以斜線結尾,參數將加到URI後面,這個值將存儲在變量$fastcgi_script_name中。
fastcgi_hide_header
語法:fastcgi_hide_header name
使用字段:http, server, location
默認情況下nginx不會將來自FastCGI服務器的"Status"和"X-Accel-..."頭傳送到客户端,這個參數也可以隱藏某些其它的頭。
如果必須傳遞"Status"和"X-Accel-..."頭,則必須使用fastcgi_pass_header強制其傳送到客户端。
fastcgi_ignore_client_abort
語法:fastcgi_ignore_client_abort on|off
默認值:fastcgi_ignore_client_abort off
使用字段:http, server, location
如果當前連接請求FastCGI服務器失敗,為防止其與nginx服務器斷開連接,可以用這個指令。
fastcgi_intercept_errors
語法:fastcgi_intercept_errors on|off
默認值:fastcgi_intercept_errors off
使用字段:http, server, location
這個指令指定是否傳遞4xx和5xx錯誤信息到客户端,或者允許nginx使用error_page處理錯誤信息。
你必須明確的在error_page中指定處理方法使這個參數有效,正如Igor所説“如果沒有適當的處理方法,nginx不會攔截一個錯誤,
這個錯誤不 會顯示自己的默認頁面,這裏允許通過某些方法攔截錯誤。
fastcgi_max_temp_file_size
語法:fastcgi_max_temp_file_size 0
默認值:?
使用字段:?
根據源代碼關閉FastCGI緩衝。
fastcgi_param
語法:fastcgi_param parameter value
默認值:none
使用字段:http, server, location
指定一些傳遞到FastCGI服務器的參數。
可以使用字符串,變量,或者其組合,這裏的設置不會繼承到其他的字段,設置在當前字段會清除掉任何之前的定義。
下面是一個PHP需要使用的最少參數:
fastcgi_param SCRIPT_FILENAME /home/www/scripts/php$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string;
PHP使用SCRIPT_FILENAME參數決定需要執行哪個腳本,QUERY_STRING包含請求中的某些參數。
如果要處理POST請求,則需要另外增加三個參數:
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
如果PHP在編譯時帶有--enable-force-cgi-redirect,則必須傳遞值為200的REDIRECT_STATUS參數:
fastcgi_param REDIRECT_STATUS 200;
fastcgi_pass
語法:fastcgi_pass fastcgi-server
默認值:none
使用字段:http, server, location
指定FastCGI服務器監聽端口與地址,可以是本機或者其它:
fastcgi_pass localhost:9000;
使用Unix socket:
fastcgi_pass unix:/tmp/fastcgi.socket;
同樣可以使用一個upstream字段名稱:
upstream backend
{
server localhost:1234;
}
fastcgi_pass backend;
fastcgi_pass_header
語法:fastcgi_pass_header name
默認值:none
使用字段:http, server, location
fastcgi_read_timeout
語法:fastcgi_read_timeout time
默認值:60
使用字段:http, server, location
前端FastCGI服務器的響應超時時間,如果有一些直到它們運行完才有輸出的長時間運行的FastCGI進程,或者在錯誤日誌中出現前端服務器響應超時
錯誤,可能需要調整這個值。
fastcgi_redirect_errors
語法:fastcgi_redirect_errors on|off
將來自fastcgi_intercept_errors的錯誤重命名。參數傳遞到FastCGI服務器。
請求頭以參數的形式傳遞到FastCGI服務器,在FastCGI的應用程序或者腳本中運行,這些參數通常是環境變量的形式,例如:User-agent
頭是以HTTP_USER_AGENT形式轉發,另外可以藉助fastcgi_param指令可以傳遞任意參數的HTTP請求頭。
fastcgi_split_path_info
語法:fastcgi_split_path_info regex
使用字段:location
可用版本:0.7.31以上
location ~ ^(.+\.php)(.*)$
{
...
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME /path/to/php$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
...
}
fastcgi_store
語法:fastcgi_store [on | off | path]
默認值:fastcgi_store off
使用字段:http, server, location
制定了存儲前端文件的路徑,參數on指定了將使用root和alias指令相同的路徑,off禁止存儲,此外,參數中可以使用變量使路徑名更明確:
fastcgi_store /data/www$original_uri;
應答中的"Last-Modified"頭將設置文件的最後修改時間,為了使這些文件更加安全,可以將其在一個目錄中存為臨時文件,使用 fastcgi_temp_path指令。
這個指令可以用在為那些不是經常改變的後端動態輸出創建本地拷貝的過程中。如:
location /images/
{
root /data/www;
error_page 404 = /fetch$uri;
}
location /fetch
{
internal;
fastcgi_pass fastcgi://backend;
fastcgi_store on;
fastcgi_store_access user:rw group:rw all:r;
fastcgi_temp_path /data/temp;
alias /data/www;
}
fastcgi_store並不是緩存,某些需求下它更像是一個鏡像。
fastcgi_store_access
語法:fastcgi_store_access users:permissions [users:permission ...]
默認值:fastcgi_store_access user:rw
使用字段:http, server, location
這個參數指定創建文件或目錄的權限,例如:
fastcgi_store_access user:rw group:rw all:r;
如果要指定一個組的人的相關權限,可以不寫用户,如:
fastcgi_store_access group:rw all:r;
·變量
$fastcgi_script_name
這個變量等於一個以斜線結尾的請求URI加上fastcgi_index給定的參數。可以用這個變量代替SCRIPT_FILENAME 和PATH_TRANSLATED,以確定php腳本的名稱。
如下例,請求"/info/":
fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /home/www/scripts/php$fastcgi_script_name;
SCRIPT_FILENAME等於"/home/www/scripts/php/info/index.php"