之前項目中碰到了一些php-fpm的問題:因為網站的一些介面,在特定情況下響應特別慢(1-2分鐘),遲遲不結束,導致php-fpm數量越來越多,最後到達127個後,伺服器就沒能響應正常請求了,瀏覽器一直打轉,遲遲不響應。把介面修好後,php-fpm進程的數量就穩定了,問題得以解決。這讓我對php-fpm這個進程產生了興趣。
在百度和google了不少文章後,我總結了一下關於CGI,fastCGI,PHP-FPM,php-cgi的概念,還有nginx解析PHP的過程,如下:(博主知識水平有限,如果有不對的地方,歡迎大家指正)
1、什麼是CGI
CGI是Common Gateway Interface(公用網關介面)的縮寫,它有什麼用呢。我們知道瀏覽器訪問一個含有動態資料的頁面,瀏覽器使用HTTP協議發送請求。資料包經過路由器和交換器,到達目標web伺服器,web伺服器收到這個請求,需要和PHP通訊,才能拿到含有動態資料的頁面。為什麼要通訊。因為他們語言不通(nginx等web伺服器和php語言和文法不一樣,沒法直接溝通)
那麼,要怎麼通訊呢。最早是用CGI協議來通訊。通過CGI協議,nginx能夠將HTTP請求轉化為PHP可以理解的語言(uri,post資料和get的資料,HTTP header等資料)。CGI規定了要傳哪些資料、以什麼樣的格式傳遞給後方處理。
1、傳統的使用CGI協議的工作方式
web伺服器本身只是內容的分發者,比如請求/index.html,web伺服器就會去尋找這個檔案,然後返回給瀏覽器,這裡指的只是靜態檔案。如果是請求/index.php會怎麼樣。web伺服器知道這不是個靜態資源,需要解析後再返回給瀏覽器,於是web伺服器就啟動一個php解譯器進程,這個解譯器實現了CGI協議,能夠完成和後端語言PHP的溝通,PHP把該返回的動態資料還給web伺服器,然後web伺服器再發給瀏覽器。
2、傳統的CGI協議的弊端
為什麼傳統的CGI工作方式會有弊端。因為每請求一個PHP指令碼,web伺服器就得為一個請求開啟一個PHP解譯器(早期是php-cgi)進程來完成解析。這意味著:每來一個請求,解譯器就得初始化php.ini並載入php擴充,等環境初始化完了,再解析,解析完成後進程自動結束(即fork-and-execute模式)。
所以用cgi方式的伺服器有多少串連請求就會有多少cgi子進程,子進程反覆載入是cgi效能低下的主要原因。都會當使用者請求數量非常多時,會大量擠占系統的資源如內 存,CPU時間等,造成效能低下。
2、什麼是fastCGI
fastCGI,通俗的翻譯為快速的CGI。FastCGI,顧名思義為更快的 CGI,它允許在一個進程內處理多個請求,而不是一個請求處理完畢就直接結束進程,web伺服器效能上有了很大的提高。
1、關於php-fpm
php-fpm,即專門為php打造的fastCGI process manager(PHP的fastCGI管理器)。nginx使用這些php-fpm進程來和PHP進行通訊,你可以理解把php-fpm理解為php解譯器。
和傳統的php-cgi的解譯器不同,php-fpm實現了fastCGI協議,而且還新增了不少特性。比如php-fpm能夠平滑重啟php環境配置:我們知道在修改了php.ini之後,wamp和phpstudy需要重啟伺服器才能重新載入php.ini裡的內容。如果是php-fpm,則不用重啟web伺服器,原先正在工作的php-fpm繼續工作,等原先工作的php-fpm完成自己的工作後,就結束掉自己。新增加的php-fpm就使用修改後的php.ini即可。
2、實現了fastCGI的工作方式
實現了fastCGI協議的nginx,第一次啟動時,會啟動一個php-fpm的master進程,該master進程初始化環境後,啟動多個worker進程(即php-fpm進程池中的php-fpm),如下圖:
當請求發來後,master進程把請求分發到進程池中的php-fpm,分發完後,就可以接下一個請求了,避免了重複勞動(重複載入php.ini初始化環境),效率自然提升了。當請求多的時候,master會啟動更多的php-fpm子進程,當請求少的時候,master也會停掉一些子進程。既提高了效能,也節省資源。 當然,當php-fpm設定的上限,不足以支援更高的並發請求時,nginx只能返回502錯誤了,因為沒有更多的php-fpm進程可用了。 在這種協議下,php-fpm成為了和PHP溝通的PHP解譯器。
3、nginx是如何和php-fpm進程交流的 到目前為止,我們知道了實現了fastCGI的php-fpm是如何工作的,但是nginx是怎麼啟動php-fpm進程的呢。 Nginx 不僅僅是一個 Web 服務器,也是一個功能強大的 Proxy 伺服器,除了進行 http 請求的代理,也可以進行許多其他協議請求的代理,包括本文與 fpm 相關的 fastcgi 協議。為了能夠使 Nginx 理解 fastcgi 協議,Nginx 提供了 fastcgi 模組來將 http 請求映射為對應的 fastcgi 請求。
下面是一個nginx的設定檔,用來把nginx中的變數,解釋為PHP能夠理解的變數:
下面是nginx把php請求交給fastCGI模組來處理的配置(在nginx.conf中可以查到此項配置)
在這個設定檔中,我們建立了一個虛擬機器主機,監聽在 80 連接埠,Web 根目錄為 /home/rf/projects/wordpress。通過location配置,我們把所有.php檔案的處理,交給了fastCGI模組。之後就是fastCGI模組啟動php-fpm(實現fastCGI模組),並通過php-fpm來解釋動態請求。
下面是我總結的一個流程圖,如果有不正確的地方,歡迎指正。