最近有幸讀到一篇文章,一文將CGI 的進化史講的特別詳細,雖然我自己之前也整理過 CGI、FastCGI、PHP-FPM 相關的筆記,但是並沒有從原理的角度來認識 CGI。
CGI 的誕生
早些年的Web 應用很簡單,客户端通過瀏覽器發起請求,服務端直接返回響應。
隨着互聯網的發展,簡單的Web 應用已經不能滿足開發者們了。
我們希望Web服務器有更多的功能,飛速發展的同時還能讓不同語言的開發者也能加入。
CGI協議協議的誕生就是 Web服務器和其他領域的開發者在保證遵守協議的基礎上,剩下的可以自由發揮,而實現這個協議的腳本叫做CGI 程序。
CGI協議規定了需要向CGI腳本設置的環境變量和一些其他信息,CGI程序完成某一個功能,可以用PHP,Python,Shell或者C語言編寫。
在沒有CGI 之前,其他語言如果需要接入Mysql 或者Memcache,還需要使用C 語言,但有了CGI協議,我們的Web處理流程可以變成下圖這樣:
FastCGI 的誕生
CGI程序存在致命的缺點:每當客户端發起請求,服務器將請求轉發給CGI,WEB 服務器就請求操作系統生成一個新的CGI解釋器進程(如php-cgi),CGI進程則處理完一個請求後退出,下一個請求來時再創建新進程。
我們知道,執行一個PHP程序的必須要先解析php.ini文件,然後模塊初始化等等一系列工作,每次都反覆這樣非常浪費資源。
FastCGI協議在CGI協議的基礎上,做出瞭如下改變:
- FastCGI被設計用來支持常駐(
long-lived)應用進程,減少了fork-and-execute帶來的開銷 - FastCGI進程通過監聽的socket,收來自Web服務器的連接,這樣FastCGI 進程可以獨立部署
- 服務器和FastCGI監聽的socket 之間按照消息的形式發送環境變量和其他數據
我們稱實現了FastCGI協議的程序為FastCGI程序,FastCGI程序的交互方式如下圖所示:
PHP-FPM 的誕生
FastCGI 程序固然已經很好了,但我們的需求總是有點苛刻,它還是存在一些明顯缺點的:
- 當我們更改配置文件(
php.ini)後,php-cgi(FastCGI 程序) 無法平滑重啓 - 我們fork的進程個數和請求量正比,請求繁忙時 fork 進程多,動態調整
php-cgi還沒做到
上面提及php-cgi 實現的FastCGI問題官方沒有解決,幸運的是有第三方幫我們解決了,它就是 php-fpm。
它可以獨立運行,不依賴php-cgi,換句話説,它自己實現了FastCGI協議並且支持進程平滑重啓且帶進程管理功能。
進程包含 master 進程和 worker 進程兩類進程。
master 進程只有一個,負責監聽端口,接收來自Web Server 的請求,而 worker 進程則一般有多個(具體數量根據實際需要配置),每個進程內部都嵌入了一個PHP 解釋器,是PHP 代碼正真執行的地方。
參考鏈接
- 從CGI到FastCGI到PHP-FPM