先日の本番サーバでの出来事。
データ関連のエクスポートを行うPHPのプログラムがあって、とあるクライアントが非常に大きいデータ(数十MB)をダウンロードし始めた。
この時監視していたところ、本番サーバのhttpdプロセスがメモリ(RES)を500MB程度使われていた。
まぁ、データ量がデータ量だからそんな物かと思ったのだけど、該当プロセスのCPUが0%になってもメモリがそのまま解放されない。
とりあえず、こんなプロセスがたまったらいかに本番サーバといえどもメモリが吹き飛んでサービス停止に陥る(本来はリソース計画で最大状態でも足りるように制限設定するべきなんだけど、諸事情から出来ない・・・)ので、とりあえずApacheのMaxRequestsPerChildを下げてメモリが枯渇する前に再起動するようにした;
本番データを開発環境に入れて同じリクエストを送ってみるがメモリはちゃんと解放される。
PHPの問題かと思ったのだけど、いまいちわからず。
仕方ないので、本番の直近バックアップイメージを仮想環境に立ち上げて、デバッグツールを入れて走らせると再現した。
そのでかいデータ、DEFLATEされていたのだ。 コンテンツタイプがtextだったので、OutputFilterで圧縮処理をがりがりやってたのだが、データがある程度でかいと、この時に握ったメモリが解放されない(メモリリークしてる)
開発環境はLANの帯域があるからDEFLATEしていなかった。
とりあえず、該当処理のアドレスをDEFLATEの除外条件にした。 けど、大きい物ほど圧縮したいなぁと思うわけだけど・・・
PHPのメモリを制限していても、DBに繋いで読んで出してを繰り返す場合にはPHP自身は変数(メモリ)を再利用しているからそこではメモリ消費が増えず、外のmod_deflateの中だけ増え続けちゃうから、大きいデータは別処理でちゃんと圧縮してからAttachしてダウンロードするように修正かな。
まぁ、httpdがメモリを解放してくれない場合にはmod_deflateをチェックと、メモ。
(582)