-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
С++ версия сервера. Не полностью отдаёт HTML для IFRAME.. #14
Comments
Давайте, наверное, все же лучше тут переписываться. Вопрос у вас был такой:
Я было подумал вначале, что write мог не весь контент за раз отдавать. Но потом освежил память и понял, что write как раз нормально написан:
Видите, он просто не выйдет из цикла до тех пор, пока не скормит ядру все данные, какими бы порциями оно их ни принимало. Сокет создается unbuffered, так что никакого flush для него делать не нужно, по идее. Может быть, происходит вылет по ошибке, возвращаемой write? Вы можете это проверить у себя, вставив там вместе с return -1 отладочную печать? (Или просто приведите логи realplexor-а - там должен писаться статус вроде как, если VERBOSITY=3.) |
Думаю, кстати, что дело может быть в следующем: EAGAIN or EWOULDBLOCK Там как раз неблокирующий режим устанавливается для сокета, и он может вылетать по EAGAIN, если в системе не хватает буферов для приема данных. Попробуйте, пожалуйста, эксперимент с диагностикой, который я выше описал. Заодно там и errno тоже выведите. |
strace: clock_gettime(CLOCK_MONOTONIC, {634478, 882726474}) = 0 |
log: |
согласно http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html Хотелось бы Ваш вердикт, т.к. на c++ я давно ничего не писал и с сокетами дел не имел. |
Ну вы этим как бы busy wait устроили, это не очень хорошо - нагрузка значительно увеличивается. Того же можно было добиться, убрав неблокирующий режим с сокета, да только неправильно это - устраивать блокировки в event-driven программах (т.к. пока крутится этот цикл с EAGAIN, остальные соединения будут ждать, т.е. вся работа, фактически, встает). Спасибо за ваше исследование, причины теперь ясны. Исправить, правда, проблему "чисто" довольно сложно будет. Я попробую на досуге. |
Что-то удалось придумать по поводу данного бага? Появляется спонтанно, только у некоторых клиентов, поэтому отловить получилось не сразу |
Я пустил всё через nginx с буферизцией(perl версия от этого тоже сильно расслабляется), а так как nginx и dklab_realplexor на одной машине, то такая проблема не возникает. Ну и для надёжности я вставил свой код который предлагал если вдруг служится EAGAIN, то контент отдастся полностью. Так же чтобы не упираться в процессор, я запустил 2 dklab_realplexor чтобы работали 2 ядра процессора. Всё это позволило даже при большом онлайн иметь загруженность процессора не более 10%. |
Проблема воспроизводится очень непредсказуемо и отловить гарантированно не получилось. Через какое-то время пропадало само. |
контент который вы, например из php, отправляете клиенту так же приходит не полностью если отправлять несколько КБ, я проверял. между клиентом и realplexor лучше вставить nginx с буферизацией. это решает сразу 2 проблемы описанные выше. |
Если плексер не целиком отправляет данные, как описано выше, то буферизация здесь не поможет. |
Как я выше писал, исправить данный баг довольно сложно. В realplexor-е событийно-ориентированное программирование на основании libev применяется только при обработки операций чтения, но НЕ при обработке операций ЗАПИСИ. Т.е. если при чтении данные пришли не все, то они накапливаются в буфере до тех пор, пока не будет все прочитано. А вот запись делается по принципу "писать по максимуму сразу", в 1 операцию. Поэтому если вдруг во время записи половина буфера запишется, а половина выдаст EAGAIN (такое бывает, когда в системе кончается память буферов записи TCP, в openvz это параметр tcpsndbuf, кажется), то все, данные потеряются. По-хорошему надо этот буфер хранить где-то и писать тоже через механизм libev: записал кусочек, подождал события "случилось окончание записи", записал оставшийся кусочек и т.д. (а если вдруг пришло событие "соединение разорвано", то буфер уничтожить). Но данного механизма сейчас нет. Быстрое лечение проблемы - увеличение буферов записи TCP и/или установка перед realplexor-ом nginx с большим буфером. |
Столкнулся с похожей проблемой. Сервер не отправляет больше ~7КБ. Так как такой размер ответа был только с dklab_realplexor.html , сжал файл JS minifier'ом до 4999 байт и больше проблема не беспокоила. |
Два года работает с патчем, контент отдаёт полностью. |
Вы этим устроили busy wait. Т.е. на время, пока система не будет готова принять новую порцию данных, процесс будет полностью заблокирован, крутясь в цикле и получая EAGAIN миллион раз, загружая ядро на 100% и не давая другим клиентам работать. И длиться это может несколько секунд. Нужно делать полноценную буферизацию потоков отвачи через libev, я даже начал какое-то время назад, но пока подзавяз. Сейчас самый простой обходной способ - поставить перед realplexor-ом nginx с достаточными буферами (proxy_buffers), который будет принимать все, что ему скармливают, и уже дальше сам буферизировать. |
Вашу переписку гугл выдаёт. Может скажете, почему на локальном сервере не работают ifram'ы |
Здравствуйте, Дмитрий!
Perl версия не справляется с рассылками в канал ограниченному списку пользователей, упирается в процессор и в результате принимает от PHP каждую команду за 5-8 секунд, что приводит к неработоспособности сайта. Если делать все каналы уникальными и не делать массовых рассылок, то пока справляется, но тоже близок к 100% ЦПУ.
Решил попробовать C++ версию. Протестировал на тестовом сервере, никаких проблем не обнаружил. Все прекрасно работало. А на боевом сервере возникла проблема.
Если на самом сервере выполнить:
telnet comet.site.ru 80
get /multiplexor/?identifier=IFRAME&HOST=site.ru&version=1.32.3
Здесь всё не влазит, поэтому концовка здесь: http://forum.dklab.ru/viewtopic.php?p=196870#196870
The text was updated successfully, but these errors were encountered: