解釋 CGI、FastCGI、php-fpm 之間的關係

解釋 CGI、FastCGI、php-fpm 之間的關係

前一段時間又重讀了《HTTP權威指南》一書,覺得有一些理論知識還是蠻重要的,需要進行一番整理,讓自己之後對整條web鏈路有個更清晰的認識。

一:Http請求:

當用戶打開瀏覽器並輸入一串url地址時,到最終頁面內容呈現在用戶眼前時,這之間的步驟可大致整理如下:

1)用戶輸入http://www.lxlxw.me。

2)瀏覽器解析出主機名。

3)瀏覽器查詢這個主機名的ip地址如192.168.0.1(即dns解析)並獲得端口號如80

4)瀏覽器發起到192.168.0.1:80的連接。(tcp連接首次握手)

5)瀏覽器向服務器發送一條http get或post報文。(有可能會先發送給proxy或gateway,再由它們轉發給服務器,如nginx做反向代理以實現負載均衡)

6)瀏覽器從服務器讀取http響應報文。

7)瀏覽器關閉連接。

以上便是一條http請求的大致過程,理論上所有的http通信都是由tcp/ip承載的,即http使用tcp連接,其保證了在資源傳輸過程中是可靠的/不會丟失或損壞的。

注:http和https比較,https就是在http層和tcp層之間接入了一個密碼加密層,稱之為TLS或SSL,常用於一些支付等安全性要求較高的網站。

注:關於http的性能優化,tcp連接的時延和瓶頸等,之後可能需要另整理一份。

二:web服務器

web服務器可以用來表示web服務器的軟件,也可以表示提供web頁面的特定設備或機器。這邊主要是指通用軟件web服務器,如apache或nginx。

《http權威指南》中有一份用perl腳本寫的web服務器的源碼,實現了最簡單的收發客戶端報文的功能。

當然,實際的web服務器比這要複雜的多,核心步驟整理如下:

1)接受一個客戶端(瀏覽器)連接,或者拒絕該客戶端的連接並將其關閉。

2)接受請求,從網絡中讀取一條http請求報文並解析。

3)處理請求,對請求報文進行解析。

4)訪問資源,訪問報文中指定的資源,有可能是緩存好的html靜態頁面或圖片資源,也有可能是動態資源,如php文件,此時web server會通過fastcgi請求php應用程序以此產生動態資源,下面會詳細講。

5)創建http響應報文,並回送給客戶端。

6)紀錄事務處理過程,即記log。

三:Fastcgi與php-fpm:

講Fastcgi之前需要先講CGI,CGI是為了保證web server傳遞過來的數據是標準格式的,它是一個協議,方便CGI程序的編寫者。Fastcgi是CGI的更高級的一種方式,是用來提高CGI程序性能的。

web server(如nginx)只是內容的分發者。比如,如果請求/index.html,那麼web server會去文件系統中找到這個文件,發送給瀏覽器,這裡分發的是靜態資源。

如果現在請求的是/index.php,根據配置文件,nginx知道這個不是靜態文件,需要去找PHP解析器來處理,那麼他會把這個請求簡單處理後交給PHP解析器。此時CGI便是規定了要傳什麼數據/以什麼格式傳輸給php解析器的協議。

當web server收到/index.php這個請求後,會啟動對應的CGI程序,這裡就是PHP的解析器。接下來PHP解析器會解析php.ini文件,初始化執行環境,然後處理請求,再以CGI規定的格式返回處理後的結果,退出進程。web server再把結果返回給瀏覽器。

那麼CGI相較於Fastcgi而言其性能瓶頸在哪呢?CGI針對每個http請求都是fork一個新進程來進行處理,處理過程包括解析php.ini文件,初始化執行環境等,然後這個進程會把處理完的數據返回給web服務器,最後web服務器把內容發送給用戶,剛才fork的進程也隨之退出。 如果下次用戶還請求動態資源,那麼web服務器又再次fork一個新進程,週而復始的進行。

而Fastcgi則會先fork一個master,解析配置文件,初始化執行環境,然後再fork多個worker。當請求過來時,master會傳遞給一個worker,然後立即可以接受下一個請求。這樣就避免了重複的勞動,效率自然是高。而且當worker不夠用時,master可以根據配置預先啟動幾個worker等著;當然空閒worker太多時,也會停掉一些,這樣就提高了性能,也節約了資源。這就是Fastcgi的對進程的管理。大多數Fastcgi實現都會維護一個進程池。注:swoole作為httpserver,實際上也是類似這樣的工作方式。

那PHP-FPM又是什麼呢?它是一個實現了Fastcgi協議的程序,用來管理Fastcgi起的進程的,即能夠調度php-cgi進程的程序。現已在PHP內核中就集成了PHP-FPM,使用--enalbe-fpm這個編譯參數即可。另外,修改了php.ini配置文件後,沒辦法平滑重啟,需要重啟php-fpm才可。此時新fork的worker會用新的配置,已經存在的worker繼續處理完手上的活。


分享到:


相關文章: