Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет Леонид Каганов ([info]lleokaganov)
@ 2016-09-06 01:39:00

Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Про зависание сайта lleo.me и дебилизм PHP
это перепост заметки, оригинал находится на моем сайте: http://lleo.me/dnevnik/2016/09/06.html

Если помните, одно время сайт lleo.me висел чуть ли не каждую неделю, и это был ад: сперва идут тебе письма от читателей и SMS от друзей, что сайт снова повис, потом ты пишешь хостеру в Канаду, чтоб он пошел и перезапустил виртуальный сервер, только тогда всё поднимется. Что случилось? Никаких следов, никаких версий. Чего мы только не делали с грамотными специалистами — и системы внутреннего мониторинга ставили, и на DDOS-атаки грешили. Разгадка оказалась проста — PHP. Вкратце: иногда серверу требуется скачать/послать файл или данные другого сервера. Не спрашивайте, зачем — есть разные надобности в движке, от автопостинга заметок до прочих нужд. Во всех сетевых учебниках быдлокодинга PHP (типичный пример: http://www.php.su/fgets ) процедура предлагается такой:

Пример 1. Построчное чтение файла

$handle = fopen('/tmp/inputfile.txt', 'r');
while (!feof($handle)) {
    $buffer = fgets($handle, 4096);

    echo $buffer;
}
fclose($handle);

Это не я придумал, это примеры из учебников. Сервер погружается в бесконечный цикл, пока не прочтет данные. Об окончании которых сразу узнает из загадочной функции feof(). Чей смысл и принцип оставим тоже на совести создателей PHP. Вроде бы нормально. Но, как выяснилось, бывают ситуации, когда цикл становится бесконечным. Может, указатель $handle=fopen() не открылся — авторы учебника его, как видим, тоже не проверяют. Может, сраный feof не поймал конец файла или размер файла точно совпал с 4096, а дальше всё пошло вразнос. Не важно. Суть в том, что возникает бесконечный цикл и ошибки чтения.

Сам по себе бесконечный цикл — проблема, но не такая фатальная, чтоб регулярно валить сервера и полтора года не понимать, отчего такое случается. Какой бы ни был бесконечный цикл, сервер отрубит соединение по таймауту секунд через 30, и на этом все кончится. Но есть нюанс. Поскольку это ошибка чтения, PHP начинает орать о ней в свои логи. А поскольку цикл бесконечный, он успевает в эти секунды засрать лог до критического размера 2Gb. Видимо, PHP на это не рассчитан и не успевает переархивировать лог. И дело не в том, что кончается память — нет, память еще есть. Просто по загадочной причине от внезапно возникшего лога 2Gb падает и PHP, и вся система, и вся виртуалка. Не пипец ли?

На lleo.me под Debian это отловить не удавалось никак: когда виртуалка заново поднимается, гагантского лога уже нет, всё чисто. Как понять, что сервер убивают скрипты, и как понять, в каких строчках, если эффект случается редко, а логов не остается? Помог сайт hultura.ru, где стоял тот же мой движок. Там FreeBSD, там хостинг Zenon, там очень внимательный и дотошный начальник технического отдела друг Сережа Беркович, и вот он каким-то образом понял и подсмотрел, как это происходит. Ну, исправить оказалось легко: просто вставить лишнюю проверку, не предусмотренную большинством примеров из учебников:

$handle = fopen('/tmp/inputfile.txt', 'r');
while (!feof($handle)) {
    $buffer = fgets($handle, 4096);
    if($buffer===false) break;
    echo $buffer;
}
fclose($handle);

Специалисты конечно рекомендуют проверяить и результаты fopen(), но на самом деле это не очень нужно — если fopen() даст false, то уж и fgets() точно сразу даст false. Кстати, специалист внутреннего устройства PHP Dmitri Dmitrienko советует навсегда отказаться от fgets(), а использовать fread() — говорит, адски кривая реализация там.

Так или иначе, зависания пропали и на hultura.ru и на lleo.me и везде, где стоял движок. Зная, что ошибка редкая, я специально выждал год, прежде, чем написать этот пост. Но теперь могу сказать: да, это было именно оно, мы нашли и победили.

Мораль: в этом мире нельзя верить никому, особенно учебникам. Никогда не используйте чей-то готовый пример, не изучив его и не переписав по-своему.

UPD: Ну и раз уж зашел разговор о программировании, я тут недавно попробовал наконец себе поставить систему разработки приложений для смартфонов, чтобы вникнуть в это полезное дело. Потратил весь вечер, поставил Eclipse, Andriod Studuio с SDK и еще тонны говна. Впечатления скверные. Во-первых, Andriod Studuio у меня не заработал: оказалось, Linux с 32-битным ядром — единственный случай, для которого не предусмотрен эмулятор смартфона. Был бы Windows — пожалуйста, была бы Ubunta-64 — тоже. Кроме того, я вдруг понял, что у меня вообще нет никакого желания изучать Java, архитектуры бесконечных папок с неприятными мне файлами XML и прочее говно. Которое устареет раньше, чем я достигну высокого мастерства разработчика в эпизодических хобби. И которое совершенно неприменимо, например, к iOS — там все другое. Поэтому я решил, что раз я хорошо владею HTML и JS, то мне для разработки нужно что-то типа PhoneGap: чтоб я мог писать свои приложения на хорошо знакомом мне JS, и они легко отлаживались на Вебе и портировались и на Android, и на iOS и на остальное говно, которое вдруг появится в будущем. Ведь сочинение динамических 3D-игр не входит в мои планы: для начала мне понадобится что-то выводить на экран, да бегать куда-то в интернет, чтобы получать-отправлять данные. Но я так понимаю, что получение сигналов приложению в спящем режиме, работа с датчиками, SMS, фото — все это тоже есть для JS-портов? В правильном ли направлении я иду? Что посоветуете?



это перепост заметки, оригинал находится на моем сайте: http://lleo.me/dnevnik/2016/09/06.html


(Читать комментарии)

Добавить комментарий:

Как:
( )анонимно- этот пользователь отключил возможность писать комментарии анонимно
Identity URL: 
имя пользователя:    
Вы должны предварительно войти в LiveJournal.com
 
E-mail для ответов: 
Вы сможете оставлять комментарии, даже если не введете e-mail.
Но вы не сможете получать уведомления об ответах на ваши комментарии!
Внимание: на указанный адрес будет выслано подтверждение.
Имя пользователя:
Пароль:
Тема:
HTML нельзя использовать в теме сообщения
Сообщение:



Обратите внимание! Этот пользователь включил опцию сохранения IP-адресов пишущих комментарии к его дневнику.