約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で実行しています。みんな、ありがとう!