1. 程式人生 > >Nginx解析PHP的原理 | CGI、FastCGI及php-fpm的關系

Nginx解析PHP的原理 | CGI、FastCGI及php-fpm的關系

時代 負責 處理請求 輕量 工作流程 pct 初始化 register 腳本文件

Nginx解析PHP的原理,CGI/FastCGI以及PHP-Fpm的關系.

一、PHP+Nginx應運而生的場景.
隨著互聯網的發展,用戶對此接受面廣,數據流的增大使得Web端的運行承載壓力日益增大,野蠻生長在大數據時代裏的WEB語言PHP也找到了比老搭檔更優越的活力搭檔Nginx,說到Nginx咱就一起嘮一嘮這其中的奧妙.

從以下幾個維度來剖析一下Nginx的活力所在,當然是和解析PHP的老搭檔APACHE相比而言.

  1. 性能
    1.1 資源占有率少,節省內存資源
    1.2 非阻塞式的請求處理機制給之增加了強勁動力,這也是為什麽能在高迸發折騰下保持金槍不倒之勢. 哈哈~
    1.3 有很多資料千篇一律說性能比Apache提升了3倍,這塊不敢茍同。
  2. 延展性
    2.1 高內聚的模塊化設計,簡介的模塊編寫,使得產品更具魅力和活力
    2.2 有活躍的技術社區和技術群體,便於技術的支持度.
  3. 量級和可用性
    3.1 輕量級
    3.2 解析靜態頁面遠比解析動態頁面性能好.
    3.3 配置更簡潔友好,戒掉了臃腫. 美中不足的是URL重寫還待加強.
    3.4 新興意味著有穩定性的挑戰和GUG的伴隨,當然不必擔憂,有前人鋪路呢.

二、什麽是CGI、什麽是FastCGI,什麽是PHP-Fpm,什麽是PHP-cgi

CGI :是一個可伸縮地、高速地在HTTP server和動態腳本語言間通信的接口
FastCGI : 是CGI的fast版本(哈哈,急速版)多數流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等,這一帶Fast可了不得了:
1.性能提升.他老爹處理請求時遇到動態腳本解析器。
2.升級附帶了支持高迸發性
3.安全上做了升級
說道性能提升了,肯定有性能提升之道,那提升的原理是啥呢?
1.1 接口處理方式采用了 C/S 結構. 在處理機制上就使得HTTP服務和腳本解析器剝離開來,使得部署變得可分離,這樣腳本解析服務器可以分出來多個守護進程,遇到動態腳本則分發給FastCIG,將得到結果反給瀏覽器。HTTP服務器呢則一心一意的幹靜態資源解析方面的活。這就相當於是多線程的概念啦,當然會快呀。
PHP-Fpm : 這個就是咱們上面提到的腳本解析守護進程.
PHP-Cgi : 是PHP自帶的FastCGI管理器。

三、Nginx如何解析PHP
Nginx 是沒法解析動態腳本的,下面看一張原理解析圖片,說白了Nginx解析php是通過fast-cig + php-fpm配合完成的.
用戶通過瀏覽器訪問PHP頁面時候,流程是首先請求到了Nginx服務器,服務器發現是動態請求,Nginx通過Fast-cgi接口來跟動態腳本PHP通信,Fast-cig在Linux下是socket(文件或者Ip類型),通信過程中由FastCGI的wrapper(wrapper可理解為用於啟動另外一個線程的程序)進而啟動一個CIG的解析器.Web server將CGI環境變量和標準輸入發送到FastCGI子進程php-cgi
FastCGI子進程完成處理後將標準輸出和錯誤信息從同一連接返回Web Server再返回給用戶。當FastCGI子進程關閉連接時,請求便告處理完成。FastCGI子進程接著等待並處理來自FastCGI進程管理器(運行在Web Server中)的下一個連接。 在CGI模式中,php-cgi在此便退出了,在php-cgi啟動的過程中,會有守護者或者說管理者(PHP-fpm),防止php-cgi的崩潰.
這樣整流程也算完成了.


PHP源碼分析 - PHP-FPM運行原理

我們知道web服務器與PHP應用之間通過SAPI接口進行交互數據。PHP提供了多種SAPI接口,例如 apache2hander、fastcgi、cli等等。當然,php-fpm也是其中一種。相比其他接口,php-fpm運用更加廣泛。

php-fpm是一種master(主)/worker(子)多進程架構,與nginx設計風格有點類似。master進程主要負責CGI及PHP環境初始化、事件監聽、子進程狀態等等,worker進程負責處理php請求。
在介紹運行原理之前,我們先了解下它的幾種運行模式。

運行模式
php-fpm支持三種運行模式,分別為static、ondemand、dynamic,默認為dynamic 。
static : 靜態模式,啟動時分配固定的worker進程。
ondemand: 按需分配,當收到用戶請求時fork worker進程。
dynamic: 動態模式,啟動時分配固定的進程。伴隨著請求數增加,在設定的浮動範圍調整worker進程。

這三種模式各有千秋,大家可以根據不同的環境調整相應的配置。

下面進入本文主題,著重介紹php-fpm運行原理。

運行原理
php-fpm采用master/worker架構設計,前面簡單地描述master和worker進程模塊的功能。下面將詳細講解這兩個模塊的運行原理。

master進程
master進程工作流程分為4個階段,如下圖:
技術分享圖片

1. cgi初始化階段:分別調用fcgi_init()和 sapi_startup()函數,註冊進程信號以及初始化sapi_globals全局變量。
2. php環境初始化階段:由cgi_sapi_module.startup 觸發。實際調用php_cgi_startup函數,而php_cgi_startup內部又調用php_module_startup執行。 php_module_startup主要功能:a).加載和解析php配置;b).加載php模塊並記入函數符號表(function_table);c).加載zend擴展 ; d).設置禁用函數和類庫配置;e).註冊回收內存方法;
3. php-fpm初始化階段:執行fpm_init()函數。負責解析php-fpm.conf文件配置,獲取進程相關參數(允許進程打開的最大文件數等),初始化進程池及事件模型等操作。
4. php-fpm運行階段:執行fpm_run() 函數,運行後主進程發生阻塞。該階段分為兩部分:fork子進程 和 循環事件。fork子進程部分交由fpm_children_create_initial函數處理( 註:ondemand模式在fpm_pctl_on_socket_accept函數創建)。循環事件部分通過fpm_event_loop函數處理,其內部是一個死循環,負責事件的收集工作。

worker進程
worker進程分為 接收客戶端請求、處理請求、請求結束三個階段。
技術分享圖片


1. 接收客戶端請求:執行fcgi_accept_request函數,其內部通過調用accept 函數獲取客戶端請求。

//請求鎖
FCGI_LOCK(req->listen_socket);
req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
//釋放鎖
FCGI_UNLOCK(req->listen_socket);

從上面的代碼,可以註意到accept之前有一個請求鎖的操作,這麽設計是為了避免請求出現“驚群”的現象。當然,這是一個可選的選項,可以取消該功能。
2. 處理請求階段:首先,分別調用fpm_request_info、php_request_startup獲取請求內容及註冊全局變量($_GET、$_POST、$_SERVER、$_ENV、$_FILES);然後根據請求信息調用php_fopen_primary_script訪問腳本文件;最後交給php_execute_script執行。php_execute_script內部調用zend_execute_scripts方法將腳本交給zend引擎處理。
3. 請求結束階段:執行php_request_shutdown函數。此時 回調register_shutdown_function註冊的函數及__destruct()方法,發送響應內容、釋放內存等操作。

總結
php-fpm采用master/worker架構設計, master進程負責CGI、PHP公共環境的初始化及事件監聽操作。worker進程負責請求的處理功能。在worker進程處理請求時,無需再次初始化PHP運行環境,這也是php-fpm性能優異的原因之一。

Nginx解析PHP的原理 | CGI、FastCGI及php-fpm的關系