Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.
Методология
Как ruststream-rdkafka измеряет себя: три цикла, прогон на настоящем брокере, арифметика
«упирается в брокер» и подсчёт кода. Процедура общая для всего фреймворка
(методология RustStream),
а эта страница говорит, как она выглядит на Kafka.
Три цикла
Один процесс прогоняет каждый сценарий трижды, тремя циклами, которые различаются одним: тем, что переносит записи.
- Сырой клиент.
StreamConsumerиз rdkafka, напрямую: получить, декодировать, сохранить смещение. - Крейт брокера. Этот крейт и ничего над ним: брокер подключается, дескриптор темы открывает подписку, а цикл забирает доставки из её потока, декодирует их и подтверждает.
- RustStream. Сервис, который пишет пользователь: обработчик
#[subscriber]и приложение вокруг него.
Всё остальное в трёх циклах одинаково: свойства консьюмера, группа консьюмеров, режим фиксации, место ack, декодирование в ту же структуру, байты полезной нагрузки, рантайм tokio с четырьмя рабочими потоками и бинарник.
Тело сообщения - 512 байт JSON. Оно декодируется в структуру из двух целочисленных полей, поэтому декодирование ничего не выделяет, и число говорит об этом крейте, а не о парсере JSON.
Прогон
- Новая тема и новая группа консьюмеров на каждый прогон. У темы одна партиция, и после прогона она удаляется, поэтому прогон никогда не видит того, что оставил предыдущий.
- Консьюмер вступает в группу первым. Продюсер работает на собственном клиенте и начинает, когда кластер сообщит об участнике группы.
- Окно открывается на первой доставке и закрывается, когда декодирована последняя, во всех трёх циклах. Вступление в группу и создание темы в него не входят.
- Число сообщений даёт пробный замер скорости сырого цикла, поэтому измеряемый прогон на любой машине длится не меньше пяти секунд.
- Циклы чередуются: сырой, крейт, RustStream, три круга. Каждый цикл сообщает свой лучший, медианный и худший круг.
Строка получает пометку «упирается в брокер», когда сырой клиент провёл прогон в ожидании сокета. Это арифметика. Один пробный замер засекает запрос метаданных и ответ на него, второй считает запросы, которые librdkafka отправляет на одну доставку. Строка получает пометку, когда их произведение достигает половины измеренного времени на сообщение. Круговая задержка публикуется вместе с машиной, так что арифметику можно проверить.
Подсчёт кода
Каждый сценарий графика стоимости - сервис, который пишет
пользователь, на KafkaBroker против того же брокера, собранный без фичи testing. Группа
консьюмеров читает тему из одной партиции, а другой поток заполняет тему до того, как открывается
измеряемая область.
Инструкции даёт callgrind, выделения памяти - DHAT. Сценарий прогоняется на одной доставке, затем на 1000, затем на 2000. Разность двух последних - установившаяся стоимость сообщения, а одна доставка - холодный старт.
Брокер настоящий, поэтому счёт меняется между прогонами одного бинарника: как часто поток сервиса находит очередь пустой и ждёт, зависит от времени. За три прогона сценарии чтения и пакета совпали с точностью до сотой доли процента, а сценарий ответа сдвинулся на 2,3 процента. Поэтому прогон против сохранённого базового замера падает, если сценарий тратит на пять процентов больше инструкций, тогда как у ядра предел - два процента. Выделения памяти на каждом прогоне сверяются с порогом, который объявляет каждый сценарий.
Как запустить самому
just bench
Рецепт поднимает стенд из docker-compose.test.yml, прогоняет оба сценария сравнения,
останавливает стенд и перезаписывает docs/benchmarks/results.json. Это занимает около
пятнадцати минут, и машина на это время нужна целиком. Рецепт очищает RUSTFLAGS, поэтому
бинарник не привязан к процессору, на котором его собрали. Оба рецепта собирают замеры так же,
как собирается выпуск: с полной оптимизацией при компоновке через границы крейтов. Поэтому числа
описывают тот код, который получает сервис.
just bench-code
Подсчёт кода занимает минуту-две и требует valgrind. just bench-code --save-baseline=main на
main записывает базовый замер, а just bench-code --baseline=main на ветке сравнивает с ним.