PHP-CGI 進程 CPU 100% 與 file_get_contents 函數(shù)的關系
有時,運行Nginx和PHP-CGI(php-fpm)網(wǎng)絡服務的Linux服務器突然出現(xiàn)系統(tǒng)負載增加。使用top命令查看,很多php-cgi進程的CPU占用率接近100%。后來通過跟蹤發(fā)現(xiàn),這種情況的出現(xiàn)與PHP的file_get_contents()函數(shù)密切相關。 (北京網(wǎng)站建設)
在大中型網(wǎng)站中,基于HTTP協(xié)議的API接口調用司空見慣。 PHP程序員喜歡用簡單方便的file_get_contents('http://example.com/')函數(shù)來獲取一個URL的返回內容,但是如果http://example.com/網(wǎng)站響應慢,file_get_contents()會一直卡在那里,不會暫停。
我們知道在php.ini中,有一個參數(shù)max_execution_time可以設置PHP腳本的最長執(zhí)行時間,但是在php-cgi(php-fpm)中,這個參數(shù)是不會生效的。真正控制PHP腳本最大執(zhí)行時間的是php-fpm.conf配置文件中的以下參數(shù):
作為單個請求服務的超時(以秒為單位),之后工作進程將被終止
應在“max_execution_time”ini 選項因某種原因未停止腳本執(zhí)行時使用
“0s”表示“關閉”
valuename='request_terminate_timeout'0s/值
默認值為0 秒,即PHP 腳本將永遠執(zhí)行。這樣,當所有的php-cgi進程都卡在file_get_contents()函數(shù)中時,這個Nginx+PHP WebServer就不能再處理新的PHP請求,Nginx就會返回“502 Bad Gateway”給用戶。需要修改該參數(shù)來設置PHP腳本的最大執(zhí)行時間,但治標不治本。比如改成30s,如果file_get_contents()獲取網(wǎng)頁內容慢,說明150個php-cgi進程每秒只能處理5個請求,WebServer也很難避免“502 Bad網(wǎng)關”。
要實現(xiàn)完整的解決方案,PHP程序員只能改掉直接使用file_get_contents('http://example.com/')的習慣,而是稍微修改一下,加個timeout,按照下面的方式實現(xiàn)HTTP GET請求。如果覺得麻煩,可以自己將下面的代碼封裝成一個函數(shù)。
?
="tag-name">php????當然,導致 php-cgi 進程 CPU 100% 的原因不只有這一種,那么,怎么確定是 file_get_contents() 函數(shù)導致的呢?
首先,使用 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?total,??15?running,?546?sleeping,???0?stopped,???0?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:???8100996k?total,??4320108k?used,??3780888k?free,???772572k?buffers?
- Swap:??8193108k?total,????50776k?used,??8142332k?free,???412088k?cached?
- ??PID?USER??????PR??NI??VIRT??RES??SHR?S?%CPU?%MEM????TIME+??COMMAND????????????????????????????????????????????????????????????
- 10747?www???????18???0??360m??22m??12m?R?100.6?0.3????0:02.60?php-cgi????????????????????????????????????????????????????????????
- 10709?www???????16???0??359m??28m??17m?R?96.8??0.4????0:11.34?php-cgi????????????????????????????????????????????????????????????
- 10745?www???????18???0??360m??24m??14m?R?94.8??0.3????0:39.51?php-cgi????????????????????????????????????????????????????????????
- 10707?www???????18???0??360m??25m??14m?S?77.4??0.3????0:33.48?php-cgi????????????????????????????????????????????????????????????
- 10782?www???????20???0??360m??26m??15m?R?75.5??0.3????0:10.93?php-cgi????????????????????????????????????????????????????????????
- 10708?www???????25???0??360m??22m??12m?R?69.7??0.3????0:45.16?php-cgi????????????????????????????????????????????????????????????
- 10683?www???????25???0??362m??28m??15m?R?54.2??0.4????0:32.65?php-cgi????????????????????????????????????????????????????????????
- 10711?www???????25???0??360m??25m??15m?R?52.2??0.3????0:44.25?php-cgi????????????????????????????????????????????????????????????
- 10688?www???????25???0??359m??25m??15m?R?38.7??0.3????0:10.44?php-cgi????????????????????????????????????????????????????????????
- 10719?www???????25???0??360m??26m??16m?R??7.7??0.3????0:40.59?php-cgi?
找其中一個 CPU 100% 的 php-cgi 進程的 PID,用以下命令跟蹤一下:
- strace?-p?10747?
如果屏幕顯示:
- 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,?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)?
- 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,?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)?
- 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,?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)?
- select(7,?[6],?[6],?[],?{15,?0})????????=?1?(out?[6],?left?{15,?0})?
- poll([{fd=6,?events=POLLIN}],?1,?0)?????=?0?(Timeout)?
那么,就可以確定是 file_get_contents() 導致的問題了。
我們專注高端建站,小程序開發(fā)、軟件系統(tǒng)定制開發(fā)、BUG修復、物聯(lián)網(wǎng)開發(fā)、各類API接口對接開發(fā)等。十余年開發(fā)經驗,每一個項目承諾做到滿意為止,多一次對比,一定讓您多一份收獲!