1. 程式人生 > >莫斯科保衛戰之PHP-502 Bad Gateway

莫斯科保衛戰之PHP-502 Bad Gateway

莫斯科保衛戰之openstack

前言


其實這個小報錯是之前的小故障但是也可以引發血案,所以我采取了修改php-fpm.conf 配置 nginx.conf的配置也相應設置好了所以今天介紹一下php的報錯。因上大學閑暇的時候喜歡軍事研究、所以本節故障為名莫斯科保衛戰!


報錯如下:

技術分享


php-fpm5.4內容詳解

現在都用php-fpm5.6 7.0 這篇5.4的php-fpm也算是之前的總結吧!


PHP5.4安裝完畢後,FPM的默認配置文件於


/usr/local/php/etc/php-fpm.conf


vim /usr/local/php/etc/php-fpm.conf


技術分享


php-fpm.conf配置詳解 : pm = dynamic 如何控制子進程,選項有static和dynamic,默認采用dynamic;如果選擇static,則由pm.max_children指定固定的子進程數。

如果選擇dynamic,則由以下參數決定:
pm.max_children ,子進程最大數
pm.start_servers ,啟動時的進程數
pm.min_spare_servers ,保證空閑進程數最小值,如果空閑進程小於此值,則創建新的子進程
pm.max_spare_servers ,保證空閑進程數最大值,如果空閑進程大於此值,此進行清理

對於專用服務器,pm可以設置為static。 pm.max_requests 設置每個子進程重生之前服務的請求數. 對於可能存在內存泄漏的第三方模塊來說是非常有用的. 如果設置為 ’0′ 則一直接受請求. 設置為500就可以了(默認0)。

將值修改為如下:pm.max_children = 32 pm.start_servers = 16 pm.min_spare_servers = 8 pm.max_spare_servers = 32 pm.max_requests = 500 之後php-fpm -t 或者 sbin目錄下 出現如下:NOTICE: configuration file /usr/local/php/etc/php-fpm.conf test is successful 表示正確。

測試配置文件是否正常,沒問題,殺掉當前的FPM進程/usr/local/php/sbin/php-fpm 或者 systemctl restart php-fpm 啟動

有時候,運行 Nginx、PHP-CGI(php-fpm) Web服務的 Linux 服務器,突然系統負載上升,使用 top 命令查看,很多 php-cgi 進程 CPU 使用率接近100%。後來,我通過跟蹤發現,這類情況的出現,跟 PHP 的 file_get_contents() 函數有著密切的關系。

  

大、中型網站中,基於 HTTP 協議的 API 接口調用,是家常便飯。PHP 程序員們喜歡使用簡單便捷的 file_get_contents("http://example.com/") 函數,來獲取一個 URL 的返回內容,但是,如果 http://example.com/ 這個網站響應緩慢,file_get_contents() 就會一直卡在那兒,不會超時。

  

我們知道,在 php.ini 中,有一個參數 max_execution_time 可以設置 PHP 腳本的最大執行時間,但是,在 php-cgi(php-fpm) 中,該參數不會起效。真正能夠控制 PHP 腳本最大執行時間的是 php-fpm.conf 配置文件中的以下參數:

<value name="request_terminate_timeout">0s</value>


註意!新版的 php-fpm 中配置文件中格式是:

request_terminate_timeout=0s


默認值為 0 秒,也就是說,PHP 腳本會一直執行下去。這樣,當所有的 php-cgi 進程都卡在 file_get_contents() 函數時,這臺 Nginx+PHP 的 WebServer 已經無法再處理新的 PHP 請求了,Nginx 將給用戶返回“502 Bad Gateway”。修改該參數,設置一個 PHP 腳本最大執行時間是必要的,但是,治標不治本。例如改成 30s,如果發生 file_get_contents() 獲取網頁內容較慢的情況,這就意味著 150 個 php-cgi 進程,每秒鐘只能處理 5 個請求,WebServer 同樣很難避免“502 Bad Gateway”。

  

要做到徹底解決,只能讓 PHP 程序員們改掉直接使用 file_get_contents("http://example.com/") 的習慣,而是稍微修改一下,加個超時時間,用以下方式來實現 HTTP GET 請求。要是覺得麻煩,可以自行將以下代碼封裝成一個函數。

當然,導致 php-cgi 進程 CPU 100% 的原因不只有這一種,那麽,怎麽確定是 file_get_contents() 函數導致的呢?

首先, 開啟 PHP <value name="request_slowlog_timeout">3s</value> 記錄慢執行日誌

新版 php-fpm 想來想去文件中格式是:

slowlog=/tmp/slow.log

request_slowlog_timeout=3s


日誌中打印出執行慢的代碼行數。

  

首先,使用 top 命令查看 CPU 使用率較高的 php-cgi 進程。

找其中一個 CPU 100% 的 php-cgi 進程的 PID,用以下命令跟蹤一下:

strace -p 10747

  

如果屏幕顯示:

技術分享


php-cgi(php-fpm) 使用了Libevent,而Libevent 在 Linux 2.6 內核以上默認會使用 epoll I/O 模型處理 FastCGI 網絡請求,而非 select/poll。在慢日誌記錄的代碼行數中,包含 file_get_contents 以及其他函數,而 file_get_contents 等作為 Client 發起 HTTP 請求的函數使用的是 select/poll 模型,也就是說,只有 file_get_contents 等滿足“TCP請求默認不超時、使用select/poll 模型、進程CPU 100%”的網絡操作函數,會導致 strace -p 看到的這種情況。


總結:上不厭高,海不厭深

本文出自 “李世龍” 博客,謝絕轉載!

莫斯科保衛戰之PHP-502 Bad Gateway