Главная » Локализация внутренних проблем Apache
Веб-сервер Apache установлен на большинстве серверов в мире. Еговыбирают из-за отличной настраиваемости, расширяемости и превосходнойфункциональности. Однако большое количество модулей и, к сожалению, невсегда качественно написаные приложения порождают проблемы, которыебывает непросто решить. Поэтому очень важно иметь под рукойинструментарий для быстрой локализации и устранения неполадки. В этойстатье я постараюсь помочь вам.

Запустите сервер в единственном экземпляре
Другими словами, запретите ему форкаться smile
При локализации причины сбоя это самый первый и необходимый шаг. Обычноapache порождает несколько своих копий при запуске, которые ожидаютзапросов от пользователей. Запуск сервера в единственном экземпляреоблегчит отладку. Есть два способа запустить “одиночный” сервер: первыйзаключается в ручном изменении количества форков и нитей вконфиг-файле. Второй проще, можно запустить сервер с опцией “-X”# httpd -XВ таком режиме работы сервер не порождает новых форков и не теряетсвязи с родительским терминалом. Благодаря этому все коммуникации идутчерез один процесс, к которому легко можно подключить какой-нибудьотладчик (например, gdb)Проверка конфигурационного файла
Для некоторых веб-проектов конфигурационные файлы Apache разрастаются вгеометрической прогрессии и локализовать ошибки в них становится всетруднее. Сам сервер предлагает два способа решения этой проблемы.Первый - это запуск сервера с ключом -t, который активирует проверку конфигурационного файла:$ httpd -t -c httpd.conf
Syntax error on line 236 of /etc/httpd/httpd.conf: LogLevel requireslevel keyword: one of emerg/alert/crit/error/warn/notice/info/debugЕсли ошибка найдена, то apache предложит возможные способы ееустранения. В приведенном примере неверно задано значение для директивыLogLevel.
Если проверка говорит, что с конфигами все в порядке, но сервер, тем неменее, не стартует, то можно включить вывод более подробной информациив error_log: для этого установите директиву LogLevel в значение Debug вконфигурационном файле.Отладка cgi-сценариев
Apache позволяет выполнять сценарии, написанные практически на любомязыке, при помощи mod_cgi. Эти сценарии могут формировать динамическийконтент по запросу клиента. Но вот локализация ошибок в подобныхпрограммах может стать не очень тривиальной задачей.
Один из способов отладки таких скриптов - это директива ScriptLogмодуля mod_cgi. Когда директива активирована, то сервер записывает влог-файл вывод любого скрипта, работа которого завершилась неудачно.Вывод включает в себя код ответа сервера, запрос от клиента и ответклиенту (если он имел место быть). Это великолепный отладочныйинструмент для сценариев, которые не пишут ошибки в “традиционный”error_log или для быстрого выяснения проблемы, когда “что-то неработает”
Для активирования логирования CGI-скриптов необходимо добавитьдирективу ScriptLog и указать расположение лог-файла в конфигурационномфайле Apache. Когда логирование включено, mod_cgi пишет примерно воттакие логи:%% [Tue Dec 26 14:47:21 2006] GET /cgi-bin/print HTTP/1.1
%% 500 /var/tmp/apache/cgi-bin/print
%request
Accept: */*
Accept-Language: en
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3
Connection: keep-alive
Host: 192.168.1.3:8080
%response
Script /cgi-bin/print
%stdout
Script Location /var/tmp/apache/cgi-bin/printДля нагруженных веб-сайтов или нехватке дискового пространстваразмер лога можно ограничивать с помощью директивы ScriptLogLengthОтладка запросов и ответов
При поддержке веб-приложений необходимо четко локализовать местоошибки: это может сервер приложений, прокси-сервер или же самвеб-сервер. Для облегчения этого процесса хорошо помогает полный дампдиалога сервера с клиентом (то есть все запросы клиента и ответысервера). Модуль mod_dumpio предназначен как раз для записи заголовковзапроса и ответа в error_log. Настройка mod_dumpio выполняется оченьбыстро и просто: для логирования запросов директива DumpIOInput должнабыть установлена в значение On; для логирования ответов установите в Onдирективу DumpIOOutput. Когда логирование активно, то в error_logпоявятся примерно вот такие строки:Sat Oct 28 10:52:31 2006] [debug] mod_dumpio.c(103): mod_dumpio: dumpio_in [getline-blocking] 0 readbytes
[Sat Oct 28 10:52:31 2006] [debug] mod_dumpio.c(51): mod_dumpio: dumpio_in (data-HEAP): 16 bytes
[Sat Oct 28 10:52:31 2006] [debug] mod_dumpio.c(67): mod_dumpio: dumpio_in (data-HEAP): GET / HTTP/1.1rn
Модуль mod_dumpio создает небольшую дополнительную нагрузку приобработке запросов и включение/выключение директив потребует егоперезапуска. Вы можете мягкую перезагрузку (graceful restart) чтобы непотерять активных соединений.Локализация причин “зависания” сервера
Apache прекрасно оттестирован, но, тем не менее, ошибки все равно есть.Они могут выражаться в “подвисаниях” сервера, внезапных остановках илив неверном контенте, переданном пользователю. Когда случаются подобныеситуации, главное - это быстро найти модуль, который вызвал ошибку.
Один из способов локализации ошибок такого рода - это просмотр стекавызовов подвисшего процесса. Стек вызовов содержит список функций,вызванных до той, которая породила ошибка. После зависания вам,вероятно, захочется узнать имя некорректно работающей функции, хотя быдля того, чтобы использовать его в качестве аргумента при поиске ошибкив багтрекерах и в качестве отправной точки при анализе кода сбойногомодуля.Одна из утилит, позволяющих получить такой стек, называется pstack. Она возвращает стек вызовов для процесса, номер которого передается ей в качестве аргумента.$ pstack 1875618756: bin/httpd -k start
ff040628 accept (3, 11c560, 11c54c, 1)
0004c3c4 unixd_accept (ffbff904, 7d490, 11c3a0, 0, 2710, 0) + 10
0004a3c0 child_main (7d490, 74400, 4e2e, 74000, 0, 74000) + 2ec
0004a6c8 make_child (4a000, 0, 1, 5, 72c00, 74000) + ec
0004b0e8 ap_mpm_run (72c00, 74000, 74000, 74000, 74000, 74400) + 934
000272d8 main (7ef18, 71c00, 73800, 73800, 0, 0) + 710
00026618 _start (0, 0, 0, 0, 0, 0) + 5cНа платформах, где нет pstack можно воспользоваться утилитами gdb и gcore для получения стека вызовов. Для подключения к процессу напрямую и получению стека вызовов gdb должен быть запущен с ключом -p, идентификатором процесса и вызовом backtrace уже внутри оболочки отладчика#0 0?0046e7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1 0?0063b681 in accept () from /lib/tls/libpthread.so.0
#2 0?00b14814 in apr_socket_accept (new=0xbff85740, sock=0?9671538,
connection_context=0?97115d8) at network_io/unix/sockets.c:187
#3 0?080819ce in unixd_accept (accepted=0xbff85774, lr=0?9671518, ptrans=0?97115d8) at unixd.c:466
#4 0?0807fd2e in child_main (child_num_arg=Variable “child_num_arg” is not available.) at prefork.c:621
#5 0?0807ffc2 in make_child (s=Variable “s” is not available.) at prefork.c:736
#6 0?08080050 in startup_children (number_to_start=5) at prefork.c:754
#7 0?0808089b in ap_mpm_run (_pconf=0?96730a8, plog=0?96a1160, s=0?9674f48) at prefork.c:975
#8 0?08061b08 in main (argc=3, argv=0xbff85a84) at main.c:717Каждый дамп стека вызовов содержит несколько фрагментов отладочнойинформации, однако для полноценного устранения проблемы необходимобОльшее количество информации и выборочный дамп структур данныхсервера. Это может оказаться неприемлемым для проектов, не позволяющихдаже кратковременных остановок. В этом слкчае на помощь приходитутилита gcore. Она может сгенерировать core-файл для зависшегопроцесса, который может быть использован для анализа ситуациисистемными администраторами и производителями операционных систем. Впримере показано использование gcore для получения core-файла ииспользование gdb для анализа полученной информации:$ gcore 5649
$ gdb -q /usr/sbin/httpd core.5649 (gdb) backtrace#0 0?0046e7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1 0?0063b681 in accept () from /lib/tls/libpthread.so.0
#2 0?00b14814 in apr_socket_accept (new=0xbff85740, sock=0?9671538,
connection_context=0?97115d8) at network_io/unix/sockets.c:187
#3 0?080819ce in unixd_accept (accepted=0xbff85774, lr=0?9671518, ptrans=0?97115d8) at unixd.c:466
#4 0?0807fd2e in child_main (child_num_arg=Variable “child_num_arg” is not available.) at prefork.c:621
#5 0?0807ffc2 in make_child (s=Variable “s” is not available.) at prefork.c:736
#6 0?08080050 in startup_children (number_to_start=5) at prefork.c:754
#7 0?0808089b in ap_mpm_run (_pconf=0?96730a8, plog=0?96a1160, s=0?9674f48) at prefork.c:975
#8 0?08061b08 in main (argc=3, argv=0xbff85a84) at main.c:717В приведенных выше примерах можно увидеть, что выполнялась функцияaccept(), когда был получен системный сигнал SIGSEGV, которая, в своюочередь, была вызвана из метода apr_socket_accept(). Если эта проблемаизвестна и описана, то выможете использовать эту информацию для поискапо базам данных ошибок. Для более подробной информации обратитесь кофициальной документации.Локализация причин аварийных остановок сервера
Если процесс Apache аварийно завершился, то pstack и gcore будутбесполезны, так как процесс уже завершен. Теоретически, core-файлдолжен записываться в директорию, определенную в ServerRoot, но упользователя, под которым запущен сервер, должны быть права на запись вэту директорию, должно быть достаточное количество дисковогопространства. Если политики безопасности запрещают запись в ServerRoot,то можно определить местоположение core-файла при помощи директивыCoreDumpDirectoryНа некоторых платформах нет возможности автоматически генерироватьcore-файл. Если вы используете именно такую платформу, то вам поможетмодуль mod_backtrace. Этот модуль срабатывает при получении любогосигнала, останавливающего работу приложения (например SIGSEGV, SIGBUSитд.) При получении подобного сигнала mod_backtrace вызываетплатформо-зависимую функцию для генерации стека вызовов и пишет его вerror_log.Этот модуль распространяется в исходных кодах и может быть загружен с сайта Apache$ wget http://people.apache.org/~trawick/mod_backtrace.cДля установки и подключения модуля утилита Apache apxs c ключом -c для сборки модуля и с ключом -i для его установки.$ apxs -ci mod_backtrace.cДля использования mod_backtrace apache должен быть собран споддержкой ExceptionHook. Для этого можно указать“–enable-exception-hook” при сборке сервера. Когда модуль установлен,загружен и exception hook активен, то активировать модуль можно припомощи директивы LoadModule и установки директивы EnableExceptionHook взначение On:LoadModule backtrace_module modules/mod_backtrace.so
EnableExceptionHook OnПосле активации модуля при получении сервером критического сигнала в error_log окажутся похожие строки:$ kill -SIGSEGV 18745[Wed Dec 20 16:48:32 2006] pid 18745 mod_backtrace backtrace for sig 11 (thread “pid” 18745)
[Wed Dec 20 16:48:32 2006] pid 18745 mod_backtrace main() is at 26bc8
/var/tmp/apache/modules/mod-backtrace.so:bt_exception_hook+0?108
/var/tmp/apache/bin/httpd:ap_run_fatal_exception+0?34
/var/tmp/apache/bin/httpd:0?32788
/lib/libc.so.1:0xc01dc
/lib/libc.so.1:0xb52d4
/lib/libc.so.1:_so_accept+0?8 [ Signal 11 (SEGV)]
/var/tmp/apache/bin/httpd:unixd_accept+0?10
/var/tmp/apache/bin/httpd:0?3a3c0
/var/tmp/apache/bin/httpd:0?3a6c8
/var/tmp/apache/bin/httpd:0?3a798
/var/tmp/apache/bin/httpd:ap_mpm_run+0?9d4
/var/tmp/apache/bin/httpd:main+0?710
/var/tmp/apache/bin/httpd:_start+0?5c
[Wed Dec 20 16:48:32 2006] pid 18745 mod_backtrace end of backtracemod_backtrace использует backtrace() на GNU системах и printstack()на платформах Solaris для получения корректного стека вызовов. Внекоторых случаях дамп может содержать некорректные символы. В этомслучае вам помогут утилиты nm, readelf и elfdump. Для использования mod_backtrace на хостах с Solaris на него необходимо наложить патч (ссылка на патч приведена в конце статьи)Отладка в “режиме разработчика” и макросы gdb для apache
Отладка на основе core-файлов - это искусство, требующее недюжинныхзнаний отлаживаемого кода и технологий его написания и сопровождения.Разработчики Apache это понимают и поэтому они реализовали несколькоотличных инструментов для отладки сервера и включили два ключевыхприема отладки в сервер. Первый - это так называемый “режимразработчика” (maintainer mode). Для его активации необходимо собратьсервер с ключом –enable-maintainer-mode. Этот режим включает отладочнуюинформацию для всех функций сервера, в нем отсутствует оптимизация иисходный код на С может быть показан при помощи дебаггера.Второй ключевой момент - это gdb-макросы. С их помощью можно увидетьсодержмое сложных структур данных apache (например цепочек фильтров),эти сведения очень полезны при анализе core-файлов, полученных послесбоя сервера. Эти макросы находятся в файле .gdbinit, которыйрасположен в корневой директории с исходными кодами сервера. Если выхотите больше узнать о этих макросах, то в конце статьи приведеныссылки.Использование исходного кода Apache для устранения проблем
Когда анализ лог-файлов, core-файлов и использование системных утилитне приносит результатов, можно обратиться напрямую к исходным кодамсервера. Исходный код помещен в четкую иерархическую структуру и каждыйкаталог содержит код конкретного объекта. В релизе 2.2.3 в деревесодержатся следующие каталоги:$SRCROOT/server - ядро сервера$SRCROOT/include - заголовочные файлы$SRCROOT/srclib/apr - окружение среды выполнения$SRCROOT/srclib/apr-util - утилиты среды выполнения$SRCROOT/support - утилиты$SRCROOT/modules - модулиЕсли стек вызовов или сессия отладки показывают на проблему соспецифичной функцией, то можно найти ее описание в дереве исходныхкодов при помощи утилиты find$ find . -name *.h | xargs egrep “apr_array_make”./srclib/apr/include/apr_tables.h:APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, …
После того, как описание найдено, при помощи find и grep можно найти и ее определение:$ find . -name *.c | xargs egrep “apr_array_header_t.*apr_array_make”/srclib/apr/tables/apr_tables.c:APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, …
В приведенном пример прототип функции находится в файлеapr_tables.h, а описание в apr_tables.c. Но помните, что в зависимостиот того, что вы ищете (функцию или макрос) результаты поиска могутпотребовать дополнительной обработки.

Категория: Интересные статьи | Просмотров: 482