聲明:
本文是對網上已有資料的整理,方便共同學習,文中附有相關鏈接供詳細查閱。
今天一起了解一下,Web 服務器與 PHP應用之間是如何工作的。
首先我們先來了解一下幾個概念及其之間的關係:Web服務器(Nginx)、CGI、FastCGI、PHP-CGI、PHP-FPM
Web服務器(Nginx)
Web服務器 通常指網站服務器,是指駐留於因特網上某種類型計算機的程序,主要功能是提供網上信息的瀏覽、下載等服務。
目前最主流的三個Web服務器是Apache、Nginx、 IIS。
Nginx:
Nginx 是一款自由、開源、小巧且高性能的 HTTP服務器 和 反向代碼裏服務器,同時它也是 IMAP / POP3 / SMTP 代理服務器。
Web Server(Nginx)只是內容的分發者。
服務器在收到客戶端發來的請求時
- 如果請求的是靜態頁面或者圖片等無需動態處理的資源時,則Web服務器會根據請求的URL等信息去文件系統中找到並返回給瀏覽器,此時無需PHP參與。
- 如果收到的是動態的頁面請求,這個時候Nginx就需要與PHP通信,就會用到CGI協議,將請求數據轉換成PHP能理解的信息,然後PHP根據這些信息返回進行相應的處理,處理完後,需要返回的信息也要通過CGI協議轉換成Nginx可以理解的信息,最後由Nginx將這些信息返回給客戶端。
CGI
CGI(Common Gateway Interface)全稱是 通用網關接口。CGI 協議同 HTTP 協議一樣是一個「應用層」協議,它的是爲了解決 Web 服務器與後臺語言之間的通信問題。
CGI 的運行原理
- 當用戶訪問我們的 Web 應用時,會發起一個 HTTP 請求。最終 Web 服務器接收到這個請求。
- Web 服務器創建一個新的 CGI 進程。在這個進程中,將 HTTP 請求數據已一定格式解析出來,並通過標準輸入和環境變量傳入到 URL 指定的 CGI 程序(PHP 應用 $_SERVER)。
- Web 應用程序處理完成後將返回數據寫入到標準輸出中,Web 服務器進程則從標準輸出流中讀取到響應,並採用 HTTP 協議返回給用戶響應。
FastCGI
CGI協議每次處理用戶請求,都需要重新fork CGI子進程、銷燬CGI子進程,一系列的 I/O 開銷降低了網絡的吞吐量,造成了資源的浪費,在大併發時會產生嚴重的性能問題。隨着Web的興起,高併發呈常態化,於是就有了FastCGI,即FastCGI是基於CGI協議的基礎上做了改進,它是一種常駐型的CGI協議,它採用進程間通信(IPC)來處理用戶的請求。
FastCGI 協議運行原理
- FastCGI 進程管理器啓動時會創建一個 主(Master) 進程和多個 CGI 解釋器進程(Worker 進程),然後等待 Web 服務器的連接。
- Web 服務器接收 HTTP 請求後,將 CGI 報文通過 套接字(UNIX 或 TCP Socket)進行通信,將環境變量和請求數據寫入標準輸入,轉發到 CGI 解釋器進程。
- CGI 解釋器進程完成處理後將標準輸出和錯誤信息從同一連接返回給 Web 服務器。
- CGI 解釋器進程等待下一個 HTTP 請求的到來。
PHP-FPM
要了解PHP-FPM,就得先說說PHP-CGI。
PHP-CGI就是PHP實現的自帶的FastCGI管理器。 雖然是php官方出品,但是這丫的卻一點也不給力,性能太差,而且也很麻煩不人性化,主要體現在:
- php-cgi變更php.ini配置後,需重啓php-cgi才能讓新的php-ini生效,不可以平滑重啓。
- 直接殺死php-cgi進程,php就不能運行了
於是就有人專門爲PHP搞出了PHP專用的FastCGI管理器,即PHP-FPM。
PHP-FPM 是對於 FastCGI 協議的具體實現,他負責管理一個進程池,來處理來自Web服務器的請求。
因爲PHP-CGI只是個CGI程序,他自己本身只能解析請求,返回結果,不會進程管理。所以就出現了一些能夠調度 php-cgi 進程的程序,比如說由lighthttpd分離出來的spawn-fcgi。同樣,PHP-FPM也是用於調度管理PHP解析器php-cgi的管理程序。
PHP-FPM通過生成新的子進程可以實現php.ini修改後的平滑重啓。
總結
一句話總結:
CGI 和 FastCGI 是一種協議和 HTTP 協議一樣位於應用層,與語言無關;PHP-FPM 是一種 FastCGI 協議的實現,能夠管理 FastCGI 進程
兩張圖總結:
PHP-FPM 是如何工作的
PHP-FPM 進程管理器有兩種進程組成,一個 Master 進程和多個 Worker 進程。Master 進程負責監聽端口,接收來自 Web 服務器的請求,然後指派具體的 Worker 進程處理請求;worker 進程則一般有多個 (依據配置決定進程數),每個進程內部都嵌入了一個 PHP 解釋器,用來執行 PHP 代碼。
從 FPM 接收到請求,到處理完畢,其具體的流程如下:
- FPM 的 master 進程接收到請求
- master 進程根據配置指派特定的 worker 進程進行請求處理,如果沒有可用進程,返回錯誤,這也是我們配合 Nginx 遇到502錯誤比較多的原因。
- worker 進程處理請求,如果超時,返回504錯誤
- 請求處理結束,返回結果
Nginx發送請求給FPM
我們知道,Nginx 不僅僅是一個 Web 服務器,也是一個功能強大的 Proxy 服務器,除了進行 http 請求的代理,也可以進行許多其他協議請求的代理,包括本文與 fpm 相關的 fastcgi 協議。爲了能夠使 Nginx 理解 fastcgi 協議,Nginx 提供了 fastcgi 模塊來將 http 請求映射爲對應的 fastcgi 請求。
Nginx 的 fastcgi 模塊提供了 fastcgi_param 指令來主要處理這些映射關係。
除此之外,非常重要的就是 fastcgi_pass 指令了,這個指令用於指定 fpm 進程監聽的地址,Nginx 會把所有的 php 請求翻譯成 fastcgi 請求之後再發送到這個地址,下面一個簡單的可以工作的 Nginx 配置文件:
在這個配置文件中,我們新建了一個虛擬主機,監聽在 80 端口,Web 根目錄爲 /home/rf/projects/wordpress。然後我們通過 location 指令,將所有的以 .php 結尾的請求都交給 fastcgi 模塊處理,從而把所有的 php 請求都交給了 fpm 處理,從而完成 Nginx 到 fpm 的閉環。
再附兩張圖: