php日志中有一條超時的日志,但是我request_terminate_timeout中設置的是0,理論上應該沒有超時時間才對。
PHP Fatal error: Maximum execution time of 30 seconds exceeded in ...
OK,先列出現在的配置:
php-fpm:
request_terminate_timeout = 0
php.ini:
max_execution_time = 30
先查閱了一下php-fpm文件中關于request_terminate_timeout的注釋
; The timeout for serving a single request after which the worker process will
; be killed. This option should be used when the 'max_execution_time' ini option
; does not stop script execution for some reason. A value of '0' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
這個注釋說明了,request_terminate_timeout 適用于,當max_execution_time由于某種原因無法終止腳本的時候,會把這個php-fpm請求干掉。
再看看max_execution_time的注釋:這設置了腳本被解析器中止之前允許的最大執行時間,默認是30s??礃幼?,我這個請求應該是被max_execution_time這個設置干掉了。
好吧,不死心,做了一個實驗:
php-fpm request_terminate_timeout 設置 | 0 | 15 |
php.ini max_execution_time 設置 | 30 | 30 |
執行結果 | php有Fatal error超時日志,http狀態碼為500 | php無Fatal error超時日志,http狀態碼為502,php-fpm日志中有殺掉子進程日志 |
好吧,結論是web請求php執行時間受到2方面控制,一個是php.ini的max_execution_time(要注意的是sleep,http請求等待響應的時間是不算的,這里算的是真正的執行時間),另一個是php-fpm request_terminate_timeout 設置,這個算的是請求開始n秒。
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加一個超時參數。
$ctx = stream_context_create(array( 'http' => array( 'timeout' => 10 //設置一個超時時間,單位為秒 ))); file_get_contents($str, 0, $ctx);
php-fpm中的request_terminate_timeout最好不要設置
新聞熱點
疑難解答