nginx 和 PHP-fpm 的互動

bytecc發表於2020-03-11

nginx是一個webservice的功能,當檢測到訪問php檔案時,會把請求交給fastcgi模組處理。我們可以在nginx的配置檔案中配置fastcgi的相關引數

nginx和php-fpm的互動
nginx的fastcgi模組會把請求交給php-fpm程式處理。php-fpm的worker程式處理完後,會把資料返回給nginx,nginx會把資料放到記憶體快取中,快取區大小為fastcgi_buffer_size,fastcgi_buffers控制。如果返回資料大於快取,則多出來的資料會被臨時寫入到檔案中,放在fastcgi_temp目錄下面。

PHP-FPM

php-fpm是一種master(主)/worker(子)多程式架構
master的工作分為四步:
1.cgi初始化階段:分別呼叫fcgi_init()和 sapi_startup()函式,註冊程式訊號以及初始化sapi_globals全域性變數。

2.php環境初始化階段: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程式分三步:
1.接收客戶端請求:執行fcgi_accept_request函式,其內部透過呼叫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的三種模式

php-fpm.conf配置pm
pm=static

nginx 和 PHP-fpm 的互動

始終保持固定數量的worker程式數,由pm.max_children決定。
pm=dynamic
php-fpm啟動時,會初始啟動一些worker,初始啟動worker數決定於pm.max_children的值。在執行過程中動態調整worker數量,worker的數量受限於pm.max_children配置,同時受限全域性配置process.max。
pm=ondemand
php-fpm啟動的時候,不會啟動任何一個worker,而是按需啟動,只有當連線過來的時候才會啟動。
啟動的最大worker數決定於pm.max_children的值,同時受限全域性配置process.max。
1秒定時器作用,如果空閒worker時間超過pm.process_idle_timeout的值(預設值為10s),則關閉該worker。這個機制可能會關閉所有的worker。

worker數量不足
當master監聽到連線事件時,發現worker程式數量不夠,會把連線放入到一個等待佇列中,一直等待到有新的worker程式建立出來,就從等待等待佇列中獲取一個連線,然後accept請求處理。當連線太多而worker數量太少時,等待的時間太長,超過了nginxf的fastcgi連線時間限制,就會返回504超時。

常見錯誤碼

php-fpm的work程式超時情況:
php-fpm:
request_terminate_timeout = 0
php.ini:
max_execution_time = 30 //這個引數記錄的是php執行時間比較,不包括資料互動,網路連線的時間,所以如果不設定request_terminate_timeout的話,會導致worker永不超時,佔用php-fpm的worker.直到超過fastcgi_connect_timeout的設定,返回504.

request_terminate_timeout 適用於,當max_execution_time由於某種原因無法終止指令碼的時候(連線資料庫,sleep等),會把這個php-fpm請求幹掉。所以最好是在php-fpm.conf加上這個設定。

502:PHP-FPM沒有開啟或者php-fpm執行時手動kill掉對應的worker程式, php-fpm沒有正常返回資料給nginx,報502 bad gateway.

500:當max_execution_time或者request_terminate_timeout生效的時候,php-fpm主動kill這個worker程式,php有Fatal error超時日誌,http狀態碼為500。php無Fatal error超時日誌,http狀態碼為502,php-fpm日誌中有殺掉子程式日誌

504:nginx的Fastcgi的引數fastcgi_connect_timeout 超時,就是說php-fpm的執行時間超過了nginx的fastcgi連線時間限制。

nginx與php-fpm的通訊方式

Nginx和PHP-FPM的程式間通訊有兩種方式,一種是TCP,一種是UNIX Domain Socket.

tcp

允許透過網路程式之間的通訊,也可以透過loopback進行本地程式之間通訊。

UNIX Domain Socket

允許在本地執行的程式之間進行通訊。
其中TCP是IP加埠,可以跨伺服器.而UNIX Domain Socket不經過網路,只能用於Nginx跟PHP-FPM都在同一伺服器的場景.用哪種取決於你的PHP-FPM配置:

方式1:
php-fpm.conf: listen = 127.0.0.1:9000
nginx.conf: fastcgi_pass 127.0.0.1:9000;
方式2:
php-fpm.conf: listen = /tmp/php-fpm.sock
nginx.conf: fastcgi_pass unix:/tmp/php-fpm.sock;
本作品採用《CC 協議》,轉載必須註明作者和本文連結
用過哪些工具?為啥用這個工具(速度快,支援高併發...)?底層如何實現的?

相關文章