当社の Web プロジェクトの 1 つでは、新しい都市の増加により、アクセス数が増加し、データベースへの負荷が増大しました。インターフェースを提供するビジネス パーティとして、多数の「502」リクエストが発生しました。最近、下流のフィードバックによって報告されました。
502、不正なゲートウェイは通常、アップストリーム (ここでは PHP) でのエラーです。PHP の場合、502 の一般的な原因は、スクリプトの実行がタイムアウト設定時間を超えているか、タイムアウト設定が大きすぎることです。 PHP プロセスに時間がかかるため、解放できず、ゲストをピックアップするためのアイドル状態のワーカー プロセスがありません。
私たちのプロジェクトは、PHP の実行時間の設定が短すぎることが原因です。この場合、まず PHP の実行時間を適切に増やし、最初に 502 を確実にクリアすることができます。結局、最適化にはさらに時間がかかります。
php の実行時間を制御するには、php.ini の max_execution_time と php-fpm の request_terminate_timeout の 2 つのオプションがあります。request_terminate_timeout は max_execution_time をオーバーライドできるため、グローバル php.ini を変更したくない場合は、単に変更してくださいphp-fpmの設定だけで十分です。
次に、php スクリプトの実行が設定時間を超えて nginx が 502 を返す原因を詳しく分析します。
最初にシーンを設定して、問題が再発しましょう。
nginx と php は、追跡を容易にするために、それぞれ 1 つのワーカーのみを起動します。
php-fpm の request_terminate_timeout は 3 秒に設定されています。
テスト スクリプト test.php
sleep(20); echo 'ok';
go go go:
ブラウザで www.v.com/test.php にアクセスすると、3 秒後に予想通り 404 が表示されます。秒。 ? ?何? ? ?
これは悪いスタートです。すぐに nginx 設定ファイルを見てください。
この場所の設定は、 5xx エラーが発生します。見栄えの良いインターフェイスにジャンプしますが、/usr/share/nginx/html に 50x.html ファイルがありません。それで私は404を手に入れました。これは問題に対する私の判断の正確さに影響を与えないでしょうか?コメントアウトするだけです!もう一度アクセスして 3 秒待つと、最終的に「通常の」インターフェイスが表示されます。
環境は良好です。以下のルーチンに従ってください。Web の問題のトラブルシューティング ルーチンに従ってください。まずエラー ログを見てみましょう:
nginx:
報告されるエラーは、recv() が失敗しました (104: ピアによって接続がリセットされました。
recv が失敗し、接続がリセットされました。接続をリセットしますか? 設定しますか? 一貫性がありませんか?
php-fpm のエラー ログを調べています:
(php-fpm の php_admin_value[error_log] オプションは、 php のエラー ログ, php.ini に上書きされます. ただし、ここでは php エラーではなく、php-fpm エラーを見ています. php-fpm のエラー ログは、php-fpm の error_log オプションで指定されます。 conf.)
各リクエストは 2 つの警告と 1 つの通知を生成します:
warning: スクリプトの実行がタイムアウトして終了しました。
warning : 子プロセスが sigterm を受信しました シグナルが終了しました
Notice: 新しい子プロセスが開始されました (pm.min_spare_servers = 1 に設定したため)
php 回のワーカー プロセスが実行されたようです出力すると、スクリプトの実行が終了するだけでなく、ワーカープロセスも終了します。phpワーカープロセスが終了するため、nginxエラー接続がリセットされるようです(tcp接続では、一方が切断されると、最初に送信されます)
ログを通じて、php スクリプトの実行がタイムアウトになり、ワーカーのサブプロセスが終了し、nginx がピアによる接続リセットのエラーを報告することがすでにわかります。 php と nginx の状況を参照してください:
php:
1.nginx 接続リクエストを受け入れます (ソケット、バインド、リッスンはすべてnginx のポートは 47039 で、標準入力の fd0 からデータを読み込んでいることがわかります。これは fast-cgi プロトコルで規定されており、accept 後の接続記述子は 3 です。
2. fd3 から nginx によって渡されたデータを fastcgi プロトコル形式で読み取り、856 バイトを受信しました。なぜ read5 なのか、時間はどうでしょうか?fastcgi プロトコルのデータ パケットは 8 バイトでアライメントされており、パケット ヘッダーとパケット本体で構成されているためです。そして、最初にリクエスト ID、バージョン、タイプ、その他の情報を含むリクエスト パケットを送信し (ヘッダーとボディはそれぞれ 8 バイトを占有します)、次に取得パラメータと環境変数を渡すために params パケットを送信します (ヘッダーは 8 バイトです)。バイト)、パケットボディが長くなります)、最後にパケットボディのないパケットヘッダーのみのparamsデータパケットが送信され、パラメーターの送信の終了を示します(パケットヘッダーの8バイト)。したがって、最初の 3 回の読み取りは、リクエスト パケットのヘッダーと本文、およびパラメータ パケットのヘッダーを読み取るために使用されます。4 回目の読み取りは実際のデータを読み取り、最後の読み取りは最後のデータのヘッダーを読み取ります。パラメータパケット。したがって、nginx によって送信されるデータは 8 8 8 856 8 = 896 バイトになります (これは、以下の nginx の送信バイトに対応します)。 post モードの場合は、stdin データ パケットも送信されることに注意してください。
3. PHP プログラムの sleep(20) で 20 秒間のスリープを設定します。その後はプロセスが終了するため、それ以上はありません。 strace プログラムも終了しました。
nginx:
#1.ブラウザへのリクエストを受け入れます。ブラウザ側のポートが 56434、IP が 192.168.1.105 であることがわかります。となり、確立されました 接続されているfdは3です。
2. fd3、http プロトコルからデータを受信します。
3. ソケット fd21 を作成して、php との接続を確立します。
4. fd21 に接続すると、ローカル マシンの 9000 番ポートに接続されていることがわかります。ここでは、nginx と php-fpm は IP ソケット接続方式を使用しています。nginx と php-fpm が 1 つのマシンにデプロイされている場合、unix が考えられます。ドメインソケット。
5. fast-cgi プロトコル形式でデータを fd21 に書き込みます。書き込まれた長さが 896 であることがわかります。これは、上記の PHP が受信した長さに対応します。
6.recvfrom 関数は fd21 から echonreset (ピアによる接続リセット)を返します
7.エラー情報を fd9 に書き込みます.fd9 が nginx エラー ログのファイル記述子であると推測できます。
8. fd21 との接続を閉じます。
9. 502 不良ゲートウェイを fd3 に書き込み、これがブラウザに返される情報です。
10. fd8 にアクセス ログを書き込みます。fd8 は nginx のアクセス ログのファイル記述子であると推測できます。
nginxのアクセスログとエラーログの推論を検証してみましょう。確かに fd8、fd9 であり、書き込みモードであることがわかります。
次に、このプロセス中のネットワーク パケット全体の送信を見てみましょう。
tcpdump を介してパケットをキャプチャすると、より便利です。アーティファクトを使用して表示します。
私は nginx と php の間の通信だけを確認したいのですが、nginx のポートが 47039 であることがわかっているので、tcp.srcport==47039 を通じて対応するパッケージを除外できます。
nginx と php-fpm の間のデータ対話のプロセスを確認できます。47039->9000 が 3 ウェイ ハンドシェイクを確立し、データを 9000、9000 の応答に送信します。 ack 付き、3 秒後に 9000 最初に返信。何も間違っていません。
注:
syn、fin はそれぞれシーケンス番号を占有します
ack、rst はシーケンス番号を占有しません (2 つのパッケージ 28 と 29 の reqnum と acknum は同じ)
シーケンス番号はバイトごとに 1 を加えます (896 バイトが 29 パケットで送信されますが、29 パケットのシーケンスは 4219146879 で、30 パケットの ACK は 4219147775 であり、これはまったく違います) of 896)
最初 返信は不要です。
以上がnginx+php-fpm サービスの HTTP ステータス コード 502 を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。