Я столкнулся с похожими проблемами, когда возник вопрос про раздачу
более гигабита. Реализация HTTP в эрланге на многих десятках тысяч
запросов в минуту не оптимальна. Основная проблема мне видится в том,
что ошметки запроса (заголовки) по одному гоняются из драйвера в код и
там аккумуллируются.
Итог простой: раздача гигабита (сырая ретрансляция) требует больше
одного ядра, что выглядит плохо на фоне varnish, которому требуется на
это не более 30%.
Когда Лев рассказывал про свой косер, я ему сказал, что мне видится
его архитектура неудачной с той точки зрения, что внутри эрланга уже
есть свой libevent со всем чем только нужно и хороший API к нему в
виде драйверов. Если бы он свой косер написал в виде драйвера, то всё
работало бы ничуть не хуже, но при этом в одном адресном пространстве
с бизнес-логикой.
Я решил провести эксперимент и спустить обработку HTTP вниз в драйвер.
Взял http_parser.c, который был выпилен из nginx и используется в
Node.js и воткнул его в эрланговый драйвер.
Получилось неплохо: http://github.com/erlyvideo/microtcp
Итог такой: этот сырой прототип раздает гигабит (./test.erl + ab)
примерно в 20-30% ядра. Ровно такой же бенчмарк на обычном эрланговом
HTTP-сервере показывает около 100%. На основании этого можно сделать
вывод о том, что действительно обработка самого протокола силами
эрланга приводит к ужасной потере скорости и развивать данный кусок
кода стоит.
Слова «эрланг параллелится по нодам» многие люди воспринимают как
волшебную мантру, которая вылечит от любой проблемы.
Что вы собрались параллелить? Шторм из HTTP запросов?
--
Страница рассылки: http://groups.google.com/group/erlang-russian
Jabber-конференция: erl...@conference.jabber.ru
Новости: http://erlanger.ru
Написать письмо: erlang-...@googlegroups.com
Отписаться: erlang-russia...@googlegroups.com
А потом, получив двухкратную нагрузку на CPU вдруг вспоминаем, что
оказывается nginx не умеет склеивать два и более одновременных
запросов к бекенду и не умеет кешировать контент в памяти.
Опачки, какая незадача! А ведь так всё в блогах красиво расписывают!
А заодно пишем долгие и подробные инструкции админам о том, как же
помимо сервера ставить ещё и кеши к нему. И ловим кучу проблем с тем,
что админы сделали что-то не так, а разгребать это приходится не им.
--
Страница рассылки: http://groups.google.com/group/erlang-russian
Jabber-конференция: erl...@conference.jabber.ru
Новости: http://erlanger.ru
Написать письмо: erlang-...@googlegroups.com
Отписаться: erlang-russia...@googlegroups.com
На сколько я понял код и Макса, то вместо gen_tcp с packet={http|httph}
Совершенно верно. Вместо gen_tcp + http.
Как я уже объяснил: парсинг HTTP запросов достаточно дорогая вещь,
поэтому имеет смысл убрать это из эрланга.
Текущая реализация в эрланге недостаточно хороша, видимо из-за того,
что гоняет хедеры отдельными сообщениями.
2012/1/4 Max Lapshin <max.l...@gmail.com>:
https://github.com/extend/cowboy/issues/121
Но тут есть небольшая тонкость.
Дело в том, что http_parser.c берет на себя половину HTTP, в частности
такие штуки как keepalive и т.п. и работает
сильно удобнее в том плане, что сразу присылает все заголовки, не надо
накапливать и возиться с этим.
Но кое чего из cowboy_http_request хочется повторно использовать и тут
возникают некоторые вопросы.
4 января 2012 г. 16:29 пользователь Max Lapshin <max.l...@gmail.com> написал:
Ещё нет. Поправлю проблемы со стабильностью и напишу.
Цель очень простая: сделать так, что бы веб-сервер на эрланге был не
более чем в полтора-два раза тормозной чем варниш.
Total: connections 1000 requests 200000 replies 200000 test-duration 19.127 s
Connection rate: 52.3 conn/s (19.1 ms/conn, <=1000 concurrent connections)
Connection time [ms]: min 8970.4 avg 15117.7 max 19031.9 median
16612.5 stddev 3052.6
Connection time [ms]: connect 2994.2
Connection length [replies/conn]: 200.000
Request rate: 10456.2 req/s (0.1 ms/req)
Request size [B]: 72.0
Reply rate [replies/s]: min 10254.1 avg 10851.1 max 12013.6 stddev
1006.9 (3 samples)
Reply time [ms]: response 49.8 transfer 10.8
Reply size [B]: header 67.0 content 130000.0 footer 0.0 (total 130067.0)
Reply status: 1xx=0 2xx=200000 3xx=0 4xx=0 5xx=0
CPU time [s]: user 1.34 system 17.46 (user 7.0% system 91.3% total 98.3%)
Net I/O: 1328860.5 KB/s (10886.0*10^6 bps)
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
Осталось только повторить на реальном железе: Net I/O: (10886.0*10^6 bps)
IMHO О©╫О©╫О©╫О©╫О©╫ packet={http|httph} О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ -
О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫ О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ HTTP О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫. О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫
О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫ erlang:decode_packet/3.
--
Dmitry Vasiliev <dima at hlabs.org>
http://hlabs.org
http://twitter.com/hdima
thanks,
Slav
4 января 2012 г. 20:38 пользователь Dmitry Vasiliev <di...@hlabs.org> написал:
> On 04.01.2012 16:16, Max Lapshin wrote:
>>
>> 2012/1/4 Gleb Peregud<gleb...@gmail.com>:
>>>
>>> На сколько я понял код и Макса, то вместо gen_tcp с packet={http|httph}
>>
>>
>> Совершенно верно. Вместо gen_tcp + http.
>>
>> Как я уже объяснил: парсинг HTTP запросов достаточно дорогая вещь,
>> поэтому имеет смысл убрать это из эрланга.
>> Текущая реализация в эрланге недостаточно хороша, видимо из-за того,
>> что гоняет хедеры отдельными сообщениями.
>
>
> IMHO опция packet={http|httph} с заголовками в отдельных сообщениях - это
> просто быстрый путь для писателей HTTP серверов. Заголовки можно разбирать и
> самостоятельно с помощью erlang:decode_packet/3.
>
> --
> Dmitry Vasiliev <dima at hlabs.org>
> http://hlabs.org
> http://twitter.com/hdima
>
>
Вы мне покажете сервер, использующий decode_packet и укладывающийся в
50% ядра при раздаче гигабита?
Это уже рабочие моменты.
Судя по отчету httperf происходят серьезные залипания на приёме
соединений и на обработке.
> Connection time [ms]: connect 2552.1
> Reply time [ms]: response 49.8 transfer 8.5
> Net I/O: 1246639.1 KB/s (10212.5*10^6 bps)
Но при этом тесты http_bench (это специальная утилита, умеющая
скачивать HDS видеопоток) говорят, что при гигабитном потоке
CPU сервера колеблется в районе 20%.
Т.е. по CPU результат достигнут, а по плавности работы есть провал.
Массовый реконнект 20 тыс клиентов — рабочая ситуация, на которую надо
рассчитывать.
Ещё есть мысль спустить кеш прям в драйвер, что бы на самые горячие
запросы (а я из приложения хорошо знаю, какие они),
ответ происходил прям из уровня драйвера, без походов в бизнес-логику.
* успешно запустилось вместе с cowboy:
https://github.com/erlyvideo/cowboy/commit/e617f740b7cf40732571171eaa750b9a6e792f48
* нормализация заголовков (content-length -> Content-Length) делается
прям в C, мутабельно
* преобразование заголовков в атомы так же, как в decode_packet
* сделан мультипроцессовый accept
* приделал поддержку file:sendfile
Результаты, конечно, не такие как у Льва с его косером, но уже ощутимо
ближе к varnish, чем у ковбоя/мисультина.
Основная разница в том, что парсинг HTTP осуществляется одним из самых
быстрых парсеров и результат шлется одним сообщением,
а не списком.
P.S. оказалось, что внутри эрланга есть куча разных имплементаций
хеш-таблиц, которые дублируются и пересекаются,
а чего-то единого нет.
--
Страница рассылки: http://groups.google.com/group/erlang-russian
Jabber-конференция: erl...@conference.jabber.ru
Новости: http://erlanger.ru
Написать письмо: erlang-...@googlegroups.com
Отписаться: erlang-russia...@googlegroups.com
Вот у нас 25 лоад-балансеров стоит. Которые ведут трафик на 14
апликейшн-серверов (косер). Заметьте, не два nginx перед тучей
апликух, а 25 перед 14'ю. Потому что балансер менее эффективен, чем
само приложение.
--
vlm
--
Страница рассылки: http://groups.google.com/group/erlang-russian
Jabber-конференция: erl...@conference.jabber.ru
Новости: http://erlanger.ru
Написать письмо: erlang-...@googlegroups.com
Отписаться: erlang-russia...@googlegroups.com
2012/1/5 Sergey Prochorov <seri...@gmail.com>:
> надо ток переименовать в microhttp, а то как-то не очевидно.
>
Лев. А зачем?
Т.е. два подвопроса:
1) не пробовали ли вы какой-нибудь чудо-балансировщик амазона?
2) почему не попросить косер балансировать? Там есть какая-то
сложность в балансировке?
--
Страница рассылки: http://groups.google.com/group/erlang-russian
Jabber-конференция: erl...@conference.jabber.ru
Новости: http://erlanger.ru
Написать письмо: erlang-...@googlegroups.com
Отписаться: erlang-russia...@googlegroups.com
Обновил.
И добавил режим http-клиента. Тоже очень неплохо вышло.
Отличительные черты от других:
1) присылает одним сообщением весь распарсенный заголовок ответа
2) тело ответа так же присылает сообщениями, но не полутора
килобайтными, как {active,once}, а как попросишь.
Т.е. внутри драйвера буферизуется ответ и шлется дальше.
Простите, но zerocopy пока нет, для этого надо подпиливать
http_parser.c, что бы он не лез в тело сообщения.
На примитивной раздаче файлов (600 байт) в три раза медленнее nginx и
в три раза быстрее inets.
Конечно стоило бы воткнуть парсер их протокола, но фиг с ним.
Основные отличия от gen_tcp частично покрыты тестами.