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


18

約1週間に1回ですが、何日間も正常に実行された後、1日数回でさえ、EC2インスタンスが応答しなくなります。Muninのメモリグラフは、「アプリ」に割り当てられたメモリが成長し始め、スワップが完全に使用され、インスタンスが効果的にひざまずくまで停止しません。別のカスタムグラフは、絶えず成長しているプロセスがapache2であることを示しています。

mod_phpといくつかのPHPスクリプトを使用して、標準のprefork Apacheセットアップを実行します。以下のグラフでわかるように、apache2プロセスをトリガーしてメモリの消費を開始する何かが発生します。私が間に合った最初の緑のスパイクは、物事が手に入らないうちにApacheを再起動しました。2番目のスパイクは少し遠くになり、インスタンスを完全に再起動する必要がありました。

ムニンメモリグラフ

私が疑問に思っているのは、これをどのようにデバッグするのが最善かということです。FastCGIを使用してPHPをセットアップし、独自のプロセスで実行する以外に、Apacheか、PHPとコードの組み合わせが過剰なメモリ使用の原因であるかを判断する良い方法は何ですか?この問題を追跡するためにどのような手順を取りますか?


更新:マットが以下に提案したように、私はstraceを巻き込んだ後にリークを追跡することができました。

メモリ内で徐々にそして継続的に成長しているapache2プロセスを見つけた後、PHPスクリプトにさらにいくつかのerror_log()呼び出しを追加し、実行中のさまざまなポイントで使用される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のchangelogは、7.19.5で修正されたいくつかのSSLメモリリークを参照しているため(7.18.2でした)、次に試してみます。

それまでは、Apacheを妥当な範囲内に収める非常に低いMaxRequestsPerChildで実行しています。みんな、ありがとう!


同じ期間でApacheの子プロセスの数はどのように変化しますか?
SimonJ

@SimonJサイモン、素晴らしい質問です。数はほとんど変わらず、プラスマイナス数プロセスです。サーバーに問題が発生しているとき、およびサーバーが停止しているときは、約60になります。ただし、Muninグラフを100%確実に設定します。
オンドレイ

解決策ではありませんが、アプリケーションの1つがRAMを狂ったように食べることがわかっている場合は、スワップをオフのままにしておくことをお勧めします。スワップが有効になっている場合、スワップはRAMよりもずっと遅いため、カーネルはいくつかのプロセスをかなり後で終了します。スワップなし-リカバリの高速化、ダウンタイムの短縮。(8GiB RAMを搭載したマシンで同様のケースでスワップを無効にしようとしただけです。YMMWです。)
クロノス

回答:


5

WHATが問題を引き起こしているのを突き止めることは、お尻の痛みになる可能性があります。そのような問題が発生した場合に最初に行うことはMaxRequestsPerChild、極端に低い数(〜100-200 )に減らし、それが違いを生むかどうかを確認することです。もしそうなら、おそらくどこかのループでメモリをリークしているコードがあり、コード監査を実行したいと思うでしょう。

もう1つ注目すべき点は、Apacheのfullstatusです。特定の要求がメモリリークを引き起こしていることを確認できるかどうかを確認してください。疑わしいプロセスのPIDを取得し、それらに対してstraceを実行します。


ありがとう、マット。'ps aux | grep apache2 'は、アクティブな60個ほどのプロセスのうち、約12個が必要以上のメモリ(RSSで100MB以上)を使用していることを示しています。/ proc / <pid> / smapsの出力を見たところ、それぞれが95%以上のスペースを占める匿名マッピングを1つだけ持っていることがわかりました。私は今、この巨大なメモリチャンクを何をいつ割り当てたかを把握しようとしています。straceについて見ていきます。ヒントをありがとう。
オンドレイ

2

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

最初、私はどうなる事は、利用可能なRAMを超えることはできませんので、$ procmem * $ procsのことのapacheにMaxRequestsのための合理的な制限を設定し、各procがかかったMEMを計算することであろう。OOMは魔女狩りを開始するため、インスタンスを再起動する必要があると思われます。あなた、境界内に留まり、スワップに行くのではなく、OOMではないことにより、ボックスがこれらの重い時間を処理できることを確認する必要があります。これは、cronジョブを実行している場合は難しく、実行するのが安全であることを確認せずにcronジョブを無条件に実行する場合は非常に困難です(つまり、5分ごとにスクリプトが最後の5分スクリプトがまだ実行中かどうかのチェックに失敗します)。

物事が非常にうまくいかなくても、ボックスを再起動する必要がないことを確認できたので、物事はあなたにとってずっと良くなり始めます。これらの重い時間の間にログインし、top、dstat、free -m、iostatなどを使用して何が起こっているかを知ることができます。

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


0

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

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

他のどのコンポーネント/パッケージが参照していますか?

あなたのパッケージは最新ですか?

httpd.confファイルに特定のパフォーマンスに関連するものはありますか?


0

問題の原因がPHPアプリケーションであり、ソフトウェアを自分で作成した場合は、PHP Quick Profilerなどのプロファイラーを使用することをお勧めします。大量のデータベーストランザクションが発生している場合、Kontrollbaseなどのソフトウェアを使用すると、そこで問題を見つけることができます。


ラファエル、ありがとう。はい、PHPアプリは私のものであり、SQLデータベースにはヒットしません。PHP Quick Profilerを試して報告します。
オンドレイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.