(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Стабилизируем PHP на бою - что и почему "роняет" веб-сервер

Источник: habrahabr
AlexSerbul

Вы отвечаете за стабильность работы веб-проекта на PHP. Нагрузка постоянно растет, добавляются фичи, клиенты довольны. В один прекрасный день начинают появляться загадочные ошибки… 

Ошибки серверного софта


… которые программисты не знают как исправить, т.к. "ломается" серверный софт, например связка apache-PHP - а клиент получает в ответ на запрос страницу о регламентных работах. Веб-разработчик часто не обладает глубокими знаниями в программировании на C в unix/linux, а сисадмин нередко, к сожалению, глубже bash в систему не погружается. Настоящий хардкор :-)

Нестабильная работа серверных скриптов


Нередко, определенные страницы веб-проекта начинают сходить с ума. Например выполняться по 15 минут и выяснить, чем же они занимаются, непросто. В прошлом посте на данную тему я описал одну из методик определения, чем занимается PHP-скрипт на боевом сервере, но чувствуется, что нужен более мощный инструмент. 

На практике я часто встречаю проекты, которые сталкиваются с подобным классом ошибок "серверного софта", и в команде не всегда знают, что делать. В логе apache часто появляются сообщения о нарушении сегментации (segmentation fault), клиенты получают страницу об ошибке, а веб-разработчик с сисадмином ломают себе голову, играются с разными версиями PHP/apache/прекомпилятора, собирают PHP из исходников с разными опциями снова и снова, пишут о багах, а им доказывают, что это баги не PHP, а их кода и так до бесконечности…

В статье я хочу рассказать как можно просто и быстро найти причину, почему PHP рассыпался на боевом сервере и устранить ее - не погружаясь в прекрасный мир системного программирования на C для unix :-) От вас потребуется желание и одна чашечка кофе.



Смотрим в лог ошибок веб-сервера


Если в логе ошибок apache вы видите что-то подобное, то статья для вас:
[Mon Oct 01 12:32:09 2012] [notice] child pid 27120 exit signal Segmentation fault (11) 

В данном случае бесполезно искать подробную информацию в логе ошибок PHP - ведь грохнулся сам процесс, а не скрипт. Если заранее не сделать на nginx симпатичную страничку о регламентных работах, то клиенты увидят аскетичную ошибку "50*".

Хочется дать кому-нибудь в морду, но кому? :-) Чтобы отвлечься от деструктивных решений, вспомним теорию.

Что такое "signal"? Это, можно сказать, средство, которое операционная система использует, чтобы сказать процессу, что он, например, не прав :-) Берет и, нарушая законы математики, делит на… 0, или насильственными действиями вызывает переполнение стека. В данном случае мы видим сигнал с номером 11 и названием "SIGSEGV". Список сигналов можно посмотреть, выполнив "kill -l":
... 11) SIGSEGV ... 

Некоторые сигналы, например SIGSEGV - нельзя перехватить, поэтому ваш процесс apache-PHP будет безжалостно убит ядром без суда и следствия. Оказывается именно его перехватить - можно, но нужно лезть в исходники :-)

А за что убили то?


Теперь найдем причину, за что же убили процесс apache-PHP? Для этого нужно настроить создание дампа памяти процесса в момент убийства :-) или coredump. Да, да - до сих пор используется устаревший лет эдак на 50 термин, означающий сохранение данных с магнитных сердечников. Как только в следующий раз процесс будет убит операционной системой, будет ядром создан файл - место и его название можно настроить. Если вы в консоли, просто наберите "man 5 core".

Например, можно складывать файлы в папочку так:
echo "/tmp/httpd-core.%p" > /proc/sys/kernel/core_pattern

Если ничего не задать, система создаст файл с именем "core.#process_number#" в рабочей директории процесса.

Только проследите, чтобы процесс apache-PHP имел туда право записи.

Это еще не всё. По-умолчанию, скорее всего, в вашей системе отключена генерация coredump-файлов. Ее можно включить, вставив в начало скрипта запуска веб-сервера строку:
ulimit -с unlimited
или, чтобы сделать настройку постоянной, отредактировать файлик "/etc/security/limits.conf". Туда можно вставить:
apache - core -1 
Подробности по формату файла - " man limits.conf".

Однако, пока я для apache не настроил папку для coredump-файлов, ничего не работало("/etc/httpd/conf/httpd.conf"):
CoreDumpDirectory /tmp 

Теперь перезапускаем апач:
service httpd restart 

Тестируем. Вручную убьем процесс:
ps aux / grep httpd

kill -11 12345

Смотрим в "/var/log/httpd/error_log":
[Mon Oct 01 16:12:08 2012] [notice] child pid 22596 exit signal Segmentation fault (11), possible coredump in /tmp 

В "/tmp" теперь найдем файлик с названием типа "/tmp/httpd-core.22596"

Вы научились получать дамп памяти убитого процесса. Теперь ждем, когда процесс будет убит естественным образом.

На месте преступления - толкуем coredump


Важно знать, что если PHP собрана без отладочных символов (ключик --enable-debug, -g для gcc при компиляции) - мы потеряем много полезной информации. Однако, если вы собрали PHP из исходников даже без этой опции, и исходники лежат рядом - этого может хватить для анализа.
Еще есть очень распространенное заблуждение, что отладочная сборка влияет на производительность и потребляемую процессом память (memory footprint). Не влияет, а лишь увеличивается размер исполняемого файла. Поэтому, если не сможете разобраться в причине ошибки без отладочной сборки - попросите сисадмина собрать модуль PHP с отладочными символами.

Чем открыть coredump? Конечно старой и "очень доброй" утилитой - gdb, изначально написанной верховным апостолом движения бесплатного свободного программного обеспечения Ричардом Столманом.
Разобраться, как работает отладчик, не займет много времени. Можно за пару часиков поглотить один из самых занимательных учебников, а можно попросить это сделать сисадмина ;-)

Обычно открывают coredump так:
gdb путь_к_выполняемому_файлу_веб-сервера путь_к_coredump

Все уважающие себя разработчики на C в unix конечно умеют пользоваться этим отладчиком, делают это, наверное, каждый день, но, к сожалению, их может не быть в вашей команде. И есть еще одно неприятное НО…

Отладка PHP в gdb - черная магия


Дело в том, что скомпилированный в байткод скрипт PHP это… не совсем программа на C ;-) Нужно, правда совсем немного, 
разобраться во внутренностях движка Zend - и вы все поймете довольно быстро. А именно - нужно найти в трейсе последний вызов функции execute, перейти в этот frame стека и исследовать локальные переменные (op_array), а также заглянуть в глобальные переменные движка Zend:
(gdb) frame 3
#3  0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605
(gdb) print (char *)(executor_globals.function_state_ptr->function)->common.function_name
$14 = 0x80fa6fa "pg_result_error"
(gdb) print (char *)executor_globals.active_op_array->function_name
$15 = 0x816cfc4 "result_error"
(gdb) print (char *)executor_globals.active_op_array->filename
$16 = 0x816afbc "/home/yohgaki/php/DEV/segfault.php"


В op_array можно запутаться, поэтому полезна команда просмотра типа этой структуры:
(gdb) ptype op_array
type = struct _zend_op_array {
    zend_uchar type;
    char *function_name;
    zend_class_entry *scope;
    zend_uint fn_flags;
    union _zend_function *prototype;
    zend_uint num_args;
    zend_uint required_num_args;
    zend_arg_info *arg_info;
    zend_bool pass_rest_by_reference;
    unsigned char return_reference;
    zend_uint *refcount;
    zend_op *opcodes;
    zend_uint last;
    zend_uint size;
    zend_compiled_variable *vars;
    int last_var;
    int size_var;
    zend_uint T;
    zend_brk_cont_element *brk_cont_array;
    zend_uint last_brk_cont;
    zend_uint current_brk_cont;
    zend_try_catch_element *try_catch_array;
    int last_try_catch;
    HashTable *static_variables;
    zend_op *start_op;
    int backpatch_count;
    zend_bool done_pass_two;
    zend_bool uses_this;
    char *filename;
    zend_uint line_start;
    zend_uint line_end;
    char *doc_comment;
    zend_uint doc_comment_len;
    void *reserved[4];
} *


Процесс отладки заключается в хождении между фреймами стека ("frame N"), переходе в каждый вызов функции "execute" и исследовании ее локальных аргументов ("print name", "ptype name"). Чем меньше номер фрейма, тем вы глубже. Иногда полезно зайти в гости в экстеншн PHP и посмотреть, где произошла ошибка и почему (хотя бы попытаться понять причину).

(gdb) frame #номер#
(gdb) print op_array.function_name
$1 = 0x2aaab7ca0c10 "myFunction"
(gdb) print op_array.filename
$2 = 0x2aaab7ca0c20 "/var/www/file.php"


И так далее…

Если вы поперхнулись кофе :-), то просто запомните, что переходя между фреймами стека вызовов с помощью команды "frame #N#", можно смотреть всего определенные элементы этой структуры - и вы точно сможете установить в каком файле PHP была вызвана функция PHP, какую функцию она вызвала и т.п. - и доберетесь до причины "Segmentation Fault" или другой ошибки, убившей процесс. И объясните программистам - в чем причина и ее поправят! Быстро и, надо быть оптимистами - навсегда.

Распространенные причины ошибок


Начните просматривать coredump-файлы (или поручите это сисадмину) и вы довольно быстро научитесь классифицировать ошибки по группам:
1) Проблемы в расширениях PHP. В этом случае либо отключите расширение, либо попробуйте поиграть его настройками. Вы точно знаете, что проблема в нем, дело за малым.
2) Проблема с рекурсией, стеком. Вы можете наступить на ошибку, при которой функция библиотеки, например, pcre, входит в рекурсию и вызывает себя тысяч двадцать раз. Можно либо настроить параметры библиотеки или, если лень, добавить процессу побольше стека ("/etc/init.d/httpd"):

ulimit -s "ставим значение больше"

А текущее значение можно посмотреть командой: "ulimit -a" (man ulimit, далее ищем "ulimit"). 
3) Проблемы в ядре PHP - тут нужно писать разработчикам PHP :-)

В общем, круг причин ошибки будет серьезно сокращен. Что нам и нужно.

Отладка запущенного процесса


Это еще не все. Если вы не можете получить coredump - можно подключиться к запущенному процессу и погулять по нему. Пока вы внутри процесса, его выполнение приостанавливается ("ps aux / grep apache / grep 'T '" - он будет в состоянии трейсинга). Когда покинете его - он снова продолжит выполняться. Подключиться можно так:
gdb -p ид_процесса

Итоги


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

Теперь можно составить чеклист для менеджера для борьбы с загадочными серверными ошибками, в которых не могут разобраться ни веб-разработчики, ни сисадмины:

  1. Включить сбор coredump-файлов на сервере (сисадмин)
  2. При необходимости пересобрать apache-PHP с отладочными символами (сисадмин)
  3. С помощью gdb (выходные на его изучение) исследовать причину появления ошибки (сисадмин с веб-разработчиком)
  4. Принять меры по ее устранению или снижению частоты появления: поменять настройки, обновить софт, написать в багтрекер, отключить расширение PHP и т.п.


В заключение приглашаю всех на наш облачный сервис Битрикс24, в котором мы эффективно используем все описанные в статье технологии.

Всем удачи и стабильной работы веб-проектов!

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 05.10.2012 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
VMware Horizon Apps Standard, v7 : 10 Pack (Named User)
Oracle Database Standard Edition 2 Named User Plus License
SAP® Crystal Presentation Design 2016 WIN INTL NUL
Bamboo
TeeChart for .NET Standard Business Edition 2017 single license
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
Реестр Windows. Секреты работы на компьютере
Один день системного администратора
Компьютерная библиотека: книги, статьи, полезные ссылки
Windows и Office: новости и советы
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100