首頁  >  文章  >  後端開發  >  解決PHP進程 CPU 100% -- file_get_contents惹的禍

解決PHP進程 CPU 100% -- file_get_contents惹的禍

高洛峰
高洛峰原創
2016-10-17 11:00:211397瀏覽

有時候,運行 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'  

0s PH

『這樣,當所有的 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  
$ctx = stream_context_create(array(  
   &#39;http&#39; => array(  
       &#39;timeout&#39; => 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.69

Tasks: 561 to run zombie

Cpu​​( s):  5.9%us,  4.2%sy,  0.0%ni, 89.4%id,  0.2%wa,  0.0%hi,  0.2%si,  0.0%st

Mem: 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}   ,左{ 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)     = 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() 所導致的問題了。


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn