有時候,運行 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 設定檔中的以下參數:
The timeout (in seconds) for serving a single request after which the worker process will be terminated
max_execution_time' ini option does not stop script execution for some reason
'0s' means 'off'
30s
<?php $ctx = stream_context_create(array( 'http' => array( 'timeout' => 1 //设置一个超时时间,单位为秒 ) ) ); file_get_contents("http://example.com/", 0, $ctx); ?>當然,導致 php-cgi 進程 CPU 100% 的原因不只有這一種,那麼,怎麼確定是 file_get_contents() 函數導致的呢? 首先,使用 top 指令查看 CPU 使用率較高的 php-cgi 流程。 top - 10:34:18 up 724 days, 21:01, 3 users, load average: 17.86, 11.16, 7.69Tasks: 561 to run zombieCpu( s): 5.9%us, 4.2%sy, 0.0%ni, 89.4%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%stMem: 92180 88k free, 772572k buffers
Swap: 8193108k total, 50776k used, 8142332k free, 412088k cached
CPU %MEM TIME+ COMMAND 0m 3 0:02.60 php- cgi
10709 www 16 0 359m
10745 www 18 0 360m 24m 14m R 94.8 0.3 0:39.51 php-cgi www 18 0 360m 25m 14m S 77.4 0.3 0:33.48 php-c 1078 2 www 20 0 360m 26m 5-c 1078 2 www 20 0 360m 26m 5-c 1078 2 www 20 0 360m 26m155m -CGI
10708www 25 0 360m 22m 12m R 69.7 0.3 0:45.16 PHP-CGI
10683www 25 0 362m 28m 28m 155 44 .25 php-cgi
1068 8 www 25 0 359m 25m 15m R 38.7 0.3 0:10.44 PHP-CGI
10719 www 25 9 php-cgi
找到其中一個CPU 100 %的php-cgi進程的PID,用以下指令追蹤一下:
strace -p 10747【如果螢幕顯示:
select( 7, [6], [6], [], {15, 0}) = 1(出[6],左{15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (逾時)
) 7, [ 6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})民意調查([{fd=6, events=POLLIN}] , 1, 0) = 0 (逾時)select(7, [6], [6], [], {15, 0}) = 1 (out [ 6],左{15, 0})} poll([ {fd=6, events=POLLIN}], 1, 0) = 0 (逾時)select(7, [6], [6], [ ], {15, 0}) = 1 (out [6] , 左{15, 0})poll([{fd=6, events=POLLIN}], 1, 0) = 0 (逾時) select(7, [6], [6], [], {15, 0}) = 1(出[6],左{15, 0})poll([{fd=6, events=POLLIN} ], 1, 0) = 00(逾時)select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN }], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 00})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6 ], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout )
那麼,就可以確定是file_get_contents() 所導致的問題了。