ホームページ  >  記事  >  バックエンド開発  >  PHP プロセス CPU の問題を 100% 解決 -- file_get_contents が問題を引き起こした

PHP プロセス CPU の問題を 100% 解決 -- file_get_contents が問題を引き起こした

高洛峰
高洛峰オリジナル
2016-10-17 11:00:211431ブラウズ

Nginx および PHP-CGI (php-fpm) Web サービスを実行している Linux サーバーでシステム負荷が突然増加することがあります。top コマンドを使用して、多くの php-cgi プロセスの CPU 使用率が 100% に近いことを確認します。その後、追跡を通じて、この種の状況の発生は PHP の file_get_contents() 関数と密接に関係していることがわかりました。

大規模および中規模の Web サイトでは、HTTP プロトコルに基づく API インターフェイス呼び出しが一般的です。 PHP プログラマーは、URL の返されたコンテンツを取得するために、シンプルで便利な file_get_contents("http://example.com/") 関数を使用することを好みますが、Web サイト http://example.com/ の応答が遅い場合は、file_get_contents(. " ) は常にそこでスタックし、タイムアウトしません。

php.iniにはPHPスクリプトの最大実行時間を設定できるパラメータmax_execution_timeがあることはわかっていますが、php-cgi(php-fpm)ではこのパラメータは有効になりません。 PHP スクリプトの最大実行時間を実際に制御できるのは、php-fpm.conf 構成ファイル内の次のパラメーターです:

ワーカー プロセスが終了するまでの単一のリクエストを処理するためのタイムアウト (秒単位)

' max_execution_time' ini オプションが何らかの理由でスクリプトの実行を停止しない場合に使用されます

'0s' means 'off'

0s

デフォルト値は 0 秒で、PHP スクリプトが実行を継続することを意味します。このように、すべての php-cgi プロセスが file_get_contents() 関数でスタックすると、この Nginx+PHP Web サーバーは新しい PHP リクエストを処理できなくなり、Nginx はユーザーに「502 Bad Gateway」を返します。 PHP スクリプトの最大実行時間を設定するにはこのパラメータを変更する必要がありますが、根本的な原因ではなく症状を治療するだけです。たとえば、30sに変更された場合、file_get_contents()がWebページのコンテンツを取得するのが遅い場合、これは150のphp-cgiプロセスが1秒あたり5つのリクエストしか処理できないことを意味し、Webサーバーが「502.不正なゲートウェイ" "。

完全な解決策を達成するには、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プロセスを表示します。

トップ - 724 日、10:34:18 アップ、21:01、3 ユーザー、負荷平均: 17.86、11.16、7.69

タスク: 合計 561、実行中 15、スリープ 546、停止 0、ゾンビ 0

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、使用済み 4320108k、空き 3780888k、バッファ 77257 2k

スワップ: 合計 8193108k、使用済み 50776k、空き 8142332k、キャッシュ 412088k


PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND D 7 www 18 0 360m 22m 12m R 100.6 0.3 0:02.60 php- CGI 09 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ギ2 www 20 0 360m 26m 15m R 75.5 0.3 0:10.93 PHP-CGI

10708WWW 25 0 360M 22M 12M R 69.7 0.3 0:45.16 PHP-CGI

10683WWW 25 0 362M 28M 15M R 54.2 0.4 0:32.65 PHP-CGI

10711WWW 25 0 360M 23M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 15M 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 (出力 [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) = 0 (タイムアウト)

select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {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 (out [6], left {15, 0})

poll([{fd=6, events=POLLIN}], 1, 0) = 0 (タイムアウト)

select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})

poll([{fd=6, events=POLLIN} ]、1、0) = 0 (タイムアウト)

select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})

poll([{fd=6, events=POLLIN) }], 1, 0) = 0 (タイムアウト)

select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})

poll([{fd=6, events=POLLIN}], 1, 0) = 0 (タイムアウト)

select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})

poll([{fd=6, events=POLLIN}], 1, 0) = 0 (タイムアウト)

select(7, [6], [6 ], [], {15, 0}) = 1 (out [6], left {15, 0})

poll([{fd=6, events=POLLIN}], 1, 0) = 0 (タイムアウト) )


そうすると、問題の原因が file_get_contents() であることがわかります。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。