У меня есть сервер, который вызывает у меня головную боль. На нем размещено несколько сайтов: они основаны либо на php, либо на java. У меня есть установка, которая использует apache2 + suPhp для сайтов php и apache2 + mod_proxy + apache tomcat для приложений java.
За последние несколько недель я наблюдал какое-то странное поведение. Иногда я получаю один процесс httpd, который достигает 30-40% процессора и более 70% памяти. Я не вижу, чтобы какой-либо процесс php или java занимал дополнительные ресурсы, поэтому я (наивно) предполагаю, что проблема не связана с кодом php или java. Эти всплески, кажется, происходят в случайное время и со случайными интервалами; иногда несколько раз в день, иногда в течение целой недели ничего не происходит.
Еще одна странная вещь, которую я заметил, это то, что когда я вручную kill -9
Если запущен процесс httpd, в течение нескольких секунд появляется другой процесс 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 возможности:
Проблема связана с определенным заголовком HTTP. Мой сценарий не копирует их, он просто использует простой завиток без дополнительных заголовков.
Запрос, вызывающий проблемы, не регистрируется. Насколько я могу судить, этого не должно быть, поскольку я говорю 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 что-нибудь полезное при отсутствии веб-сервера? Если да, то, возможно, вам стоит подумать о запуске их на отдельных машинах.