PHP-CGI 進程 CPU 100% 與 file_get_contents 函數的關系
有時,運行Nginx和PHP-CGI(php-fpm)網絡服務的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配置文件中的以下參數:
作為單個請求服務的超時(以秒為單位),之后工作進程將被終止
應在“max_execution_time”ini 選項因某種原因未停止腳本執行時使用
“0s”表示“關閉”
valuename='request_terminate_timeout'0s/值
默認值為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網關”。
要實現完整的解決方案,PHP程序員只能改掉直接使用file_get_contents('http://example.com/')的習慣,而是稍微修改一下,加個timeout,按照下面的方式實現HTTP GET請求。如果覺得麻煩,可以自己將下面的代碼封裝成一個函數。
?
="tag-name">php????當然,導致 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?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() 導致的問題了。
我們專注高端建站,小程序開發、軟件系統定制開發、BUG修復、物聯網開發、各類API接口對接開發等。十余年開發經驗,每一個項目承諾做到滿意為止,多一次對比,一定讓您多一份收獲!