Бенчмарк HTTP-серверов (С/C++) в FreeBSD



Проведено сравнение производительности ядер HTTP-серверов, построенных с использованием семи C/C++ библиотек, а также (в познавательных целях) — других готовых решений в этой области (nginx и node.js).

HTTP-сервер — это сложный и интересный механизм. Есть мнение, что плох программист, не написавший свой компилятор, я бы заменил «компилятор» на «HTTP-сервер»: это и парсер, и работа с сетью, и асинхронность с многопоточностью и много чего еще....

Тесты по всем возможным параметрам (отдача статики, динамики, всевозможные модули шифрования, прокси и т.п.) — задача не одного месяца кропотливой работы, поэтому задача упрощена: будем сравнивать производительность ядер. Ядро HTTP-сервера (как и любого сетевого приложения) — это диспетчер событий сокетов и некий первичный механизм их обработки (реализованный в виде пула потоков, процессов и т.п.). Сюда же можно отнести парсер HTTP-пакетов и генератор ответов. На первый взгляд, все должно свестись к тестированию возможностей того или иного системного механизма обработки асинхронных событий (select, epoll и т.п.), их мета-обёрток (libev, boost.asio и др.) и ядра ОС, однако конкретная реализация в виде готового решения дает существенную разницу в производительности.

Был реализован свой вариант HTTP-сервера на libev. Конечно, реализована поддержка небольшого подмножества требований пресловутого rfc2616 (вряд ли ее полностью реализует хоть один HTTP-сервер), лишь необходимый минимум для соответствия требованиям, предъявляемым к участникам данного тестирования,

  1. Слушать запросы на 8000-ом порту;
  2. Проверять метод (GET);
  3. Проверять путь в запросе (/answer);
  4. Ответ должен содержать:
                HTTP/1.1 200 OK
                Server: bench
                Connection: keep-alive
                Content-Type: text/plain
                Content-Length: 2
                42
            

  5. На любой другой метод\путь — должен возвращаться ответ с кодом ошибки 404 (страница не найдена).

Как видите — никаких расширений, обращений к файлам на диске, интерфейсов шлюза и т.п. — все максимально упрощено.
В случаях, когда сервер не поддерживает keep-alive соединения (кстати, этим отличился только cpp-netlib), тестирование проводилось в соотв. режиме.

Предыстория


Изначально стояла задача реализовать HTTP-сервер с нагрузкой в сотни миллионов обращений в сутки. Предполагалось, что будет относительно небольшое кол-во клиентов, генерирующих 90% запросов, и большое число клиентов, генерирующих оставшиеся 10%. Каждый запрос нужно отправлять дальше, на несколько других серверов, собирать ответы и возвращать результат клиенту. От скорости и качества ответа зависел весь успех проекта. Поэтому просто взять и использовать первое попавшееся готовое решение не представлялось возможным. Нужно было получить ответы на следующие вопросы:
  1. Стоит ли изобретать свой велосипед или же использовать существующие решения?
  2. Подходит ли node.js для высоконагруженных проектов? Если да, то выкинуть заросли С++ кода и переписать все в 30 строк на JS.

Были и менее значимые вопросы, например, влияет ли HTTP keep-alive на производительность? (спустя год ответ был озвучен здесь — влияет, и весьма существенно).

Разумеется, сначала был изобретён свой велосипед, затем появился node.js (узнал про него два года назад), ну а потом захотелось узнать: насколько существующие решения эффективнее собственного, не зря ли было потрачено время? Собственно, так и появился данный пост.

Подготовка


Железо
  • Процессор: CPU: AMD FX(tm)-8120 Eight-Core Processor
  • Cеть: localhost (почему — см. в TODO)

Софт
  • ОС: FreeBSD 9.1-RELEASE-p7

Тюнинг
Обычно в нагрузочном тестировании сетевых приложений принято изменять следующий стандартный набор настроек:
/etc/sysctl.conf
kern.ipc.somaxconn=65535
net.inet.tcp.blackhole=2
net.inet.udp.blackhole=1
net.inet.ip.portrange.randomized=0
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65535
net.inet.icmp.icmplim=1000

/boot/loader.conf
kern.ipc.semmni=256
kern.ipc.semmns=512
kern.ipc.semmnu=256
kern.ipc.maxsockets=999999
kern.ipc.nmbclusters=65535
kern.ipc.somaxconn=65535
kern.maxfiles=999999
kern.maxfilesperproc=999999
kern.maxvnodes=999999
net.inet.tcp.fast_finwait2_recycle=1

Однако в моем тестировании они не приводили к повышению производительности, а в некоторых случаях даже приводили к значительному замедлению, поэтому в финальных тестах никаких изменений настроек в системе не проводилось (т.е. все настройки по умолчанию, ядро GENERIC).

Участники


Библиотечные
Имя Версия События Поддержка keep-alive Механизм
cpp-netlib 0.10.1 Boost.Asio нет многопоточный
hand-made 1.11.30 libev да многопроцессный (один поток на процесс), асинхронный
libevent 2.0.21 libevent да однопоточный*, асинхронный
mongoose 5.0 select да однопоточный, асинхронный, со списком (подробнее)
onion 0.5 libev да многопоточный
Pion Network Library 0.5.4 Boost.Asio да многопоточный
POCO C++ Libraries 1.4.3 select да многопоточный (отдельный поток для входящих соединений), с очередью (подробнее)

Готовые решения
Имя Версия События Поддержка keep-alive Механизм
Node.js 0.10.17 libuv да модуль cluster (многопроцессная обработка)
nginx 1.4.4 epoll, select, kqueue да многопроцессная обработка

*для тестов переделан по схеме «многопроцессный — один процесс один поток»

Дисквалифицированы
Имя Причина
nxweb только Linux
g-wan только Linux (и вообще...)
libmicrohttpd постоянные падения при нагрузках
yield ошибки компиляции
EHS ошибки компиляции
libhttpd синхронный, HTTP/1.0, не дает поменять заголовки
libebb ошибки компиляции, падения

В качестве клиента использовалось приложение от разработчиков lighttpd — weighttpd. Изначально планировалось использовать httperf, как более гибкий инструмент, но он постоянно падает. Кроме того, weighttpd основан на libev, который гораздо лучше подходит для FreeBSD, чем httperf с select-ом. В качестве главного тестового скрипта (обертки над weighttpd с подсчётом расхода ресурсов и пр.) рассматривался gwan-овский ab.c, переделанный под FreeBSD, но в последствии был переписан с нуля на Пайтоне (bench.py в приложении).

Клиент и сервер запускались на одной и той же физической машине.
В качестве переменных значений использовались:
  • Количество серверных потоков (1, 2 и 3)
  • Количество параллельно открытых запросов клиентов (10, 100, 200, 400, 800)

В каждой конфигурации выполнялось по 20-30 итераций, 2 млн. запросов за итерацию.

Результаты


В первой версии статьи были допущены грубые нарушения в методике тестировании, на что было указано в комментариях пользователями VBart и wentout. Так, в частности, не использовалось строгое разделение задач по ядрам процессора, общее кол-во потоков сервера\клиента превышало допустимые нормы. Также не были отключены опции, влияющие на результаты измерений (AMD Turbo Core), не были указаны погрешности измерений. В текущей версии статьи используется подход, описанный здесь.

Для серверов, запущенных в однопоточном режиме, получены следующие результаты (взяты максимальные медианы по комбинациям серверных/клиентских потоков):
Место Имя Клиентск. потоков Проц. время Запросов
Польз. Сист. Успешных (в сек.) Неуспешных (%)
1 nginx 400 10 10 101210 0
2 mongoose 200 12 15 53255 0
3 libevent 200 16 33 39882 0
4 hand-made 100 20 32 38550 0
5 onion 10 22 33 29230 0
6 POCO 10 25 50 20943 0
7 pion 10 24 83 16526 0
8 node.js 10 23 173 9374 0
9 cpp-netlib 10 100 183 5362 0

Масштабируемость:

В теории, если бы ядер было больше, мы бы наблюдали линейный рост производительности. К сожалению, проверить теорию не представляется возможным — ядер не хватает.

nginx, откровенно говоря, удивил — ведь по сути это готовое, многофункциональное, модульное решение, а результаты на порядок превзошли узкоспециализированные библиотеки. Респект.

mongoose пока сыроват, версия 5.0 не обкатана и ветка находится в активной стадии разработки.

cpp-netlib показал худший результат. Мало того что он единственный не поддерживал HTTP keep-alive соединения, так ещё и падал где-то в недрах boost-а, было проблематично выполнить все итерации подряд. Однозначно, решение сырое, документация — устаревшая. Законное последнее место.

node.js уже ругали здесь, не буду так категоричен, но V8 еще пилить и пилить. Что это за high-load решение, которое даже без полезной нагрузки так жадно потребляет ресурсы и выдаёт 10-20% производительности топовых участников тестирования?

HTTP keep-alive on/off: если в посте разница доходила до x2 раз, то в моих тестах разница была до х10.

Погрешность по ministat: No difference proven at 95.0% confidence.

TODO


  • бенчмарк в режиме «клиент и сервер на разных машинах». Нужно быть осторожным — все может упереться в сетевые железки, причём не только модели сетевых карт, а свичей, роутеров и т.п. — всю инфраструктуру между реальными машинами. Для начала можно попробовать прямое подключение;
  • тестирование клиентской HTTP API (организовать в виде сервера и прокси). Проблема в том, что далеко не все библиотеки предоставляют API для реализации HTTP-клиента. С другой стороны, некоторые популярные библиотеки (libcurl, например) предоставляют исключительно клиентский набор API;
  • использование других HTTP-клиентов. httperf не использовался по указанным выше причинам, ab — по многим отзывам устарел и не держит реальных нагрузок. Многие рекомендовали . Здесь представлена пара десятков решений, какие-то из них стоило бы сравнить;
  • аналогичный бенчмарк в Linux-среде. Вот это должна быть интересная тема (как минимум — новая волна для холиварных обсуждений);
  • прогнать тесты на топовом Intel Xeon с кучей ядер.


Ссылки


Stress-testing httperf, siege, apache benchmark, and pronk — HTTP-клиенты для нагрузочного тестирования серверов.
Performance Testing with Httperf — советы и рекомендации о проведении бенчмарков.
ApacheBench & HTTPerf — описание процесса бенчмарка от G-WAN.
Warp — еще один high-load HTTP-сервер с претензией, Haskell.

Приложение


В приложении вы найдёте исходники и результаты всех итераций тестирования, а также подробные сведения по сборке и установке HTTP-серверов.
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 54
  • +6
    В ходе разговора с авторами nginx они несколько раз упомянули, что для нагрузочного тестирования используют ab из apache и wrk (https://github.com/wg/wrk)
    • 0
      Для тестирования я использую Tsung и siege.
    • +4
      Без измерения cpu/memory usage это все не имеет смысла
      • 0
        Присоединяюсь. Важно, насколько ресурсы компа заняты во время обработки этого потока запросов. Интересно было бы создать фоновую нагрузку, например, архивировать файлы или mp3/mp4 конвертировать. Может быть, это подвинет позиции.
        А сейчас — это если весь сервак выделен под эту задачу. Если так, то тоже интересно, сколько этого сервера «пропадает».
        • +1
          Я думаю, с теми объемами пересылаемых данных, которые упоминает в статье автор, сервер очень вряд ли занимается чем-либо еще, кроме диспетчеризации. :)
          • –1
            Поддерживаю предыдущего оратора.

            Автор, прости. Статья интересная. Я — нуб.
            Но мне очень, жалко ноду, поэтому я всю ночь не спал и запилил топик добра.
        • 0
          Колонки «Время(польз.\сист.)» в таблице результатов — это psutil get_cpu_times() для родительского и дочерних процессов сервера.
          Память не мерялась в силу того, что ни один участник не использовал этот ресурс сколько-нибудь значительно (кроме node.js, о чем есть упоминание).
        • +9
          Ноджс — хайлоад-решение? Хахаха, то есть мяу
          • 0
            если вы его не умеете готовить — так оставьте это тем, кто умеет :)
            • +1
              Да, можно, конечно — поделим ядра, оставив минимум одно самой системе, чтобы не блокировать сетевой стек:

               exec('taskset -pc ' + affinity + ' ' + pid);
              


              Естественно, это у this.isCluster == true, чтобы форки тоже попали в affinity.
              Дальше оно само разберётся.

              Поправим конфиги по типу как у автора + ulimit, kernel.sem и т.п..

              Статику всё равно лучше через nginx, что правда — то правда, это ещё минус одно ядро.
              Зато в разработке логики всё будет просто и шоколадно :)
              • +4
                Я node.js использовал ещё в версии 0.2, когда там были прямые posix-вызовы, что все сильно упрощало. Это хороший инструмент для ряда задач, но из другого эшелона. Тот же PHP с libev даёт сравнимую производительность, но у меня язык не двинется назвать это хайлоад-решением. Вокруг ноджса слишком много пиара.
            • +6
              >> httperf с его линуксовым select-ом

              Все-таки select это не линуксовый вызов, а вездесущий, я бы сказал, мультиплатформенный в общем.
              • 0
                Кстати, не хватает теста чистой libuv ;)
                • –2
                  За графики конечно спасибо — очень познавательно, но половина результатов я уже понял в априори.
                  Сам уже давно юзаю libevent & libev. В своё время делал счетчик кликов для баннерки на libevenet. Держала миллионы запросов в сутки — подтверждаю.

                  Может в этот зоопарк можно было добавить gwan. Он как раз для таких задач, как счетчики.
                  Однако, каждой твари по паре, каждому HTTP серверу по своей задачи.
                  • +5
                    А чего в год цифру не дали? Миллиарды получились бы. 1 000 000 запросов в сутки — это 11.5 rps, нехитрая математика подтверждает.
                    • 0
                      К сожалению, gwan очень сильно завязан на linux — окружение. Было бы интересно узнать, что представляет из себя этот выделяющийся на фоне остальных серверов своей весьма агрессивной рекламой сервер.
                    • 0
                      Интересное исследование, спасибо. Да, наибольшее разочарование — node.js
                      • –1
                        Скорее всего, она всё-таки была неправильно приготовлена, кто-то наверное что-то упустил.
                        Ноде нельзя отдавать всё, т.к. она всё и сожрёт.

                        Чуть выше отписался.
                      • +6
                        Клиент и сервер запускались на одной и той же физической машине

                        так низзя…
                        • –2
                          Спорный вопрос, смотря какие стоят цели и задачи. Если это нагрузочный прогон системы перед запуском в продакшн — то однозначно localhost не подходит. Если же это тестирования сферических ядер на лабораторном стенде — localhost вполне жизнеспособное решение.
                          одно из мнений «за» (раздел Why localhost tests are relevant?)
                          • +2
                            ИМХО — очень сферический в вакууме тест.
                            Процессоры считают последовательно, и доверять ядру распределение нагрузки многопоточных задач никак нельзя.
                            Интересно было бы посмотреть, если бы автор оставил 6 ядер серверу, одно системе, одно CURL'у.
                            А так — на переключение контекста очень много времени будет уходить.
                        • +4
                          Может я чего-то не то скажу, но я всегда считал, что epoll это в linux, а во FreeBSD это kqueue. (onion и poco из тестируемых образцов). Разве нет?
                          • 0
                            Вы правы, для onion в FreeBSD механизм событий при сборке по-умолчанию — libev.
                            poco (из портов) — в FreeBSD использует select.
                          • +3
                            CPU: AMD FX(tm)-8120 Eight-Core Processor
                            Количество серверных потоков (1 и 8).
                            client_threads = psutil.NUM_CPUS
                            Клиент и сервер запускались на одной и той же физической машине.
                            Т.е. в вашем тесте клиент и сервер весьма жестко конкурировали за ресурсы, и кому-то их лучше удалось поделить между собой.

                            Кроме того ваш процессор снабжен технологией Turbo Core 2, которая в зависимости от нагрузки и TDP/ACP может весьма своеобразно повышать частоту отдельных ядер. Надеюсь в процесее испытания она была отключена?
                            • –3
                              Контроль за ресурсы — по сути все сервера находятся в одинаково невыгодном положении, надеялся компенсировать это результатами, построенными на многократных запусках (более ста итераций на каждый сервер). Но согласен — это один из самых спорных моментов в данной статье. Никогда не слышал про Turbo Core 2, еще раз убеждаюсь, что идеальных бенчмарков не бывает, слишком много влияющих параметров.
                              • 0
                                Перегнал тесты по nginx с worker_processes = 8 и выключенным AMD Turbo Core и Cool'n'Quiet.
                                Результаты — минус 1-2 процента производительности почти по всем итерациям (макс. результат — 136485, упал до 135620 (-0.6%).
                                Утверждение о влиянии AMD Turbo Core выглядит сомнительным.
                                К вопросу о тестировании на разных машинах — какие модели сетевых карт были бы приняты за достоверно отображающие производительность? Например, подходит ли для адекватного тестирования Broadcom BCM57780? Realtek RTL8139? Что можете сказать о свиче?
                                • +1
                                  У вас система с worker_processes = 8 упирается вовсе не в сервер. По опыту, системные вызовы клиентской части тяжелее, и чтобы упереться в nginx нужно под клиент выделить существенно большие ресурсы.

                                  Я могу рассказать, как я замеряю. 12-ти (физических, вирутальных 24) ядерный сервер. Если вопросы скалирования не интересуют (нужно определится, что измеряем — скалирование или производительность, а мешать всё в кашу — нельзя), то тестировать имеет смысл только с одним рабочим процессом. Выставляем worker_processes 1; и worker_cpu_affinity (последнее особенно для FreeBSD актуально, ибо планировщик там может чудить). Динамическое скалирование частоты процессора отключаем, система чистая, никаких cron-задач, работающих фоновых служб и прочего. Берем клиент (самый производительный из известных мне — wrk, остальные становятся узким местом раньше) и запускаем цикл измерений в 8 потоков (ещё 3 физических ядра пригодятся системе) — 30-100 измерений по 30-120 секунд, замеры сохраняем в файл для последующего анализа с помощью ministat (числа без указания погрешностей — можно рассматривать только ради развлечения). Применение всех изложенных мер позволяет получить относительную погрешность в пределах 2% (ни о каких 0.6% разницы речи идти не может, на реальной системе едва ли сможете измерить с такой точностью).

                                  В вашем тесте вы скорее всего протестировали weighttpd с помощью разных серверов (а не наоборот). Какой из них имеет паттерн обработки запросов более согласующийся с упомянутой утилитой, таким образом входя в резонанс при определнных условиях. Для получаения более-менее достоверных результатов клиент должен обладать запасом по производительности минимум раза в 2-3 превосходящим сервер, а в идеале на порядок.
                                  • 0
                                    Т.е. на моей конфигурации (8 физических ядер) достаточно будет 1 рабочего процесса (с заданным аффинити), 4 потока клиента (3 ядра остается системе), 30-100 измерений по 30-120 секунд. Ок, прогоню такие тесты с weighttp и wrk, результаты предоставлю.
                                    • 0
                                      Пока все в процессе, но первые (грубые) результаты по вашей методике (1 серв. процесс с афинити, 4 потока клиента с аффинити) аналогичны результатам из моих первоначальных тестов (там ведь тоже были режимы с 1 серв. процессом). nginx в этом режиме опережает остальных топовых участников в 2.5 раза. Ваш комментарий по этому поводу, как разработчика nginx?
                                      Кстати, wrk показал 1-3% прирост по сравнению с weighttp. Подробные результаты будут позже…
                                      • 0
                                        Так я уже выше об этом и написал, что в остальных режимах вы упираетесь не в веб-сервер, а в бенчмаркалку. В nginx практически нет взаимодействия между процессами и единственным узким местом может стать только слушающий сокет, а до тех пор производительность должна расти линейно с увеличением числа рабочих процессов.

                                        В тот момент же, когда вы упираетесь в бенчмаркалку то возникают всякие пограничные эффекты. Помню год назад один человек написал в рассылку, он тестировал с помощью ab и с удивлением обнаружил, что выключение логов дает не прирост производительности, а наоборот — регрессию. Включая access_log он стабильно наблюдал заметно больший rps. Я изучил этот случай, и вот что выяснилось: с выключенными логами рабочий процесс nginx-а то и дело уходил в спячку, ab не успевал прислать следующий запрос после завершения обработки всех предыдущих, но если включить логи, то лишний write() строчки лога на диск на каждый запрос чуть подтормаживал процесс и ab чаще успевал прислать запрос, так что nginx не оставался совсем без работы и не засыпал, последнее оказывалось существенно дороже записи логов.
                            • +2
                              Node.js — не хайлоад-решение и никогда так не позиционировался. Он «быстрый» в смысле «быстрее, чем аналогичные решения на других скриптовых языках — Python, Ruby, Perl, PHP», а не в смысле «быстрее всех». Члены команды разработки Node.js даже никогда не обсуждают его скорость в сравнении с Go, Rust, C++ и другими компилируемыми языками. Не сравнивают они его и с высокопроизводительными VM типа Java или .NET: у тех в запасе почти 2 десятка лет работы над производительностью. Сегодняшний V8 по уровню развития как раз сравним с JVM примерно десятилетней давности.

                              В вашем конкретном случае в дополнение к собственно работе с HTTP ему еще приходится запускать виртуальную машину, заниматься сборкой мусора и JIT-компилировать код и т.д. Поэтому сравнивать его с Nginx или libevent вообще не имеет смысла. Вы же не сравниваете скорость болида Формулы 1 и тролейбуса, правда?
                              • –1
                                PayPal — хайлоад? Как прокомментируете перевод фронтов (для начала) с JVM на Node.js. Ещё из списка: Ebay's ql.io, Linkedin, Wallmart, Trello, Groupon и ещё. Что для вас хайлоад? Сотня млн. запросов в день, норм? А несколько сотен?

                                П.С. Разница в 3х между, к примеру, nginx и node.js — всё-таки это как Формула 1 и, скажем, средний спорткар, но не троллейбус :).
                                • +4
                                  Вы ж понимаете, что это громкие слова. По пунктам:

                                  PayPal: переводят сайт на NodeJS с Java. Процессинг платежей так и остается на смеси Java и C++, и планов по миграции на что-то другое для этих задач нет. Цель миграции для сайта — иметь возможность быстро менять наполнение, проводить A/B тесты для конверсий и т.д. Т.е. сугубо маркетинговые задачи. С той же легкостью они могли мигрировать на Django или Rails — им просто нужен был инструмент, позволяющий работать с фаннелом в очень сжатые сроки. Ну и сами понимаете, сайт для них — это не узкое место в плане производительности.

                                  Walmart и LinkedIn: Node.js используется как прокси для мобильных сервисов. Весь тяжелый процессинг так же остается на стороне Java. Поэтому неудивительно, что на Black Friday в волмарте Нод вел себя спокойно — он также не был узким местом.

                                  Групону до перехода хватало производительности Рельсов. Тот факт, что Node.js им подошел, меня нисколько не удивляет. Кроме того, при переходе ребята сильно переработали архитектуру всего сервиса, и основной выигрыш в производительности поличили именно от этого, а не от скорости v8.

                                  Trello — небольшой проект. Называть хайлоадом все, что смотрит в интернет, я бы не стал.

                                  ql.io мертв уже больше года. Но даже когда он еще жил, он был «research»-проектом и никогда не процессил больших объемов данных. В инфраструктуре Ebay он не используется. Ближайший аналог — YQL — крутится на JVM+Rhino, и там нагрузки действительно колоссальные.

                                  > Что для вас хайлоад? Сотня млн. запросов в день, норм? А несколько сотен?

                                  Хайлоад не начинается с какой-то четкой границы. И не зависит только от запросов в секунду. Например, допустим, у нас есть сервис, в котором нет сетевых эффектов: у каждого пользователя свой набор данных и никто не запрашивает чужие данные: т.е. нет никакого обмена сообщениями, общих документов, одновременного редактирования и т.п. Один железный бокс в такой системе обслуживает 50 пользователей с комфортным запасом по производительности. У нас 5 миллионов пользователей, и для них мы подняли 100 тысяч таких боксов, пошардили данные и настроили лоад-балансер и автозамену падающих узлов. Если их станет в два раза больше, мы просто поднимем в 2 раза больше боксов, и за исключением выросших затрат на хостинг, к никаким другим последствиям это не приведет. Хайлоад ли это?

                                  А вот если есть сетевые эффекты, то рост пользовательской базы в 2 раза может легко привести к тому, что какие-то части системы не смогут работать без значительной переработки. Вот именно такие «узкие места» в производительности в моем понимании — хайлоад. В Фейсбуке это рассылки уведомлений, сообщений, обновление новостных лент. А вот система загрузки фотографий явно скейлится линейно с ростом нагрузки, и хайлоадом при всем количестве железа может быть названа только с натяжкой.

                                  Во всех вышеперечисленных примерах Node.js, хоть и является частью большой системы, но не оказывается узким местом в плане роста инфраструктуры, поэтому заслуги платформы в успехе данных проектов практически нет. На месте Node.js мог оказаться Питон, Руби, PHP или Perl, и ничего бы кардинально не поменялось.

                                  И да, Нод я люблю и на нем работаю. В нашем проекте есть части на Node.JS, Erlang, Java, Python, и несмотря на миллионы пользователей и большую нагрузку, я не могу назвать части, написанные на NodeJS, хайлоадом. Узкие места сейчас для нас покрывают Erlang и Java — там хайлоад есть. Показательно, что именно из-за них мне приходится иногда просыпаться по ночам. Из-за Node.js я не просыпаюсь не потому, что он супер-надежный, а потому, что он не находится на критическом пути.

                                  В этих компаниях та же ситуация, и я уверен, что пока Эран и его друзья смотрели на равные графики нодовских процесссов, ребятам из отделов бекенд-сервисов Волмарта пришлось изрядно попотеть.

                                  Единственный хайлоад-проект на Ноде, о котором мне известно — это Voxer.
                                  • –2
                                    Ну почему же громкие слова? Как раз-таки я посчитал ваше утверждение "Node.js — не хайлоад-решение" — весьма смелым. Я с этим не согласен и, уверен, парни из PayPal тоже. Нода не для тяжёлой логики (и вообще чего-либо CPU-intensive), это да.

                                    Ваша мысль понятна, для вас хайлоад определяется тяжеловестностью выполняемой логики (которую выполняют, как правило, бэкэнды). Это логично. Но вот возьмём два 8-ядерных commodity-сервера: на одном Java/C[++] обрабатывает какую-нибудь длинную очередь HD-видео от 100 клиентов, загружая под 100% все ядра; на другом крутится Нода с 7 форками (с лёгкой логикой, вроде отдачи из кэша), крутится хорошо, на 40K RPS, тоже загружая под 100% сервер. Первое — хайлоад (что очевидно), а второе тогда что, если не хайлоад?

                                    Как тогда, по-вашему, называть, допустим, отдачу статики 15 млн. пользователям ежедневно? Ну вот нету ничего тяжелого в проекте (к примеру всякого рода t.co/bit.ly, хостеры картинок и т.п.).

                                    То, что грамотное горизонтальное маштабирование позволяет использовать %language% — это понятно. Также понятно, что для тяжёлой логики есть JVM / .NET / компилируемые языки.

                                    Во-вторых, скорость работы и стабильность для конечного пользователя — критически важный показатель для такой системы как PayPal (всё-таки не хостинг картинок с котиками). Ежедневно через систему проходят платежи на сотни млн. $.

                                    Факт того, что PayPal переводит эту часть (фронты) на Ноду, вполне говорит нам, что она production ready && highload ready.
                                • 0
                                  Из того, что я про него читал здесь (раздел How is it so fast?), в node.js нет оверхедов на JIT-компиляцию и виртуальная машина не вовлечена в процесс, незнаю насколько это соотвествует действительности.
                                  На практике помню, что GC практически полностью парализовывал работу сервера.
                                  • 0
                                    До тех пор, пока последовательное выполнение инструкций будет основой архитектуры информационных систем, нужно всё таки делать поправки на ветер. Самой системе нужно оставлять хоть что-нибудь, хоть одно ядро, чтобы она жила.

                                    Можно почитать что-нибудь типа Ч. Петцольд — Код
                                    • 0
                                      Из вашей статьи:

                                      It’s speed comes from the fact that it compiles JavaScript directly into native assembly.


                                      Таки Jit-компиляция есть, сборка мусора есть. Т.е. оверхед есть.
                                      • 0
                                        Не происходит ли Jit-компиляция единожды, в момент запуска скрипта?
                                        • +1
                                          Нет, там компиляция проходит в несколько этапов: вначале генерируется неоптимизированный код, а затем по ходу его выполнения собирается информация о частоте вызова методов и фактических типах параметров и переменных. По этим данным собирается оптимизированный код. Если в какой-то момент встречается какой-то новый тип, то приходится возвращаться к первоначальному варианту кода, но данные продолжают собираться, чтобы подготовить новый оптимизированный вариант. В сложных случаях — в частности в NodeJS этой бедой страдает EventEmitter — виртуальная машина вынуждена оптимизировать и деоптимизировать одни и те же функции снова и снова.
                                  • 0
                                    • 0
                                      Недавно занимался нагрузочным тестированием и открыл для себя httpress: bitbucket.org/yarosla/httpress/wiki/Home По производительности он показал себя лучше, чем ab, хотя у ab более подробная статистика прогона.
                                      • 0
                                        Утилита от создателя дисквалифицированного nxweb. По заявлению автора — Inspired by weighttp tool, синтаксис ком. строки полностью совпадает.
                                        Компиляция осложнена linux-зависимостями типа sys/sendfile и memalign (патчится легко).
                                        При запуске выкидывает кучу ошибок соединения, потом тесты проходят, результат аналогичен weighttp.
                                        Других различий не обнаружил.
                                        • 0
                                          Компиляция осложнена linux-зависимостями типа sys/sendfile и memalign (патчится легко).

                                          с чего бы вдруг сендфайл стал linux-зависимостью?! :) тем более, что в freebsd/solaris он тоже есть?

                                          и для генератора нагрузки sendfile() не нужен. разьве что для POST'а.
                                          • 0
                                            sendfile
                                            Not specified in POSIX.1-2001, or other standards.
                                            Other UNIX systems implement sendfile() with different semantics and prototypes. It should not be used in portable programs.
                                            В данной утилите он не нужен, но он там почему-то есть.
                                            • 0
                                              я знал, что вы туда сошлётесь :) ну нет в posix.1-2001… и что? :)
                                              linux-зависимость — это epoll/splice/vmsplice/fincore. но явно не достаточно портабельный sendfile.
                                              • 0
                                                ну нету в FreeBSD файла sys/sendfile.h :) (и нигде нет, кроме linux).
                                                Это все про общую «небрежность» кода, что заставляет задуматься об использования этой тулзы в любых тестах.
                                            • 0
                                              с чего бы вдруг сендфайл стал linux-зависимостью?! :) тем более, что в freebsd/solaris он тоже есть?
                                              Он в этих системах разный. В nginx, например, для FreeBSD, Linux, Solaris и Darwin — 4 отдельных реализации, везде есть нюансы.
                                        • +6
                                          Удивительно, как меняется мир. Добавить apache никому даже в голову не пришло.
                                          • 0
                                            Признаться — была такая мысль, но как-то не попалось готового модуля, который можно быстро переделать под нужды тестирования (все больше какие-то пространые мануалы с вовлечением apxs и прочих ужасных вещей). Та же участь постигла lighttpd. Но это, я думаю, и не страшно — тут тестируются C/C++ библиотеки/фреймворки, nginx и node.js приведены лишь для сравнения с миром «готовых» HTTP-серверов. А так да — в черновиках была целая простыня из mongrel, cherokee и т.п.
                                          • +2
                                            Было бы интересно увидеть в сравнении еще Go и Rust. Эти языки компилируются в нативный код. Ещё мне ыбло бы интересно увидеть Erlang
                                            • 0
                                              А вообще, методика тестов странная, как и выводы.
                                              настройки sysctl.conf странные, mbuf-кластеров мало, цифр по netstat/vmstat -z нет.

                                              я писал однопоточный http-сервер на python(gevent) и без каких-либо ухищрений он выдавал 11k rps. тесты выполнялись на реальном железе через линк в 1GEx2.
                                              это написанное на интерпретируемом языке и без jit. есть у меня мысли перенести это на pypy и посмотреть цифры.
                                              • 0
                                                В системе настройки не менялись, они не давали прироста производительности (см. параграф под настройками в статье).
                                                Какой утилитой тестили python сервер?
                                              • НЛО прилетело и опубликовало эту надпись здесь

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