[Перевод] Независимый HttpBench для D, или врут ли тесты TechEmpower?

Простой фреймворк для тестирования HTTP-серверов, вдохновленный Simple Web Benchmark (Прим.пер. Там есть график для многих других языков), но сфокусированный на dlang фреймворках и библиотеках.

Он измеряет достижимый RPS (запросы в секунду) в сценарии простого текстового ответа (plaintext).

Тесты были собраны или изменены из различных мест (в том числе TechEmpower).

Он использует докер-контейнер для построения и размещения сервисов и может работать локально или использовать нагрузочный тестер с удаленного хоста.

В качестве генератора нагрузки используется по умолчанию wrk и запрашивает статистику у коллектора, но hey тоже поддерживается (просто используйте ключ --tool).

Тесты можно запускать и без докера, достаточно лишь установить компиляторы для протестированных языков и генератор загрузки wrk/hey (но протестировано только на linux).

Примечание для тестов io_uring:


  • Для работы тестов необходимо как минимум ядро Linux 5.7.
  • Также возможны проблемы с пользовательскими ограничениями на залоченную память (ulimit -l) при запуске с обычным пользователем.
  • Наблюдается некоторая регрессия производительности, начиная с Kernel 5.7.16. См. еще баги: #189, #8.


Тесты

Тесты делятся на два типа:


  • singleCore  — сервисы запускаются в режиме одного ядра для измерения производительности без нескольких потоков/процессов (по умолчанию).
  • multiCore  — сервисы начинают использовать все ядра процессора хоста


Использование


Сборка контейнера дли запуска


  • make build — сборка контейнера
  • make shell — запуск контейнера
    Примечание: Гувернер производительности с помощью этой команды выставляется в режим производительности.


Запуск тестов

Тупо для теста, просто запустите одну команду из (в шелле контейнера):

make all        # runs all tests
make single     # runs tests limited to single CPU core usage
make multi      # runs tests limited to multiple CPU cores usage

Основная точка входа для продвинутых тестов находится в _suite/runner.d который представляет собой исполнимый CLI-сценарий.


  • _suite/runner.d list — выдать список доступных тест-бенчмарков
  • _suite/runner.d bench — запустить тесты
  • _suite/runner.d responses — выдавать ответы от каждого тестового сервиса
  • _suite/runner.d versions — выдать используемых перечень языков и версий в формате Markdown таблицы
    Используйте _suite/runner.d -h для справки по CLI интерфейсу.

Пример:

_suite/runner.d bench --type singleCore dlang rust # запустить все тесты для dlang и rust 


Тестирование удаленного хоста

Поскольку не рекомендуется использовать только локальный хост для бенчмаркинга (см. линк), CLI поддерживает выполнение тестера нагрузки с удаленного хоста.

Шаги:


  • на хосте, на котором будут работать серверы, войдите в шелл контейнера.
  • оттуда запустите что-то вроде _suite/runner.d bench --type singleCore -r foo@192.168.0.3 --host 192.168.0.2 dlang

Где -r или --remote указывает имя пользователя и имя хоста, используемое для выполнения загрузочного тестера через ssh. --host в большинстве случаев не нужен, так как CLI определяет IP хоста по маршруту по умолчанию, но он добавляется для случаев, когда он все равно нужен.

Проще сгенерировать ключ ssh и скопировать его идентификатор на хост генератора нагрузки, так как в противном случае основная команда ssh будет запрашивать пароль дважды для каждого теста (разогрев и сам тест).

Загрузочный тестер (hey) должен быть установлен на хосте нагрузочного тестера.

Хост, генерирующий нагрузку, в идеале должен быть более производительным.


Фреймворки / библиотеки

Были добавлены некоторые из топовых фреймворков с Techempower в качестве базовых точек для сравнения.

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


  • нет маршрутизатора (т.е. совпадение только по длине пути и т.д.)
  • нет парсера HTTP-запросов
  • предварительно собранный статический текст для ответа
  • и всё такое

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


C

Эти варианты добавлены для определения потенциала конфигурации тестовой среды. Они не пытаются работать как обычные HTTP-серверы, а просто используют eventloop на максимальной скорости.

Добавлены epoll и io_uring. Оба именуются как raw.


dlang

arsd-official

Я хотел добавить эту популярную библиотеку в список для сравнения. В настоящее время используются три конфигурации внутренних http серверов:


  • process — форкнутый процесс, каждый из которых обслуживает один запрос.
  • threads — threadpool для работы с подключенными клиентами
  • hybrid — экспериментальная гибридная реализация только для Linux смеси форков, тредов и файберов в цикле событий.

Они добавляются в тесты singeCore, так как они не используют (на данный момент) несколько eventloop, так что мы можем сравнить этот традиционный способ (прим.пер. CGI) с другими в этой категории.

См. описание от автора — Адама.

during


  • raw — тест, который старается быть как можно быстрее, чтобы достичь теоретического предела используемой системы (поэтому никаких парсеров, маршрутизаторов, … — просто ивентлуп)
    TBD — Используя новый асинхронный ввод/вывод io_uring, было бы интересно сравнить с наиболее часто используемой epoll на Linux-системах.

epoll

Не библиотека, а просто основной механизм опросов, используемый большинством фреймворков. Добавлено к тестированию теоретического предела системы, на котором мы измеряем — так же, как during/raw

eventcore

Библиотека, которая является основой для фреймворка vibe-d. Она обобщает цикл событий как для epoll на linux (iocp и kqueue на windows и MacOS).

Это микробенчмарк, так как он не имеет правильного http парсера, маршрутизатора или модуля построения ответов, и в настоящее время отображает только потенциал цикла событий библиотеки.


  • callbacks — использует только обратные вызовы для обработки событий сокета.
  • fibers — использует файберы для эмуляции синхронного поведения при асинхронных событиях

hunt


  • hunt-http — идиоматическое использование фреймворка (HTTP-маршрутизатор, парсер и все остальное)
  • hunt-pico — высоко специализированный и оптимизированный тест, использующий picohttpparser и настраиваемые обработчики только для тестовых целей (предварительно построенные ответы, отсутствие маршрутизатора, …) — неудивительно, что он относительно высоко в Techempower

lighttp

Нашёл на code.dlang.org, так что тоже добавил в микс.

В нем есть парсер, маршрутизатор и генератор ответов.

mecca

Основная библиотека из Weka.

В ней используется собственная низкоуровневая реализация файберов.

Замечание: Использует некоторые хаки для доступа к внутренностям druntime, чтобы иметь возможность переключать файберы. Но она не компилируется с текущим релизом и несколькими компиляторами. Я пытался это поправить, но все еще остались некоторые проблемы.

photon

Этого нет на code.dlang.org, но это интересная библиотека, которая переписывает syscalls glibc и эмулирует их через epoll eventloop и файберы, внутри себя.

В тесте используется nodejs http-parser (не такой быстрый, как pico) и не используется маршрутизатор.

vibe-core

Библиотека более высокого уровня, использующая eventcore и добавляющая основанный на файберах фреймворк для вызова коллбэков.

По-прежнему является микробенчмарком, так как использует только TCPConnection и читает запрос построчно, а затем просто пишет статический текст ответа.

Не используется ни маршрутизатор, ни http парсер.

vibe-d

Наконец-то самый популярный веб фреймворк для dlang, который содержит все.


dotnet

В качестве сравнения используется ASP.Net Core.

В нем есть несколько настроек, упомянутых выше (упрощенный маршрутизатор, готовые текстовые ответы, …). Прим.пер. Посмотрев код, я таки отнес его к полноценным тестам.


golang

fasthttp используется в качестве справочного.

Тест использует только HTTP парсер, но не маршрутизатор.


rust

Actix используется для сравнения в двух вариантах:


  • actix-web — обычное использование библиотеки
  • actix-raw — более тонко настраиваемый вариант с менее общеупотребительным функционалом


Результаты


Single core results (однопоточные)

Генератор нагрузки: AMD Ryzen 7 3700×8-Core, kernel 5.8.10
Тестовая машина: Intel® Core i5–5300U CPU @ 2.30GHz, kernel 5.8.9
Сеть: 1Gbps through cheap gigabit switch
Команда тестирования: for i in 8 64 128 256; do _suite/runner.d bench --type singleCore --tool wrk -b 2 -d 120 -c $i -r tomas@10.0.0.2; done


Версии компиляторов

От переводчика. Полные версии таблиц с результатами можно посмотреть в оригинале. Но там все неочевидно перемешано, потому я сделал более наглядные графики по кол-ву обработанных запросов за 2 минуты (req, rps пропорционально) для двух категорий — полноценные фреймворки без твиков и все остальные, включая базовые библиотеки. И два результата — для 8 воркеров и для 256, чтобы показать масштабируемость.

jci2cmcenicw42e-webp5wninlc.png
xgdwigrhdfwjmo-vke9hyruu9nc.png

И да, тесты TechEmpower, смешивая твикнутые версии с обычными, изрядно местами приукрашивают.

© Habrahabr.ru