Post on 16-Jun-2015
description
EventmachineСтруктура evented-приложений
fork per requestОтстрел форка на запрос
• Раньше была практика форкаться на запрос;
• copy-on-write позволял шарить между процессами код;
• невообразимо медленно, но для модемов нормально.
предфоркнутые обработчики
prefork
•Apache первой версии, все воркеры держат accept;
•N-воркеров — N одновременных запросов;
•mod_php в безопасности;
•отдача файликов на модемы кладет сервер;
•дорогая межсерверная коммуникация.
Вместо процессов нитки
thread pool
•Для разделения данных между воркерами, запускаются треды. Те же процессы, но в одном адресном пространстве;
•Проблемы с синхронизацией ниток.
новые проблемы
Много клиентов
• При большом количестве одновременных запросов начинаются проблемы с шедулингом и переключением контекста;
• время поровну делится на клиентов и пропорционально количеству клиентов замедляется отдача ответа
• Нитки отчасти помогают уменьшить стоимость переключения контекста, т.к. не требуют смены адресного пространства
• Valgrind и gdb будут сниться ночью. Проезд по памяти осуществляется под нагрузкой и очень плохо отслеживается
• Помимо непредсказуемости переключения, нитки неоптимальны по количеству переключений:
• Переключения в данном примере стоило бы делать так:
Нитки в Ruby
• Медленные;
• Не утилизируют ядра процессора;
• Реализованы самым неоптимальным способом;
• Основные библиотеки не threadsafe (мало кто вкладывает в это силы).
Evented
• Многие сетевые приложения делают частый ввод-вывод и быструю обработку данных (шаблонизация + проверки);
• Операции ввода вывода долгие и с неизвестным временем работы. Чем их ждать, лучше заниматься делом;
• Беда с дисковым вводом-выводом: он на текущий момент на практике синхронный;
• НЕ конечный автомат (FSM);
• Нитки в руби реализованы через вызов select.
• Приходящее событие;
• Обработка;
• Запись данных в сокет.
EVentmachine
• Стандарт де-факто для Ruby 1.8;
• Ввод данных;
• Готовность к выводу данных;
• Таймер;
• Сигнал от OS (мертвый ребенок, SIGHUP и т.п.).
next tick
• Вместо delayed_job можно выполнить долгую операцию после текущего такта работы (на следующем run loop)
Проблемы
• Очень тяжело распиливать линейный код на колбеки;
• Использование многоядерности (evented приложения вообще стараются делать однонитевыми).
Fibers
• В Ruby 1.9 есть fibers — управляемые пользователем нитки. Coroutines;
• Команда Neverblock портировала их на Ruby 1.8;
• Revactor использует не Eventmachine, а стандарную libev;
• Совмещают удобства ниток и eventmachine.
multicore• Руби пока далек от использования многоядерности;
• В 1.9 всё равно есть GIL;
• Возможно альтернативные команды помогут (Rubinius, MacRuby);
• Python тоже использует GIL;
• В Java нитки дорогие (системные, а не зеленые);
• Запускаем процессы по количеству ядер.
Выводы
• Fork очень дорогой;
• Не-evented архитектура плохо обслуживает много медленных клиентов;
• EventMachine для руби подходит прекрасно, огромное количество библиотек, всё хорошо;
• Fibers удобнее чем EventMachine, но мало используются;
• Для работы на многих ядрах запускается N рабочих процессов.