PHP-FPM詳解

PHP-FPM

PHP-FPM的全稱是PHP FastCGI Process Manager,PHP-FPM是FastCGI的實現,並提供了程序管理的功能。FastCGI程序包含master程序和worker程序兩種程序。master程序只有一個,負責監聽埠,接收Nginx的請求,而worker程序則一般有多個(可配置),每個程序內部都嵌入了一個PHP直譯器,是PHP程式碼真正執行的地方。

Nginx

Nginx (“engine x”) 是一個高效能的HTTP和反向代理伺服器,也是一個IMAP/POP3/SMTP伺服器。這裡介紹一下什麼是正向代理和反向代理,這個對於我們理解Nginx很重要。

正向代理

我們那訪問國外的網站為例,比如訪問Google、Facebook。我們需要藉助vpn才能訪問,我們藉助vpn訪問國外的網站,其實就是個正向代理的過程,

PHP-FPM詳解

vpn對於使用者來說,是可以感知到的(因為使用者需要配置連線),vpn對於google伺服器來說,是不可感知的(google伺服器只知道有http請求過來)。所以,對於使用者來說可以感知到,而對於伺服器來說感知不到的伺服器,就是正向代理伺服器(vpn)

反向代理

拿Nginx作為反向代理伺服器實現負載均衡來舉例,假設此時我們訪問百度,看圖:

PHP-FPM詳解

當用戶訪問百度時,所有的請求會到達一個反向代理伺服器,這個反向代理伺服器會將請求分發給後邊的某一臺伺服器去處理。此時,這個代理伺服器其實對使用者來說是不可感知的,使用者感知到的是百度的伺服器給自己返回了結果,並不知道代理伺服器的存在。也就是說,對於使用者來說不可感知,對於伺服器來說是可以感知的,就叫反向代理伺服器(Nginx)

PHP-FPM+Nginx通訊

FastCGI致力於減少Web伺服器與CGI程式之間互動的開銷,從而使伺服器可以同時處理更多的Web請求。與CGI這種為每個請求建立一個新的程序不同,FastCGI使用持續的程序來處理一連串的請求。這些程序由FastCGI程序管理器管理,而不是web伺服器。

透過圖來理解PHP-FPM和Nginx的通訊

PHP-FPM詳解

(1)當Nginx收到http請求(動態請求),它會初始化FastCGI環境。(如果是Apache伺服器,則初始化modefastcgi模組、如果是Nginx伺服器則初始化ngxhttp_fastcgi_module)

(2)我們在配置nginx解析php請求時,一般會有這樣一行配置:

fastcgi_pass 127。0。0。1:9000;

或者長這樣:

fastcgi_pass unix:/tmp/php-cgi。sock;

它其實是Nginx和PHP-FPM一個通訊載體(或者說通訊方式),目的是為了讓Nginx知道,收到動態請求之後該往哪兒發。(關於這兩種配置的區別,後邊會專門介紹)

(3)Nginx將請求採用socket的方式轉給FastCGI主程序

(4)FastCGI主程序選擇一個空閒的worker程序連線,然後Nginx將CGI環境變數和標準輸入傳送該worker程序(php-cgi)

(5)worker程序完成處理後將標準輸出和錯誤資訊從同一socket連線返回給Nginx

(6)worker程序關閉連線,等待下一個連線

不從配置的角度,再描述一下PHP和Nginx的通訊

我們知道Nginx也是有master和worker程序的,worker程序直接處理每一個網路請求

其實在Nginx+PHP的架構裡邊,php可以看做是一個cgi程式的角色,因此出現了php-fpm程序管理器來處理這些php請求。php-fpm和nginx一樣,也會監聽埠(透過nginx。conf裡的配置我們知道,nginx預設監聽8080埠,php-fpm預設監聽9000埠),並且有master和worker程序,worker負責處理每一個php請求

關於fastcgi:fastcgi是一個協議。市面上有多種實現了fastcgi協議的程序管理器,php-fpm就是其中的一種。php-fpm作為一種fastcgi程序管理服務,會監聽埠,一般預設監聽9000埠,並且是監聽本機,也就是隻接收來自本機的埠請求

關於fastcgi的配置檔案,目前fastcgi的配置檔案一般放在nginx。conf同級目錄下,配置檔案形式,一般有兩種:

fastcgi。conf和 fastcgi_params。不同的nginx版本會有不同的配置檔案,這兩個配置檔案有一個非常重要的區別:fastcgi_parames檔案中缺少下列配置:fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

我們可以開啟fastcgi_params檔案加上上述行,也可以在要使用配置的地方動態新增。使得該配置生效

當需要處理php請求時,nginx的worker程序會將請求移交給php-fpm的worker程序進行處理,也就是最開頭所說的nginx呼叫了php,其實嚴格得講是nginx間接呼叫php(反向代理的方式)

我本機配置了能正常解析php程式的nginx配置,介紹一下每一行配置的含義

server{listen 8080;index index。phproot /work/html/;location ~ [^/]\。php(/|$){root /work/html/;fastcgi_pass 127。0。0。1:9000;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;include fastcgi_params;}access_log /work/html/logs/test。log;}

第一個大括號 server{ }:代表一個獨立的server

listen 8080:代表該server監聽8080埠

location ~ [^/]\。php(/|$){ }:代表一個能匹配對應uri的location,用於匹配一類uri,並對所匹配的uri請求做自定義的邏輯、配置。這裡的location,匹配了所有帶。php的uri請求,例如:http://192。168。244。128:8011/test。php/asdasd http://192。168。244。128:8011/index。php等

root /work/html/:請求資源根目錄,告訴匹配到該location下的uri到/work/html/資料夾下去尋找同名資源

fastcgi_pass 127。0。0。1:9000:這行程式碼的意思是,將進入到該location內的uri請求看做是cgi程式,並將請求傳送到9000埠,交由php-fpm處理(php-fpm配置中會看見它監聽了此埠)

fastcgiparam SCRIPTFILENAME

fastcgiscriptname; :這行配置意思是:動態添加了一行fastcgi配置,配置內容為SCRIPTFILENAME,告知管理程序,cgi指令碼名稱。由於我的nginx中只有fastcgiparams檔案,沒有fastcgi。conf檔案,所以要使php-fpm知道SCRIPT_FILENAME的具體值,就必須要動態的新增這行配置

include fastcgi_params; 引入fastcgi配置檔案

fastcgi_pass

Nginx和PHP-FPM的程序間通訊有兩種方式,一種是TCP Socket,一種是Unix Socket。

Tcp Socket方式是IP加埠,可以跨伺服器。而UNIX Socket不經過網路,只能用於Nginx跟PHP-FPM都在同一伺服器的場景,用哪種取決於你的PHP-FPM配置

Tcp Socket方式:

nginx。conf中配置:fastcgi_pass 127。0。0。1:9000;

php-fpm。conf中配置:listen=127。0。0。1:9000;

Unix Domain Socket方式:

nginx。conf中配置:fastcgi_pass unix:/tmp/php-fpm。sock;

php-fpm中配置:listen = /tmp/php-fpm。sock;

(php-fpm。sock是一個檔案,由php-fpm生成)

舉例:

兩種通訊配置方式,Nginx和PHP-FPM的通訊過程如下:

Tcp Socket:

Nginx <=> socket <=> TCP/IP <=> socket <=> PHP-FPM

(上邊畫Nginx和PHP-FPM通訊的圖時就是這種方式,這種情況是Nginx和PHP-FPM在同一臺機器上)

看一下Nginx和PHP-FPM不在同一臺機器上的情況:

Nginx <=> socket <=> TCP/IP <=> 物理層 <=> 路由器 <=> 物理層 <=> TCP/IP <=> socket <=> PHP-FPM

Unix Socket:

Nginx <=> socket <=> PHP-FPM

include fastcgi_params;

在nginx中有很多的fasgcgi*的配置,更多的配置可以在nginx。conf的同級目錄中看到,在fastcgi。conf和fastcgiparams中,這兩個的區別,上邊有說明。看一下里邊的內容:

PHP-FPM詳解

這裡邊的內容都會被傳遞給PHP-FPM所管理的fastcgi程序。為什麼會傳遞這些呢?相信大家都用過$SERVER這個全域性變數,這裡邊的值就是從此配置中拿到的。我們可以在fastcgiparams中看到REMOTEADDR,就是客戶端地址,PHP之所以能拿到客戶端資訊,就是因為Nginx的配置中的fastcgiparams。更多ngxhttpfastcgimodule模組的內容,可以看官方文件:http://nginx。org/en/docs/http/ngxhttp_fastcgi_module。html

php-fpm.conf配置

熟悉php-fpm的配置,能幫助我們最佳化伺服器效能

emergency_restart_threshold = 60emergency_restart_interval = 60s

表示在emergencyrestartinterval所設值內出現SIGSEGV或者SIGBUS錯誤的php-cgi程序數如果超過 emergencyrestartthreshold個,php-fpm就會優雅重啟。這兩個選項一般保持預設值

process_control_timeout = 0

設定子程序接受主程序複用訊號的超時時間。 可用單位: s(秒), m(分), h(小時), 或者 d(天) 預設單位: s(秒)。 預設值: 0。

listen = 127。0。0。1:9000

fpm監聽埠,即nginx中php處理的地址,一般預設值即可。可用格式為: ‘ip:port’, ‘port’, ‘/path/to/unix/socket’。 每個程序池都需要設定。

request_slowlog_timeout = 10s#當一個請求該設定的超時時間後,就會將對應的PHP呼叫堆疊資訊完整寫入到慢日誌中。 設定為 ’0′ 表示 ‘Off’slowlog = log/$pool。log。slow慢請求的記錄日誌,配合request_slowlog_timeout使用

下邊幾個配置引數比較重要:

pmpm指的是process manager,指定程序管理器如何控制子程序的數量,它為必填項,支援3個值(1)static: 使用固定的子程序數量,由pm。max_children指定(可以同時存活的子程序的最大數量)(2)dynamic:基於下面的引數動態的調整子程序的數量,至少有一個子程序(會使用下邊幾個配置)pm。start_servers: 啟動時建立的子程序數量,預設值為min_spare_servers + max_spare_servers - min_spare_servers) / 2pm。min_spare_servers: 空閒狀態的子程序的最小數量,如果不足,新的子程序會被自動建立pm。max_spare_servers: 空閒狀態的子程序的最大數量,如果超過,一些子程序會被殺死(3)ondemand: 啟動時不會建立子程序,當新的請求到達時才建立,有下邊兩個配置pm。max_childrenpm。process_idle_timeout 子程序的空閒超時時間,如果超時時間到沒有新的請求可以服務,則會被殺死區別:如果pm設定為 static,那麼其實只有pm。max_children這個引數生效。系統會開啟設定數量的php-fpm程序如果pm設定為 dynamic,那麼pm。max_children引數失效,後面3個引數生效系統會在php-fpm執行開始 的時候啟動pm。start_servers個php-fpm程序,然後根據系統的需求動態在pm。min_spare_servers和pm。max_spare_servers之間調整php-fpm程序數還有一個比較重要的配置:pm。max_requests每一個子程序的最大請求服務數量,如果超過了這個值,該子程序會被自動重啟。在解決第三方庫的記憶體洩漏問題時,這個引數會很有用。預設值為0,指子程序可以持續不斷的服務請求

PHP-FPM程序池

php-fpm。conf中預設配置了一個程序池,我們可以開啟我們的php-fpm。conf看一下,下邊是我的:

PHP-FPM詳解

現在我們執行一下:ps -aux|grep php-fpm

PHP-FPM詳解

會看見有一個master,10個worker程序,和我們配置的一樣(www為程序池名)

想配置多個,這樣做即可:

PHP-FPM詳解

在nginx中fastcgi_pass這個地方配置使用哪個程序池即可