1. 程式人生 > >php-fpm設定問題導致網站無法訪問

php-fpm設定問題導致網站無法訪問

1,request_terminate_timeout引起的資源問題

request_terminate_timeout的值如果設定為0或者過長的時間,可能會引起file_get_contents的資源問題。

如果file_get_contents請求的遠端資源如果反應過慢,file_get_contents就會一直卡在那裡不會超時。我們知道php.ini 裡面max_execution_time 可以設定 PHP 指令碼的最大執行時間,但是,在 php-cgi(php-fpm) 中,該引數不會起效。真正能夠控制 PHP 指令碼最大執行時間的是 php-fpm.conf 配置檔案中的request_terminate_timeout引數。

request_terminate_timeout預設值為 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”。解決辦法是request_terminate_timeout設定為10s或者一個合理的值,或者給file_get_contents加一個超時引數。

1 2 3 4 5 6 7 $ctx = stream_context_create(array( 'http' => array( 'timeout' => 10    //設定一個超時時間,單位為秒 ) )); file_get_contents($str, 0, $ctx);

2,max_requests引數配置不當,可能會引起間歇性502錯誤:

1 pm.max_requests = 1000

設定每個子程序重生之前服務的請求數. 對於可能存在記憶體洩漏的第三方模組來說是非常有用的. 如果設定為 ’0′ 則一直接受請求. 等同於 PHP_FCGI_MAX_REQUESTS 環境變數. 預設值: 0.
這段配置的意思是,當一個 PHP-CGI 程序處理的請求數累積到 500 個後,自動重啟該程序。

但是為什麼要重啟程序呢?

一般在專案中,我們多多少少都會用到一些 PHP 的第三方庫,這些第三方庫經常存在記憶體洩漏問題,如果不定期重啟 PHP-CGI 程序,勢必造成記憶體使用量不斷增長。因此 PHP-FPM 作為 PHP-CGI 的管理器,提供了這麼一項監控功能,對請求達到指定次數的 PHP-CGI 程序進行重啟,保證記憶體使用量不增長。

正是因為這個機制,在高併發的站點中,經常導致 502 錯誤,我猜測原因是 PHP-FPM 對從 NGINX 過來的請求佇列沒處理好。不過我目前用的還是 PHP 5.3.2,不知道在 PHP 5.3.3 中是否還存在這個問題。

目前我們的解決方法是,把這個值儘量設定大些,儘可能減少 PHP-CGI 重新 SPAWN 的次數,同時也能提高總體效能。在我們自己實際的生產環境中發現,記憶體洩漏並不明顯,因此我們將這個值設定得非常大(204800)。大家要根據自己的實際情況設定這個值,不能盲目地加大。

話說回來,這套機制目的只為保證 PHP-CGI 不過分地佔用記憶體,為何不通過檢測記憶體的方式來處理呢?我非常認同高春輝所說的,通過設定程序的峰值內在佔用量來重啟 PHP-CGI 程序,會是更好的一個解決方案。

3,php-fpm的慢日誌,debug及異常排查神器:

request_slowlog_timeout設定一個超時的引數,slowlog設定慢日誌的存放位置

1 tail -f /var/log/www.slow.log

上面的命令即可看到執行過慢的php過程。
大家可以看到經常出現的網路讀取超過、Mysql查詢過慢的問題,根據提示資訊再排查問題就有很明確的方向了。