徹底弄懂502/503/504(php-fpm+nginx)親測可用

參考:http://phpmianshi.com/?id=90

環境 php7.3.5 + nginx1.16.0

 

相信大家都遇到過50X的問題,網上也看了很多文章,總是各種不對,所以今天咱們詳解各種出現50X的情況和原因

502:Bad Gateway  作爲網關或者代理工作的服務器嘗試執行請求時,從上游服務器接收到無效的響應。

503:Service Unavailable 由於臨時的服務器維護或者過載,服務器當前無法處理請求。這個狀況是臨時的,並且將在一段時間以後恢復。如果能夠預計延遲時間,那麼響應中可以包含一個 Retry-After 頭用以標明這個延遲時間。如果沒有給出這個 Retry-After 信息,那麼客戶端應當以處理500響應的方式處理它。

504:Gateway Time-out 作爲網關或者代理工作的服務器嘗試執行請求時,未能及時從上游服務器(URI標識出的服務器,例如HTTP、FTP、LDAP)或者輔助服務器(例如DNS)收到響應。

 

nginx+php 出現502 bad gateway,一般這都不是nginx的問題,而是由於 fastcgi或者php的問題導致的,常見的有以下幾種。

1.php-fpm進程掛掉或者重啓,大家可以service php-fpm stop 然後再打開php頁面就返回502

nginx錯誤日誌:

*153514 connect() to unix:/dev/shm/php-cgi.sock failed (2: No such file or directory) while connecting to upstream

所以平時我們要平滑重啓 kill -USR2 pid  就不會報錯了

 

2.php-fpm 平滑重啓時也是有可能有502的,大家可以打開一個sleep(10) 的頁面,然後service php-fpm reload  或者 kill -USR2 pid 測試

php-fpm錯誤日誌:

/phpmianshi.com/test.php' (request: "GET /test.php") executing too slow

 

主要原因是:php-fpm.conf中process_control_timeout 設置過小造成的

process_control_timeout 參數解釋

參數含義是 設置子進程接受主進程複用信號的超時時間. 控制子進程處理來自master的信號的時間,默認爲0.如果正在處理請求, 很可能會收到錯誤報警。建議將此參數設置爲相同的值 request_terminate_timeout,以便worker有時間完成處理請求, 否則將會中斷。

 

3.request_terminate_timeout 設置的過小,php沒有執行完就被中斷,大家可以設置小一點,寫一個sleep腳本測試

php-fpm錯誤日誌:

[18-May-2020 19:37:47] WARNING: [pool www] child 7906, script '/data/wwwroot/mianshiphp/test.php' (request: "GET /test.php") executing too slow (1.295579 sec), logging
[18-May-2020 19:37:47] WARNING: [pool www] child 7906, script '/data/wwwroot/mianshiphp/test.php' (request: "GET /test.php") execution timed out (1.629247 sec), terminating
[18-May-2020 19:37:47] WARNING: [pool www] child 7906 exited on signal 15 (SIGTERM) after 72.682120 seconds from start

4.nginx fastcgi_read_timeout 設置過小,返回504

比如:設置 fastcgi_read_timeout =1 ,php腳本sleep(3)  ,則返回504

php-fpm錯誤日誌:

[18-May-2020 20:01:47] WARNING: [pool www] child 12044, script '/data/wwwroot/mianshiphp/test.php' (request: "GET /test.php") executing too slow (1.235212 sec), logging

5.當服務器壓力過大,沒有更多的php-fpm處理請求時,返回504

比如設置php-fpm進程數爲1,壓力測試 ab -n 100 -c 20 http://phpmianshi.com/?id=90

 

有文章說,壓力過大,沒有足夠的php-fpm處理時會返回502,我這裏測試是不對的,而是部分請求返回了200,其他請求返回了504

 

說明當php-fpm不足時,是有一個等待隊列存在的。已經接到請求的php-fpm會返回200,長時間得不到php-fpm處理的請求就返回了504,

 

那麼這個等待隊列是什麼呢?分析如下:

 

其實就是php-fpm.conf 中的listen.backlog配置 ,當backlog隊列滿了,會出現502錯誤,

 

首先查看php活躍的套接字:  ss -ln |grep -E 'php|Netid'

 

Netid  State      Recv-Q Send-Q Local Address:Port               Peer Address:Port              
u_str  LISTEN     0      32768  /dev/shm/php-cgi.sock 79562794              * 0

 

關注 Recv-Q 和 Send-Q 這兩個字段。

 

LISTEN 狀態: Recv-Q 表示的當前等待服務端調用 accept 完成三次握手的 listen backlog 數值,也就是說,當客戶端通過 connect() 去連接正在 listen() 的服務端時,這些連接會一直處於這個 queue 裏面直到被服務端 accept();Send-Q 表示的則是最大的 listen backlog 數值,這就就是上面提到的 min(backlog, somaxconn) 的值。

 

 

於是修改listen.backlog = 1 ,同時開ab -n 5 -c 5 https://www.phpmianshi.com/backlog.php 測試,發現所有請求又都返回200了

 

ss -ln |grep -E 'php|Netid'

 

Netid  State      Recv-Q Send-Q Local Address:Port               Peer Address:Port              
u_str  LISTEN     3      32768  /dev/shm/php-cgi.sock 79562794              * 0

 

過一會 Recv-Q 慢慢減少到0,所有請求執行完成,說明php-fpm並沒有拒絕後兩次請求

 

具體原因如下:

 

當 queue 滿了之後,服務器並不會按照理論所述,不再對 SYN 進行應答,返回 ETIMEDOUT。根據這篇文檔的描述,服務器會隨機的忽略收到的 SYN,建立起來的連接數可以無限的增加,只不過客戶端會遇到延時以及超時的情況。

 

總結:適當增加max_children還是有用的,這樣的話php-fpm能同時處理的請求增加,客戶端的延遲等待時間也會相應的減小。

 

6.當遇到這個狀態碼的時候表示服務臨時不可用,比如nginx配置了頻率限制而client端又超過了配置的限制後就會收到503的響應。

 

其他待補充...

 

總結:

 

解決問題的最好的方式還是自己去看nginx和fastcgi的errorlog。

最後做個總結: php-cgi進程數不夠用、php執行時間長、或者是php-cgi進程死掉,都會出現502錯誤。

當nginx收到了無法理解的響應時,就返回502。當nginx超過自己配置的超時時間還沒有收到請求時,就返回504錯誤。

 

 

 


 

 

 


 

 


 

 

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