web-dev-qa-db-ja.com

FastCGIとApache500エラーが断続的に発生する

FastCGI(mod_fastcgi)の問題があります。これはたまに発生し、サーバーの完全なメルトダウンを引き起こすわけではなく、500エラーだけです。ここにいくつかあります。最初にAPCを使用しているので、PHPはFastCGIではなく独自のプロセスを制御しています。また、webrootを次のように設定しています。

/var/www/html

中のfcgi-bin:

/var/www/html/fcgi-bin

まず、Apache error_logです。

[Fri Jan 07 10:22:39 2011] [error] [client 50.16.222.82] (4)Interrupted system call: FastCGI: comm with server "/var/www/html/fcgi-bin/php.fcgi" aborted: select() failed, referer: http://www.domain.com/

また、「fcgi-pm」プロセスでstraceを実行しました。これは、爆撃された頃の痕跡からの抜粋です。

21725 gettimeofday({1294420603, 14360}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6503 38*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 96595}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6154 23*C /var/www/html/fcgi-bin/php.fcgi - - 6483 28*", 16384) = 92
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 270744}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 5741 38*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 311502}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6064 32*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 365598}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6179 33*C /var/www/html/fcgi-bin/php.fcgi - - 5906 59*", 16384) = 92
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 454405}, NULL) = 0

'select()'は関係なく同じままであるように見えますが、read()は、爆撃中に戻り値を46から他の数値に変更します。誰かがこのようなものを見たことがありますか。これはある種のファイルロックでしょうか?

ありがとう、ベン

4
benkorn1

あらすじ

Apacheでもまったく同じ動作を観察しました。この問題はlighttpdに固有のものではないようです。

私の場合、症状はまったく同じでした。 Apacheアクセスログには断続的な500応答コードが表示され、PHPのエラーログには対応するエントリがありませんでした(そしてPHPエラー報告は最大限に冗長になるように構成されていました)。

この問題については、Apacheメーリングリストで詳しく説明しました(リストのアーカイブで、「error.logに対応するエントリがない、access.logの断続的な500応答」の件名を検索してください)。

根本的な原因

1100110の回答は根本原因を示唆していますが、Apacheから直接追加のドキュメントと、問題を解決するための提案を提供します。

この件に関するApacheの公式の言葉は次のとおりです。

https://httpd.Apache.org/mod_fcgid/mod/mod_fcgid.html

特別なPHP考慮事項

デフォルトでは、PHP FastCGIプロセスは500リクエストを処理した後に終了し、このモジュールがすでにアプリケーションに接続して次のリクエストを送信した後に終了する場合があります。それが発生すると、エラーがログに記録され、 500内部サーバーエラーがクライアントに返されます。これはPHP PHP_FCGI_MAX_REQUESTSを0に設定することで動作を無効にできますが、PHPアプリケーションがリソースをリークします。あるいは、PHP_FCGI_MAX_REQUESTSをデフォルトよりもはるかに高い値に設定して、この問題の頻度を減らすことができます。FcgidMaxRequestsPerProcessをPHP_FCGI_MAX_REQUESTS以下の値に設定して、問題を解決できます。

PHP子プロセス管理(PHP_FCGI_CHILDREN)は常にmod_fcgidで無効にする必要があります。これにより、生成されたアプリケーションプロセスに一度に1つの要求のみがルーティングされます。したがって、PHPによって作成された子プロセスは効果的に使用されません。(さらに、PHP子プロセスは適切に終了されない場合があります。)デフォルトでは、環境変数をPHP_FCGI_CHILDREN = 0に設定すると、PHP子プロセスの管理が無効になります。

PHPの一般的なAPCオペコードキャッシュは、PHPが子プロセスを管理しない限り、PHP FastCGIプロセス間でキャッシュを共有できません。 、キャッシュの有効性はmod_fcgidで制限されます;同時PHPリクエストは異なるオペコードキャッシュを使用します。

そこにあります。

可能な解決策

オプション1

1つの解決策は、PHP_FCGI_MAX_REQUESTSをゼロに設定することですが、この対策を講じると、メモリリークが制御不能になる可能性があります。

私が参照したさまざまなドキュメントの一部では、Fast-CGIを介したPHPに固有のメモリリークが発生しているため(この組み込みの「プロセスリサイクル」動作))、またはリスクは、不適切に記述された「暴走」スクリプトに限定されます。

いずれにせよ、特に共有ホスティング環境では、PHP_FCGI_MAX_REQUESTSをゼロに設定することに固有のリスクがあります。

オプション2

上記の抜粋で説明されているように、2番目の解決策は、FcgidMaxRequestsPerProcessをPHP_FCGI_MAX_REQUESTS以下の値に設定することです。ただし、ドキュメントでは重要なポイントが省略されています:値はゼロよりも大きい必要があります(ゼロはこれで「無制限」または「チェックを無効にする」ことを意味するため)環境)。 FcgidMaxRequestsPerProcessのデフォルト値がゼロでPHP_FCGI_MAX_REQUESTSのデフォルト値が500であるとすると、これらの値をオーバーライドしていない管理者は、断続的な500応答コードを経験します。このため、FcgidMaxRequestsPerProcessとPHP_FCGI_MAX_REQUESTSが同じデフォルト値を共有しない理由を理解できません。おそらくこれは、これら2つのディレクティブをそのように構成すると、PHP_FCGI_MAX_REQUESTSをゼロに設定した場合と同じ最終結果が得られるためです。この点については、ドキュメントがあいまいです。

オプション3

3番目の解決策は、Fast-CGIを完全に放棄し、suPHPや昔ながらのCGI + SuExecなどの同等の代替手段を優先することです。さまざまなPHPモードで、基本的な生のパフォーマンスベンチマークを実行しましたが、結果は次のとおりです。

  1. Mod-PHP 77.7
  2. CGI 69.0
  3. suPHP 67.0
  4. Fast-CGI 55.7

Mod-PHPは、77.7のスコアで、最高のパフォーマンスを発揮します。スコアは任意であり、PHPモード全体のページ読み込み時間の相対的な差異を示すためにのみ機能します。

これらのベンチマークがかなり代表的であると仮定すると、Fast-CGIの実装にこの1つの(かなり深刻な)欠陥があることを考えると、Fast-CGIに固執する理由はほとんどないようです。頭に浮かぶ唯一の実質的な理由は、オペコードのキャッシュです。私の理解では、PHPはCGIまたはsuPHPモードを介したオペコードキャッシングを利用できません(プロセスはリクエスト間で持続しないため)。

Fast-CGIはすぐに使用できるオペコードキャッシング(APCなど)を利用しませんが、賢いユーザーはFast-CGIでAPCを効果的にする方法を考案しました(ユーザーごとのキャッシュを介して):- http://www.brandonturner.net/blog/2009/07/fastcgi_with_php_opcode_cache/ 。ただし、いくつかの欠点があります。

  1. ユーザーごとに専用のキャッシュがあるため、メモリ(RAM)の要件はかなりのものです。 (観点から、Mod-PHPモードでは、すべてのユーザーが単一のキャッシュを共有することを考慮してください。)
  2. Apacheは、同等の新しいmod_fcgidではなく、古いモジュールmod_fastcgiを使用する必要があります。 (詳細については、上の段落で引用した記事を参照してください。)
  3. 設定はかなり複雑です。

関連する結果として、あなたはあなたの質問で次のように言いました:

まず、APCを使用しているので、PHPはFastCGIではなく、それ自体のプロセスを制御しています。

Mod_fastcgi(mod_fcgidではなく)を使用していない限り、また上記のいくつかの段落で引用した手順と同様の手順を実行していない限り、APCは効果なしにリソースを消費しています。そのため、APCを無効にすることをお勧めします。

ソリューションの概要

次の3つの対策のいずれかを実行します。

  1. PHP_FCGI_MAX_REQUESTS環境変数をゼロに設定します。 (PHPスクリプトが制御不能に成長するためにスクリプトにメモリリークが発生する可能性があります。)
  2. FcgidMaxRequestsPerProcessをPHP_FCGI_MAX_REQUESTS以下の値に設定しますが、ゼロより大きくします。
  3. Fast-CGIを放棄して、suPHPや従来のCGI + SuExecなどの同等の代替物を使用します。
6
Ben Johnson

私はどこかで(Apacheではなくlighttpdを扱っている)phpが何らかの理由で500を超えるリクエストを処理できないことを読みました。 501番目のリクエストは、何らかの理由で爆撃されます。

申し訳ありませんが、それ以上の情報はありませんが、少なくとも一見の価値があります。

tl; dr PHP_FCGI_MAX_REQUESTSを500に設定して、問題が解決するかどうかを確認します。

情報が見つかりました。Lighttpdに適用されますが、Apacheに適用されるかどうかはわかりません。

それをテストしてください。これがlighttpdの問題だけなのか、それとも一般的な問題なのかを聞いてみたいと思います。

PHPアプリケーションが時々エラー500を返すのはなぜですか?

「この問題は、PHPのほとんど知られていない問題に起因するようです:PHP 500リクエストを処理した後、新しいFastCGI接続の受け入れを停止します。残念ながら、PHPクリーンアップコードPHPはシャットダウンできますが、ソケットは開いたままなので、lightyはリクエスト番号501をPHPに送信できます。それは「受け入れられた」が、PHPは単に終了するように見え、lightyから500が返されます。

この発生を制限するには、PHP_FCGI_MAX_REQUESTSを500に設定します。」

-- http://redmine.lighttpd.net/projects/1/wiki/Docs:PerformanceFastCGI

1
1100110

お返事をありがとうございます。すべてのPHPエラーがログファイルに送られます。いくつかの通知が表示されますが、エラーはありません。このコードを記述しなかったことを認める必要があります。今のところ、500個のエラーすべてをリダイレクトしました。 '.htaccess'ルールを使用してindex.phpに追加します。何かが足りないはずです。これは発生しないはずです。'PHP_FCGI_MAX_REQUESTS 'が最大値に達すると、phpが子を強制終了し、これが混乱するという推測しかありません。 FastCGI。ただし、正しく理解していれば、PHPには、FastCGIが通信する唯一の親プロセスがあるはずなので、それが正しいかどうかはわかりません...これが私のラッパースクリプト:

#!/bin/bash
# Shell Script To Run PHP5 using mod_fastcgi under Apache 2.x
# Tested under Red Hat Enterprise Linux / CentOS 5.x
### Set PATH ###
PHP_CGI='/usr/bin/php-cgi -d apc.shm_size=60M'
PHP_FCGI_CHILDREN=25
PHP_FCGI_MAX_REQUESTS=1000
### no editing below ###
export PHP_FCGI_CHILDREN
export PHP_FCGI_MAX_REQUESTS
exec $PHP_CGI

これは非常に大容量のサーバーであるため、PHP_FCGI_CHILDRENが非常に高く設定されています。

ありがとう、ベン

0
user66079