nginx+php-fpm サービスの HTTP ステータス コード 502 の詳細な分析

nginx+php-fpm サービスの HTTP ステータス コード 502 の詳細な分析

弊社の Web プロジェクトの 1 つでは、新しい都市の増加によりトラフィックと DB 負荷が増加しています。インターフェイスのビジネス プロバイダーとして、最近、ダウンストリーム フィードバックから大量の「502」リクエストを受け取りました。

502 (Bad Gateway) は、通常、上流 (この場合は PHP) のエラーによって発生します。PHP の場合、502 の一般的な原因は、スクリプトの実行がタイムアウト設定時間を超えたか、タイムアウト設定が大きすぎるために、PHP プロセスが長時間解放できず、クライアントを受信するアイドル ワーカー プロセスがないことです。

私たちのプロジェクトは、PHP の実行時間が短すぎることが原因です。この場合、502 が最初にクリアされるように、PHP の実行時間を適切に増やすことができます。結局、最適化には時間がかかります。

PHP 実行時間を制御するオプションは 2 つあります。php.ini の max_execution_time と php-fpm の request_terminate_timeout です。Request_terminate_timeout は max_execution_time を上書きできるため、グローバル php.ini を変更したくない場合は、php-fpm 構成のみを変更する必要があります。

次に、PHP スクリプトの実行が設定時間を超え、nginx が 502 を返す原因を詳しく分析します。

まず問題を再現するための状況を設定しましょう:

Nginx と PHP は、追跡を容易にするためにそれぞれ 1 つのワーカーのみを起動します。

php-fpm の request_terminate_timeout は 3S に設定されています。

テストスクリプト test.php

睡眠(20);
'ok' をエコーし​​ます。

行け!行け!行け:

ブラウザで www.v.com/test.php にアクセスすると、3 秒後に結果は...404 になりますか? ? ?何? ? ?

スタートは良くありません。nginxの設定ファイルを見てみましょう。

この場所の設定は、5xx エラーが発生したときに見栄えの良いインターフェースにジャンプするためのものですが、/usr/share/nginx/html に 50x.html ファイルがありません。それで404エラーが発生しました。これは私の判断の正確さに影響しませんか?コメントアウトするだけです!再度アクセスし、3 秒待つと、最終的に「通常の」インターフェースが表示されます。

環境の準備ができたので、手順に従って、Web の問題のトラブルシューティング ルーチンを実行してみましょう。まず、エラー ログを見てみましょう。

nginx:

エラー メッセージはすべて、recv() が失敗しました (104: ピアによって接続がリセットされました)。

受信に失敗し、接続がリセットされました。接続がリセットされたのはなぜですか?意見の相違はありますか?

php-fpm のエラー ログを見てみましょう。

(php-fpm の php_admin_value[error_log] オプションは PHP エラー ログを指定し、php.ini のログを上書きすることに注意してください。ただし、ここでは PHP エラーではなく PHP-fpm エラーを調べます。PHP-fpm エラー ログは php-fpm.conf の error_log オプションによって指定されます。)

各リクエストでは 2 つの警告と 1 つの通知が生成されます。

警告: スクリプトの実行がタイムアウトになり終了しました。

警告: 子プロセスは SIGTERM シグナルを受信して​​終了しました。

注意: 新しい子プロセスが開始されました (pm.min_spare_servers = 1 に設定したため)

PHP ワーカー プロセスの実行がタイムアウトすると、スクリプトの実行が終了するだけでなく、ワーカー プロセスも終了するようです。 php ワーカー プロセスが終了したため、nginx エラー接続がリセットされたようです (TCP 接続では、一方の接続が切断されると、もう一方の接続に RST が送信されます)

ログから、PHP スクリプトの実行がタイムアウトし、ワーカー子プロセスが終了したため、nginx が「Connection reset by peer」というエラーを報告したことがわかります。次に、strace を使用して PHP と nginx の状況を確認します。

php:

1. nginx の接続要求を受け入れます (socket、bind、listen はすべてマスターで完了します)。nginx のポートが 47039 であることがわかります。FD0、つまり標準入力からデータを読み取ります。これは fast-cgi プロトコルで規定されています。受け入れ後の接続記述子は 3 です。

2. nginx から FD3 に渡されたデータを fastcgi プロトコル形式で読み取り、856 バイトを受信します。なぜ5回読むのですか?

fastcgi プロトコル データ パケットは 8 バイト境界に配置され、ヘッダーと本体から構成されるためです。そして、最初にリクエスト ID、バージョン、タイプ、その他の情報を含むリクエスト データ パケットを送信し (ヘッダーと本文はそれぞれ 8 バイトを占めます)、次にパラメータ データ パケットを送信して get パラメータと環境変数を渡し (ヘッダーは 8 バイト、本文の方が長い)、最後にパラメータ送信の終了を示す、本文がなくヘッダーのみのパラメータ データ パケットを送信します (ヘッダーは 8 バイトです)。したがって、最初の 3 つの読み取りは、リクエスト パケットのヘッダーと本文、およびパラメータ パケットのヘッダーを読み取るために使用されます。4 番目の読み取りは実際のデータを読み取るためのもので、最後の読み取りは最後のパラメータ パケットのヘッダーを読み取るためのものです。したがって、nginx によって送信されるデータは 8+8+8+856+8=896 バイト (以下の nginx の送信バイトに相当) になります。 post メソッドが使用される場合、stdin データ パケットも送信されることに注意してください。

3. スリープ時間を20秒に設定します。PHPプログラムではsleep(20)です。プロセスが終了するので、これ以上は発生しません。 strace プログラムも終了します。

nginx:

1.ブラウザへのリクエストを受け入れます。ブラウザ側のポートは56434、IPは192.168.1.105、確立された接続のFDは3であることがわかります。

2. FD3、HTTP プロトコルからデータを受信します。

3. PHP との接続を確立するためのソケット FD21 を作成します。

4. FD21 に接続すると、ローカル マシンのポート 9000 への接続が行われていることがわかります。ここで、nginx と php-fpm は IP ソケット接続方式を使用します。nginx と php-fpm が同じマシンに展開されている場合は、Unix ドメイン ソケットを検討できます。

5. fast-cgi プロトコル形式で FD21 にデータを書き込みます。書き込まれた長さは 896 であり、これは上記の PHP によって受信された長さに対応していることがわかります。

6. recvfrom関数はFD21からECONNRESET(ピアによる接続リセット)を返します。

7. エラー情報を FD9 に書き込みます。FD9 は nginx エラー ログのファイル記述子であると推測できます。

8. FD21との接続を閉じます。

9. ブラウザに返される情報である 502 Bad Gateway を 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 を応答し、9000 は 3 秒後に RST を応答します。何も問題はありません。

知らせ:

SYNとFINはそれぞれシーケンス番号を占有する

ACK と RST はシーケンス番号を占有しません (パケット 28 と 29 の reqnum と acknum は同じです)

シーケンス番号はバイトごとに 1 です (パケット 29 は 896 バイトを送信し、パケット 29 のシーケンスは 4219146879 で、パケット 30 の ack は 4219147775 であり、正確に 896 バイト異なります)

RST は応答を必要としません。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Nginx 502 Bad Gateway エラーの原因と解決策
  • PHP+nginx サービス 500 502 エラーのトラブルシューティングのアイデアの詳細な説明
  • Linux の Nginx でよくある 502 エラーの解決方法の詳細な説明
  • Nginx 502 エラーの解決方法の詳細な説明
  • PHP スクリプトは Nginx 502 エラーを監視し、php-fpm を自動的に再起動します
  • Nginx 502 Bad Gateway エラーの 4 つの一般的な原因と解決策
  • PHP を 5.3.28 から 5.3.29 にアップグレードすると Nginx 502 エラーが発生する
  • nginx サーバーでの 502 不正なゲートウェイ エラーの原因のトラブルシューティング

<<:  Windows 上の MySQL 5.6 で my.ini 設定ファイルを見つける方法

>>:  MySQL インストール図の概要

推薦する

Zabbix を使用して Nginx/Tomcat/MySQL を監視する方法の詳細なチュートリアル

目次ZabbixはNginxを監視するZabbixはTomcatを監視するZabbixはMySQLを...

私の CSS フレームワーク - base.css (ブラウザのデフォルト スタイルをリセット)

コードをコピーコードは次のとおりです。 @文字セット "utf-8"; /* @...

Minio 軽量オブジェクト ストレージ サービスのインストールとブラウザの使用チュートリアル

目次導入インストール1. マウントするフォルダを作成する2. イメージをプルする3. コンテナを作成...

Ubuntuサーバーの一般的なコマンドの概要

以下のコマンドのほとんどは、コンソール/ターミナル/シェルで入力する必要があります。 'su...

Dockerコンテナ内でホストDocker操作を呼び出して実行する

まず、この投稿は Docker 初心者向けです。もちろん、ベテランであれば記事中の分割線以降の操作方...

VUEはG2チャートを使用した実装を導入します

目次G2チャートについて使用テンプレートで使用される完全なコード (棒グラフ)世界地図を追加するG2...

Linux の Centos7 に Mysql5.7.19 をインストールする詳細なチュートリアル

1. MySQLをダウンロードするURL: https://dev.mysql.com/downlo...

vue3+vite プロジェクトで svg を使用する方法の詳細なグラフィック説明

今日、vue3+viteプロジェクトの実践で、svgを使用する場合、以前の記述方法が使用できないこと...

vueの実践的な応用におけるvuexの永続性の詳細な説明

目次vuex 永続性要約するvuex 永続性vuex: ブラウザを更新すると、vuexの状態は初期状...

1分でVueが右クリックメニューを実装

目次レンダリングインストールコードの実装カスタムスタイル要約する効率的に要件を満たし、車輪の再発明を...

Dockerを使用してSpring Bootプロジェクトをデプロイする手順

目次シンプルなSpringbootプロジェクトを作成する1. pom.xmlでSpring Boot...

Linuxでスクリーンショットを撮って編集するための最高のツール

メインのオペレーティング システムを Windows から Ubuntu に切り替えたとき、最初に考...

Javascript クロージャの使用シナリオの原則の詳細

目次1. 終了2. クロージャの使用シナリオ1.タイムアウトを設定する2. コールバック3. 手ぶれ...

CSS フレキシブルレイアウト FLEX、メディアクエリ、モバイルクリックイベントの実装

フレックスレイアウト定義: Flexレイアウトの要素は、 Flex 、または略して「コンテナー」と呼...