PHP-FPM+Nginx通訊原理

  • 2019 年 11 月 23 日
  • 筆記

引言

用了這麼久了PHP+Nginx了,你了解他們之間的通訊原理嗎?這一次做一回真正的PHPer(在上一篇文章裡邊已經全面介紹了CGI、FastCGI、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訪問國外的網站,其實就是個正向代理的過程,上圖:

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

反向代理

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

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

PHP-FPM+Nginx通訊

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

通過圖來方便我們理解PHP-FPM和Nginx的通訊

1、當Nginx收到http請求(動態請求),它會初始化FastCGI環境。(如果是Apache伺服器,則初始化mode_fastcgi模組、如果是Nginx伺服器則初始化ngx_http_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的通訊

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

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

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

4、關於fastcgi的配置文件,fastcgi的配置文件一般放在nginx.conf同級目錄下,配置文件形式,一般有兩種:

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

我們可以打開fastcgi_params文件加上上述行,也可以在要使用配置的地方動態添加。使得該配置生效。

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

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

server{  listen 8080;  index index.php  root /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;}

1、第一個大括弧 server{ }:代表一個獨立的server

2、listen 8080:代表該server監聽8080埠

3、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等

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

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

6、fastcgi_param SCRIPT_FILENAME

fastcgi_script_name; :這行配置意思是:動態添加了一行fastcgi配置,配置內容為SCRIPT_FILENAME,告知管理進程,cgi腳本名稱。由於我的nginx中只有fastcgi_params文件,沒有fastcgi.conf文件,所以要使php-fpm知道SCRIPT_FILENAME的具體值,就必須要動態的添加這行配置。

7、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和fastcgi_params中,這兩個的區別,上邊有說明。看一下裡邊的內容:

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

php-fpm.conf配置

熟悉php-fpm的配置,能幫助我們優化伺服器性能

emergency_restart_threshold = 60emergency_restart_interval = 60s

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

rocess_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) / 2  pm.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看一下,下邊是我的:

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

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

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

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

參考:

https://www.php.cn/php-weizijiaocheng-393152.html

https://www.cnblogs.com/skynet/p/4173450.html

https://blog.csdn.net/afring/article/details/93880216

https://www.cnblogs.com/ahaii/p/5776809.html

文章轉載自:IT猿圈(公眾號)