FastCGI的工作原理
1、Web Server啟動(dòng)時(shí)載入FastCGI進(jìn)程管理器(IIS ISAPI或Apache Module)
2、FastCGI進(jìn)程管理器自身初始化,啟動(dòng)多個(gè)CGI解釋器進(jìn)程(可見(jiàn)多個(gè)php-cgi)并等待來(lái)自Web Server的連接。
3、當(dāng)客戶(hù)端請(qǐng)求到達(dá)Web Server時(shí),F(xiàn)astCGI進(jìn)程管理器選擇并連接到一個(gè)CGI解釋器。Web server將CGI環(huán)境變量和標(biāo)準(zhǔn)輸入發(fā)送到FastCGI子進(jìn)程php-cgi。
4、FastCGI子進(jìn)程完成處理后將標(biāo)準(zhǔn)輸出和錯(cuò)誤信息從同一連接返回Web Server。當(dāng)FastCGI子進(jìn)程關(guān)閉連接時(shí),請(qǐng)求便告處理完成。FastCGI子進(jìn)程接著等待并處理來(lái)自FastCGI進(jìn)程管理器(運(yùn)行在Web Server中)的下一個(gè)連接。 在CGI模式中,php-cgi在此便退出了。
在上述情況中,你可以想象CGI通常有多慢。每一個(gè)Web請(qǐng)求PHP都必須重新解析php.ini、重新載入全部擴(kuò)展并重初始化全部數(shù)據(jù)結(jié)構(gòu)。使用FastCGI,所有這些都只在進(jìn)程啟動(dòng)時(shí)發(fā)生一次。一個(gè)額外的好處是,持續(xù)數(shù)據(jù)庫(kù)連接(Persistent database connection)可以工作。
這個(gè)很容易找到。也容易理解,但是繼續(xù)google之后,發(fā)現(xiàn)自己的概念又模糊了。
比如有些例子用
spawn-fcgi
/usr/local/bin/spawn-fcgi -a 127.0.0.1 -p 9000 -C 5 -u root -g root -f /usr/bin/php-cgi
參數(shù)含義如下
- -f <fcgiapp> 指定調(diào)用FastCGI的進(jìn)程的執(zhí)行程序位置,根據(jù)系統(tǒng)上所裝的PHP的情況具體設(shè)置
- -a <addr> 綁定到地址addr
- -p <port> 綁定到端口port
- -s <path> 綁定到unix socket的路徑path
- -C <childs> 指定產(chǎn)生的FastCGI的進(jìn)程數(shù),默認(rèn)為5(僅用于PHP)
- -P <path> 指定產(chǎn)生的進(jìn)程的PID文件路徑
- -u和-g FastCGI使用什么身份(-u 用戶(hù) -g 用戶(hù)組)運(yùn)行,Ubuntu下可以使用www-data,其他的根據(jù)情況配置,如nobody、apache等
剛看到FastCGI原理的時(shí)候,我想象中的運(yùn)行模型是,前端的反向代理服務(wù)器如Nginx收到請(qǐng)求,然后轉(zhuǎn)發(fā)給cgi進(jìn)程,這個(gè)cgi進(jìn)程有N個(gè),從而實(shí)現(xiàn)并發(fā)處理。但是接下來(lái)搜索到的C語(yǔ)言實(shí)現(xiàn)的FastCGI應(yīng)用的例子好像又把這個(gè)模型給否定了。并且fastcgi是語(yǔ)言無(wú)關(guān)的,難道你要用python寫(xiě)并發(fā)?
#include "fcgi_stdio.h"
#include <stdlib.h>
int count;
void initialize(void)
{
count=0;
}
void main(void)
{
initialize();
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"));
}
}
這個(gè)代碼看不出來(lái)有任何并發(fā)處理的部分。比如fork什么的。
另外一種模型就是有一種叫做FastCGI進(jìn)程管理器的進(jìn)程,就像上面說(shuō)的是管理fastcgi進(jìn)程的進(jìn)程,請(qǐng)求轉(zhuǎn)發(fā)到管理器的時(shí)候,由它來(lái)進(jìn)行選擇相應(yīng)的應(yīng)用進(jìn)程,卡就卡在這了,這個(gè)管理器是怎么來(lái)選擇進(jìn)程的啊,假如我有N個(gè)不同邏輯的可執(zhí)行文件,它怎么知道要轉(zhuǎn)發(fā)給哪個(gè)進(jìn)程呢,google到的fastcgi配置都是針對(duì)反向代理的后端也即管理器設(shè)置的,沒(méi)有發(fā)現(xiàn)有針對(duì)不同邏輯發(fā)給不同的應(yīng)用進(jìn)程的部分。
繼續(xù)狂搜,還是無(wú)果,都是類(lèi)似的文章。網(wǎng)上搜索不到的問(wèn)題,要么就是很難很偏,要么就是很簡(jiǎn)單,簡(jiǎn)單到不值一提,很顯然,我屬于后者。轉(zhuǎn)換思路,開(kāi)始考慮假如要自己來(lái)實(shí)現(xiàn)這個(gè)功能的話(huà)該怎么辦。一步步地推理,在結(jié)合搜索到的文章,大概理清了思路,我的理解如下,不對(duì)的地方請(qǐng)指正。
1.有一個(gè)CGI進(jìn)程管理器,這個(gè)管理器一般是用第3方的fastcgi開(kāi)發(fā)套件,比如上面提到的spawn-fcgi ,用它可以啟動(dòng)指定可執(zhí)行文件的N個(gè)實(shí)例,關(guān)于之前選擇進(jìn)程的疑問(wèn),這里可以得到解釋?zhuān)蔷褪嵌鄠€(gè)進(jìn)程只是同一個(gè)可執(zhí)行文件的實(shí)例,假如你想把不同的模塊分開(kāi)生成可執(zhí)行文件的話(huà)估計(jì)就得再啟動(dòng)多一個(gè)管理器了吧。
2.假如你是用python寫(xiě)的fastcgi的應(yīng)用程序,那么當(dāng)你用管理器啟動(dòng)了100個(gè)實(shí)例的時(shí)候,也就相當(dāng)于啟動(dòng)了100個(gè)python解析器,如果是用C等靜態(tài)語(yǔ)言寫(xiě)的話(huà)那還好,只是跟你寫(xiě)的程序大小有關(guān)。
可能是沒(méi)有接觸過(guò)CGI程序的原因,讓我對(duì)這基本的模型都糾結(jié)了一下午,希望這篇文章能幫些初學(xué)者。