Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

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

Anna | 24.06.2014 | нет комментариев

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

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

Тесты по каждому допустимым параметрам (отдача статики, динамики, всевозможные модули шифрования, прокси и т.п.) — задача не одного месяца заботливой работы, следственно задача упрощена: будем сопоставлять эффективность ядер. Ядро HTTP-сервера (как и всякого сетевого приложения) — это диспетчер событий сокетов и некоторый первичный механизм их обработки (реализованный в виде пула потоков, процессов и т.п.). Сюда же дозволено отнести парсер HTTP-пакетов и генератор результатов. На 1-й взор, все должно свестись к тестированию вероятностей того либо другого системного механизма обработки асинхронных событий (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 4.1** poll да многопоточный (обособленный поток для входящих соединений), с очередью (подробнее)
onion 0.5 epoll да многопоточный
Pion Network Library 0.5.4 Boost.Asio да многопоточный
POCO C Libraries 1.4.3 epoll/select да многопоточный (обособленный поток для входящих соединений), с очередью (подробнее)

Готовые решения

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

*для тестов переделан по схеме «многопроцессный — один процесс один поток»
**Авторы mongoose дословно на днях выкатили 5 версию, в которой фактически с нуля переделана зодчество. Как раз когда все тесты с 4.2 были завершены. Но новая версия все ещё сырая, keep-alive поломан, следственно решено было остаться на 4.2. Но не здесь то было. Создатели решили убрать отовсюду версию 4.2. Максимально доступная стабильная версия стала 4.1. Пришлось откатиться (и переделывать под нее код).

Дисквалифицированы

Имя Повод
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 и 8).
    Исключение — mongoose. У него кол-во потоков сервера неизменно равно числу открытых соединений. При попытках задать макс. кол-во потоков огромнее 50 (значение по умолчанию) — mongoose начинал падать.
  • число параллельно открытых запросов заказчиков (10, 50, 100, 200, 400, 800)

В всякой конфигурации выполнялось по 5 итераций (каждого — 2*6*5=60 итераций для всякого сервера). Ожидалось, что различные сервера покажут себя отменнее в различных конфигурациях.

Итоги

Как и ожидалось, различные сервера показали наилучший итог в различной комбинации вышеназванных параметров. Позже недолгих раздумий, в итоговую таблицу вошли итоги лучшей комбинации для данного сервера. В приложении вы сумеете обнаружить итоги для каждой матрицы значений.

Для 1 млн. запросов имеем:

Место Имя Потоков Время Запросов
Серверных Клиентских Польз. Сист. Удачных (в сек.) Неуспешных (%)
1 hand-made 8 200 23.82987 8.13092 168947 0
2 mongoose 50 200 8.690878 14.812137 154340 0
3 libevent 8 400 24.15859 14.827379 139770 0
4 nginx 8 100 8.379323 9.861154 136485 0
5 POCO 8 50 40.928956 15.933258 86716 0
6 onion 8 50 9.55005 6.030781 64403 0
7 pion 8 400 81.543614 17.370284 48359 0
8 node.js 8 100 121.474981 12.551338 46595 0
9 cpp-netlib 1 100 87.590467 29.244296 16673 0

График потерь (запросы, законченные ошибками либо закрытием соединения для таблицы выше):

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

С победителями (первые 4 места показали примерно идентичную скорость) не все так однозначно. Если посмотреть подробнейший отчёт запусков (bench_res.csv в приложении) то увидим следующее:

  • В hand-made решении в режиме «1 поток сервера на 800 потоков заказчика» (самый «экстремальный» режим работы) процент утраченных запросов колеблется от 15% до 18%. Это нехорошо.
  • У mongoose-а задача с огромным числом соединений (вызвано лимитацией макс. кол-ва открытых соединений сервера — 50). Потери доходят до 58%. И это отслеживается фактически во всех режимах «400 клиентских потоков и выше».
  • У libevent и nginx потерь нет. На все запросы неизменно приходят результаты.

Сравним libevent и nginx. Невзирая на то, что по скорости они фактически идентичны, nginx гораздо проигрывает libevent-у в режимах с 400 клиентскими потоками и незначительно в режимах с 800 клиентскими потоками. Следственно, именно libevent (доработанный до схемы «создаём несколько процессов на одном порте») я бы назвал победителем соревнований, но решать вам.

Не буду хвалить свою реализацию — в всеобщем зачёте она держит 10 первых мест. Невзирая на данный факт, это лишь наколенная имитация HTTP-сервера. Данная реализация больше 2-х лет обрабатывает сотни миллионов HTTP запросов в день от реальных HTTP-заказчиков, собирает результаты с больше сотни разных HTTP-серверов и не нуждается в оправданиях и попытках приравнять ее к полновесным решениям.

node.js, искренне говоря, разочаровал (не так категорично, как выразился товарищ тут, но V8 еще пилить и пилить. Что это за high-load решение, которое даже без пригодной нагрузки так алчно потребляет источники и выдаёт 1/4 продуктивности топовых участников тестирования? Дозволено добавить, что при создании пригодной нагрузки (скажем, применения модуля async) процессорное время начинает убиваться ещё в 9000 раз огромнее, при этом памяти всякий процесс из cluster-а отъедает больше 500 Мб. Возможно, это проявляется лишь на FreeBSD, но я уверен, что задача в node.js.

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

TODO

  • бенчмарк в режиме «заказчик и сервер на различных машинах». Многие придерживаются теории, что де именно такой режим покажет реальную картину. С иной стороны видимо, что все упрётся в сетевые железки, причём не только модели сетевых карт, а свичей, роутеров и т.п. — всю инфраструктуру между реальными машинами. В подключении же напрямую смысла не огромнее, чем через localhost;
  • тестирование клиентской 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-серверов.

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB