Как определить причину явной утечки памяти в моем веб-приложении на основе Apache / PHP?

18

Примерно раз в неделю, но иногда даже пару раз в день после нескольких дней работы мои экземпляры EC2 перестают отвечать на запросы. Графики памяти Мунина рассказывают довольно простую историю: объем памяти, выделяемой для «приложений», начинает расти и не останавливается до тех пор, пока не будет полностью использован обмен, и экземпляр фактически не опустится на колени. Другой пользовательский график показывает, что постоянно растущий процесс - apache2.

Я запускаю стандартную предварительную установку Apache с mod_php и несколькими PHP-скриптами. Как вы можете видеть на графике ниже, происходит что-то, что запускает процессы apache2, чтобы начать потреблять все больше и больше памяти. Первый зеленый шип, который я вовремя поймал и перезапустил Apache, прежде чем все вышло из-под контроля. Второй всплеск стал немного дальше, и экземпляр пришлось перезагрузить сразу.

График памяти Мунина

Что мне интересно, так это как лучше отладить это. Если не считать настройку PHP с FastCGI и запуск его в собственных процессах, какой хороший способ выяснить, является ли Apache или комбинация PHP и моего кода причиной чрезмерного использования памяти? Какие шаги вы бы предприняли, чтобы отследить эту проблему?


ОБНОВЛЕНИЕ: я был в состоянии отследить утечку после того, как вмешался strace, как предложил Мэтт ниже.

После нахождения процесса apache2, который постепенно и непрерывно рос в памяти, я добавил еще несколько вызовов error_log () к моему PHP-скрипту, который распечатывал общее количество RSS, использованное в различных точках его выполнения (используя вывод ps). Это, однако, оказалось обманчивым - в то время как казалось, что RSS скачал только после того, как мой сценарий был выполнен, более поздняя отладка показала, что это действительно не так. Быть осторожен!

К счастью, все эти вызовы error_log () оказались полезными в конце. Когда я запустил strace ( strace -p <pid> -tt -o trace.log -s 256), я увидел, что для каждого запроса процесс выделял около 400 КБ памяти (найдите системный вызов 'brk' и вычтите параметр первого вызова из последнего вызова - некоторые обычно приходят в одном за другим). Затем я искал самый последний системный вызов 'write', содержащий мое сообщение об ошибке error_log (), в котором говорилось, в какой точке сценария выделяется память. С помощью нескольких более стратегически размещенных вызовов error_log () для более точного определения местоположения я наконец нашел виновника.

Утечка памяти, когда мы вызвали curl_exec () из нашего PHP-скрипта. Некоторый код, связанный с обработкой SSL-соединения, делает что-то не так - утечка исчезла, когда я переключился на HTTP. Список изменений в Curl ссылается на несколько утечек памяти SSL, которые были исправлены в 7.19.5 (мы были на 7.18.2), поэтому я попробую это позже.

Тем временем я работаю с очень низким MaxRequestsPerChild, который держит Apache в разумных пределах. Спасибо всем!

Ондрей
источник
Как число дочерних процессов apache изменяется за один и тот же период?
SimonJ
@ SimonJ Саймон, отличный вопрос, число остается примерно таким же, плюс минус несколько процессов. Оно колеблется около 60, когда у серверов возникают проблемы, а также когда они находятся в состоянии покоя. Я настрою график Мунина, чтобы быть уверенным на 100%.
Ондрей
Не решение, но если известно, что одно из приложений потребляет оперативную память как сумасшедшую, то лучше не включать подкачку: когда ядро ​​обнаруживает недостаток ОЗУ, оно убивает самые большие объемы памяти (apache). Если включен режим подкачки, ядро ​​будет убивать некоторые процессы намного позже, поскольку подкачка происходит намного медленнее, чем ОЗУ. Нет свопа - быстрое восстановление, меньшее время простоя. (Я пытался отключить swap в аналогичном случае на машине с 8 ГБ ОЗУ, так что YMMW.)
хронос

Ответы:

5

Отслеживание того, ЧТО вызывает проблему, может быть болью в заднице. Первое, что я бы сделал, если бы у меня возникла такая проблема, это уменьшил бы MaxRequestsPerChildдо агрессивно низкого числа (~ 100-200) и посмотрел бы, имеет ли это значение. Если это произойдет, то у вас, вероятно, есть код, который пропускает память в цикле где-то, и вы захотите запустить аудит кода.

Еще одна вещь, на которую стоит обратить внимание, это полный статус Apache, посмотрим, сможете ли вы выяснить, какой именно запрос вызывает утечку памяти. Получите идентификаторы PID для ваших подозрительных процессов и установите их.

матовый
источник
Спасибо Мэтт. 'ps aux | grep apache2 'говорит мне, что из 60 или около того активных процессов около дюжины используют намного больше памяти, чем должны (> 100 МБ в RSS). Я посмотрел на вывод / proc / <pid> / smaps и обнаружил, что у каждого есть ровно одно анонимное отображение, которое занимает 95% + пространства. Я сейчас пытаюсь выяснить, что и когда выделил этот огромный кусок памяти. Я посмотрю на strace - спасибо за совет.
Ондрей
2

Пятница ровно в 11 вечера? Это соответствует времени резервного копирования? Имеется ли в вашей системе система ввода-вывода для обслуживания процессов и резервных копий в это время? Тенденции в программном обеспечении также отражают тенденции # процедур или даже табло Apache, как насчет дискового ввода-вывода?

Первое , что я хотел бы сделать было бы подсчитать , сколько мем каждый прок принимает, а затем установить разумный предел для MaxRequests в апача , так что $ procmem * $ прока не может превышать доступной памяти. Я подозреваю, что ваш экземпляр должен быть перезагружен, потому что OOM начинает охоту на ведьм, которая, вероятно, (часто) не очень плодотворна. Вы должны убедиться, что ваш ящик может выдержать эти тяжелые времена, не выходя за рамки и, конечно же, не OOM. Это сложнее, если у вас есть cronjobs, и чрезвычайно сложно, если указанные cronjobs запускаются в одностороннем порядке, не убедившись, что они безопасны для выполнения (т. Е. Скрипт каждые 5 минут не может проверить, работает ли последний 5min).

Теперь, когда вы убедились, что даже если что-то пойдет не так, вам не нужно будет перезагружать свою коробку, все станет намного лучше для вас. В эти тяжелые времена вы сможете войти в систему и получить представление о том, что происходит, используя top, dstat, free -m, iostat и т. Д.

Метод Мэтта, возможно, стоит попробовать, но его следует использовать только в качестве инструмента для устранения неполадок, я не рекомендую придерживаться его таким образом, поскольку в следующий раз вам будет гораздо сложнее найти общую проблему. Тем не менее, это будет действительно выявлять проблемы с apache / modules, а не что-нибудь в вашем коде. Я думаю, вы согласитесь, что шансы хорошие, это не какая-то утечка памяти в модуле apache (при условии, что вы используете авторитетный дистрибутив).

fimbulvetr
источник
0

Первый вопрос, который нужно задать, это то, что приложение работает через Apache?

Это тот, который вы написали, или стороннее приложение?

На какие другие компоненты / пакеты он ссылается?

Вы в курсе ваших пакетов?

Что-нибудь конкретное в ваших httpd.confфайлах связано с производительностью?

кроличий садок
источник
0

Если ваша проблема вызвана приложением PHP, и если вы написали программное обеспечение самостоятельно, я рекомендую вам использовать профилировщик, например, PHP Quick Profiler . Если у вас много транзакций с базой данных, то такое программное обеспечение, как, например, Kontrollbase, может помочь вам найти проблему там.

Рафаэль Лютигер
источник
Рафаэль, спасибо. Да, приложение PHP мое, и оно не затрагивает базы данных SQL. Я сделаю снимок PHP Quick Profiler и сообщу.
Ондрей