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'
デフォルト値は 0 秒で、PHP スクリプトが実行を継続することを意味します。このように、すべての php-cgi プロセスが file_get_contents() 関数でスタックすると、この Nginx+PHP Web サーバーは新しい PHP リクエストを処理できなくなり、Nginx はユーザーに「502 Bad Gateway」を返します。 PHP スクリプトの最大実行時間を設定するにはこのパラメータを変更する必要がありますが、根本的な原因ではなく症状を治療するだけです。たとえば、
完全な解決策を達成するには、PHP プログラマが file_get_contents("http://example.com/") を直接使用する習慣を変更できるようにするだけですが、それをわずかに変更し、タイムアウトを追加し、次のメソッドを使用して HTTP を実装します。 GET リクエスト。それが面倒な場合は、次のコードを自分で関数にカプセル化することもできます。
<?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プロセスを表示します。
トップ - 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() であることがわかります。