web-dev-qa-db-ja.com

Apache / PHPベースのWebアプリで明らかなメモリリークの原因を特定するにはどうすればよいですか?

週に1回程度、場合によっては1日数回、何日も問題なく動作した後、EC2インスタンスが応答しなくなります。 Muninのメモリグラフはかなり単純な話をします。「アプリ」に割り当てられたメモリは増加し始め、スワップが完全に使用されてインスタンスが効果的に停止するまで停止しません。別のカスタムグラフは、絶えず成長しているプロセスがApache2であることを示しています。

Mod_phpといくつかのPHPスクリプトを使用して、標準のprefork Apacheセットアップを実行します。下のグラフを見るとわかるように、Apache2プロセスがトリガーされてますます多くのメモリを消費し始めます。最初の緑スパイクが間に合い、手に負えなくなる前にApacheを再起動しました。2番目のスパイクは少し遠くなり、インスタンスを完全に再起動する必要がありました。

Mininメモリグラフ

私が疑問に思っているのは、これを最もよくデバッグする方法です。 PHP FastCGIで設定し、それを独自のプロセスで実行するのではなく、Apacheであるか、PHPそして、過度のメモリ使用を引き起こしている私のコード?この問題を追跡するためにあなたはどのようなステップをとりますか?


更新:Mattが以下に提案したように、straceを実行した後、リークを追跡することができました。

メモリ内で徐々に継続的に増加しているApache2プロセスを見つけた後、さらにいくつかのerror_log()呼び出しを私のPHPスクリプトに追加し、スクリプトのさまざまなポイントで使用されるRSSの総量を出力しました実行(psの出力を使用)。ただし、誤解を招くようになりました-RSSが私のスクリプトの実行が完了した後にのみジャンプするように見えましたが、後でデバッグすると、実際にはそうではありませんでした。

幸いなことに、これらすべてのerror_log()呼び出しは、最終的には有用であることがわかりました。 strace(strace -p <pid> -tt -o trace.log -s 256)、リクエストごとに、プロセスが約400kのメモリを割り当てていることがわかりました(「brk」システムコールを探し、最初のコールのパラメータを最後のコールから差し引きます。次に、error_log()メッセージを含む最新の「書き込み」システムコールを検索しました。これにより、スクリプトのどの時点でメモリが割り当てられたかがわかります。より戦略的に配置されたerror_log()呼び出しをいくつか使用して、場所をより正確に特定し、最終的に原因を見つけました。

PHPスクリプトからcurl_exec()を呼び出したときにメモリがリークしていました。SSL接続の処理に関連するいくつかのcurlコードが問題を起こしています-HTTPに切り替えたときにリークはなくなりました。Curlの変更ログは、7.19.5(私たちは7.18.2でした)で修正されたいくつかのSSLメモリリークを参照しているので、次にそれを試します。

それまでの間、Apacheを適切な範囲内に保つ非常に低いMaxRequestsPerChildで実行しています。みんな、ありがとう!

18
ondrej

何が問題の原因であるかを追跡することは、お尻の痛みになる可能性があります。このような問題が発生した場合に最初に行うことは、MaxRequestsPerChildを積極的に低い数値(約100〜200)に減らし、違いが生じるかどうかを確認することです。もしそうなら、おそらくループのどこかでメモリをリークしているコードがあり、コード監査を実行したいと思うでしょう。

もう1つ注目すべき点は、Apacheの完全なステータスです。メモリリークの原因となっている特定のリクエストを特定できるかどうかを確認してください。疑わしいプロセスのPIDを取得し、それらに対してstraceを実行します。

5
matt

金曜日@正確に午後11時?バックアップ時間に相当しますか?システムには、その時点でプロセスとバックアップを提供するために使用できるI/Oがありますか?トレンドソフトウェアは、#procやApacheスコアボードもトレンドにしますか?ディスクI/Oはどうですか?

first私が行うことは、各procが取るメモリ量を計算し、ApacheのMaxRequestsに適切な制限を設定して、$ procmem * $ procsが使用可能なRAMを超えないようにすることです。 OOMは魔女狩りを開始するため、インスタンスを再起動する必要があると思います。あなたはneedを使用して、ボックスがその境界内に留まり、スワップやOOMに行かないようにすることで、これらの重い時間を処理できるようにします。これは、cronjobsを実行している場合はより困難であり、安全を確認せずに無言で実行された場合(つまり、5分ごとのスクリプトが最後の5minがまだ実行されているかどうかのチェックに失敗する場合)は非常に困難です。

これで、事態が大幅に悪化した場合でも、ボックスを再起動する必要がないことを確認したので、状況は大幅に改善されます。これらの長い時間の間にログインして、top、dstat、free -m、iostatなどを使用して何が起こっているのかをよく知ることができます。

Mattの方法は試す価値があるかもしれませんが、トラブルシューティングのツールとしてのみ使用する必要があります。この方法をそのままにしておくことはお勧めしません。次回の検索時に問題全体を見つけるのが非常に難しくなるためです。とは言っても、Apache /モジュールの問題のみが実際に取り除かれ、コードには何も含まれません。可能性が高いことは、Apacheモジュールのある種のメモリリークではないことに同意できると思います(評判の良いディストリビューションを使用している場合)。

2
fimbulvetr

最初に尋ねる質問は、Apacheを介して実行されているアプリケーションは何ですか?

あなたが書いたものですか、それともサードパーティのアプリですか?

他にどのようなコンポーネント/パッケージを参照していますか?

パッケージは最新ですか?

httpd.confパフォーマンスに関連するファイル?

0
warren

PHPアプリケーションが原因で問題が発生し、ソフトウェアを自分で作成した場合は、たとえば PHP Quick Profiler のようなプロファイラーを使用することをお勧めします。次に行われるデータベーストランザクションの多くは、たとえば Kontrollbase のようなソフトウェアで問題を見つけるのに役立ちます。

0