Nginx解析PHP腳本的過程

之前項目中碰到了一些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來解釋動態請求。

下面是我總結的一個流程圖,如果有不正確的地方,歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章