Назад | Перейти на главную страницу

Httpd-процесс, потребляющий много памяти

У меня есть сервер, который вызывает у меня головную боль. На нем размещено несколько сайтов: они основаны либо на php, либо на java. У меня есть установка, которая использует apache2 + suPhp для сайтов php и apache2 + mod_proxy + apache tomcat для приложений java.

За последние несколько недель я наблюдал какое-то странное поведение. Иногда я получаю один процесс httpd, который достигает 30-40% процессора и более 70% памяти. Я не вижу, чтобы какой-либо процесс php или java занимал дополнительные ресурсы, поэтому я (наивно) предполагаю, что проблема не связана с кодом php или java. Эти всплески, кажется, происходят в случайное время и со случайными интервалами; иногда несколько раз в день, иногда в течение целой недели ничего не происходит.

Еще одна странная вещь, которую я заметил, это то, что когда я вручную kill -9 Если запущен процесс httpd, в течение нескольких секунд появляется другой процесс httpd, который также начинает занимать много памяти и процессора. Я могу повторить это несколько раз, пока это не перестанет происходить само по себе: /

Итак, у меня на самом деле есть несколько вопросов:

  1. Есть ли у кого-нибудь советы, как мне отследить причину такого поведения? В конечном счете, я хотел бы увидеть, какой запрос вызывает эти проблемы. Я просмотрел журналы доступа и ошибок httpd и не нашел ничего необычного. Я совсем не знаком с исследованием этого типа проблем, поэтому даже вещи, которые могут показаться вам очень очевидными, могут помочь.
  2. Есть ли способ ограничить количество ресурсов, которые может потреблять один дочерний процесс httpd? Или просто убить его, когда он перейдет в определенный объем памяти?
  3. В связи с предыдущим вопросом, могу ли я, возможно, настроить oom-daemon так, чтобы он был более управляемым для процессов httpd и меньше - для других процессов? Я спрашиваю, потому что, пока я не найду достойное решение, я хотел бы убедиться, что он перестанет убивать мой Java-процесс, когда процессы httpd снова начнут действовать.

ОБНОВИТЬ

Недавно я узнал, что запрос, вызывающий этот беспорядок, исходит от googlebot. Это отрывок из вывода lsof для процесса, потребляющего всю доступную память и процессор:

httpd   18588 nobody   37u  IPv6 96675092               TCP myhost.com:http->crawl-66-249-76-96.googlebot.com:56730 (ESTABLISHED)

Я настроил mod_security, чтобы регистрировать все запросы, поступающие из диапазона IP-адресов, который, похоже, используют роботы Google с этим правилом в моем <VirtualHost>:

SecRule REMOTE_ADDR "@ipMatch 66.249.76.0/24" phase:1,id:1,auditlog,allow

Я оставил сервер в таком виде на время. За это время процесс httpd увеличился несколько раз, до такой степени, что демон OOM начал убивать процессы (httpd, java, теперь он даже время от времени отключает mysql). Затем я извлек все URL-адреса, по которым работает googlebot, и создал небольшой скрипт, который скрутил все эти URL-адреса, надеясь, что я смогу вызвать всплеск процесса httpd и, таким образом, найти запрос, вызывающий эти проблемы.

К сожалению, этого не произошло - все запросы возвращались быстро, а использование процессора и памяти было далеко от того, что было, когда робот googlebot попадает на сервер.

Итак, я думаю, есть 2 возможности:

  1. Проблема связана с определенным заголовком HTTP. Мой сценарий не копирует их, он просто использует простой завиток без дополнительных заголовков.

  2. Запрос, вызывающий проблемы, не регистрируется. Насколько я могу судить, этого не должно быть, поскольку я говорю mod_security регистрировать запрос на этапе 1, который происходит до того, как apache фактически обработает запрос.

У кого-нибудь есть другие идеи?


ОБНОВЛЕНИЕ 2:

strace вывод процесса:

brk(0x3568c000)                         = 0x3568c000
brk(0x356ca000)                         = 0x356ca000
brk(0x35708000)                         = 0x35708000
brk(0x35746000)                         = 0x35746000
brk(0x35784000)                         = 0x35784000
brk(0x357c2000)                         = 0x357c2000
brk(0x35800000)                         = 0x35800000
brk(0x3583e000)                         = 0x3583e000
...
brk(0x3587c000)                         = 0x3587c000
brk(0x358ba000)                         = 0x358ba000
brk(0x358f8000)                         = 0x358f8000
brk(0x35936000)                         = 0x35936000
brk(0x35974000)                         = 0x35974000
brk(0x359b2000)                         = 0x359b2000
brk(0x359f0000)                         = 0x359f0000
brk(0x35a2e000)                         = 0x35a2e000
brk(0x35a6c000)                         = 0x35a6c000
brk(0x35aaa000)                         = 0x35aaa000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f2028000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f2005000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1fe2000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1fbf000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f9c000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f79000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f56000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f33000
...
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f10000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1eed000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1eca000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1ea7000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1e84000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1e61000
mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1e3e000
+++ killed by SIGKILL +++

Заранее спасибо.

Наконец нашел ответ. Оказывается, на одном из сайтов, которые мы размещаем, где-то был спрятан теневой .htaccess с RewriteRule, который в некоторых случаях запускает бесконечный цикл.

Первое: вы должны ограничить максимальное количество запускаемых процессов apache. Это можно сделать, опустив MaxSpareServers. Начните с низкого уровня (3-10 и увеличивайте его alitle bit, пока производительность не начнет падать). MinSpareServers должно быть 2.

PHP обычно работает как модуль apache (mod_php), это означает, что он работает в том же адресном пространстве, что и apache, я имею в виду, что вы увидите только процесс apache, а внутри также будет запускаться php. Вы можете запустить gdb на этих процессах и запустить backtrace внутри gdb чтобы увидеть, что они делают. Ты можешь использовать pstack для этого тоже. Если вы заметили, для какого URL-адреса это происходит (проверьте access.log, чтобы узнать URL-адрес), вы можете начать отладку кода php. Найдите отладчик php и / или профилировщик php.

Я не вижу, чтобы какой-либо процесс php или java занимал дополнительные ресурсы

То, что, по вашему мнению, стоит вообще проверить, говорит о том, что вы либо очень много знаете об уязвимостях CGI, либо очень мало знаете о веб-обслуживании / управлении процессами.

В конце концов, я хотел бы узнать, какой запрос вызывает эти проблемы.

Это разумное место для начала. Самым простым решением было бы установить mod_security и настроить его для регистрации входящих запросов (Apache регистрирует только в точке отправки ответа). Существуют и другие подходы, такие как анализ трафика (pastMon, Wireshark) или вход на обратный прокси-сервер.

Есть ли способ ограничить количество ресурсов, которые может потреблять один дочерний процесс httpd

Не напрямую, но вы должны установить LimitInternalRecursion, LimitRequestBody, LimitRequestFields, LimitRequestFieldSize, LimitRequestLine, MaxKeepAliveRequests, MaxRequestsPerChild и Timeout на разумные значения.

Могу ли я, возможно, настроить oom-daemon, чтобы он был более успешным в процессах httpd

Избавиться от убийцы OOM - почти всегда плохая идея. Даже если вы думаете, что знаете, что делаете. Делаете ли вы Java что-нибудь полезное при отсутствии веб-сервера? Если да, то, возможно, вам стоит подумать о запуске их на отдельных машинах.