Перейти к основному содержимому
Нормативная версия документации - английская

Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.

Методология

Как ruststream-pulsar измеряет себя: три цикла, прогон на настоящем брокере, арифметика «упирается в брокер» и подсчёт кода. Процедура общая для всего фреймворка (методология RustStream), а эта страница говорит, как она выглядит на Pulsar.

Три цикла​

Один процесс прогоняет каждый сценарий трижды, тремя циклами, которые различаются одним: тем, что переносит сообщения.

  • Сырой клиент. Консьюмер крейта pulsar, напрямую: получить, декодировать, подтвердить.
  • Крейт брокера. Этот крейт и ничего над ним: брокер подключается, PulsarSubscription открывает подписку, а цикл забирает доставки из её потока, декодирует их и подтверждает.
  • RustStream. Сервис, который пишет пользователь: обработчик #[subscriber] и приложение вокруг него.

Всё остальное в трёх циклах одинаково: подписка и её тип, место ack, декодирование в ту же структуру, байты полезной нагрузки, рантайм tokio с четырьмя рабочими потоками и бинарник.

Тело сообщения - 128 байт JSON. Оно декодируется в структуру из двух целочисленных полей, поэтому декодирование ничего не выделяет, и число говорит об этом крейте, а не о парсере JSON.

Прогон​

  • Новый топик и новая подписка на каждый прогон. Топик персистентный и непартиционированный, в пространстве имён public/default. После прогона он удаляется через API администрирования, поэтому прогон никогда не видит того, что оставил предыдущий.
  • Консьюмер подключается первым. Затем его снабжает продюсер на втором соединении, опережая обработанное консьюмером не больше чем на 20 000 сообщений.
  • Окно открывается на первой доставке и закрывается на последнем подтверждении, во всех трёх циклах. Подключение, подписка и создание топика в него не входят. Подтверждение - это команда, записанная в сокет без ожидания ответа, поэтому ни один цикл не может увидеть, как сервер его записал.
  • Число сообщений даёт пробный замер, который измеряет скорость сырого цикла на 50 000 сообщений, поэтому измеряемый прогон на любой машине длится не меньше пяти секунд.
  • Циклы чередуются: сырой, крейт, RustStream, три круга. Каждый цикл сообщает свой лучший, медианный и худший круг.

Строка получает пометку «упирается в брокер», когда сырой клиент провёл прогон в ожидании транспорта. Это арифметика. Пробный замер вне кругов засекает поиск топика и ответ на него - самый дешёвый запрос, ответа на который ждёт клиент. Сам консьюмер круговой задержки не ждёт: он заранее выдаёт разрешения на получение и подтверждает без ответа. Но за каждой доставкой стоит одна круговая задержка - публикация, которую продюсер держит открытой, пока брокер не сохранит сообщение. Строка получает пометку, когда эта круговая задержка достигает половины измеренного времени на сообщение. Круговая задержка публикуется вместе с машиной, так что арифметику можно проверить.

Подсчёт кода​

Каждый сценарий графика стоимости - сервис, который пишет пользователь, на PulsarBroker против того же брокера, собранный без фичи testing. Подписка Shared читает персистентный топик, созданный для прогона. Другой поток со своим рантаймом и соединением заполняет топик через издатель этого крейта до того, как открывается измеряемая область, поэтому каждое сообщение сохранено раньше, чем сервис возьмёт первое.

Инструкции даёт callgrind, выделения памяти - DHAT. Сценарий прогоняется на одной доставке, затем на 1000, затем на 2000. Разность двух последних - установившаяся стоимость сообщения, а одна доставка - холодный старт.

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

Как запустить самому​

just bench

Рецепт поднимает стенд из docker-compose.test.yml, прогоняет оба сценария сравнения, останавливает стенд и перезаписывает docs/benchmarks/results.json. Это занимает несколько минут, и машина на это время нужна целиком. Рецепт очищает RUSTFLAGS, поэтому бинарник не привязан к процессору, на котором его собрали. Оба рецепта собирают замеры так же, как собирается выпуск: с полной оптимизацией при компоновке через границы крейтов. Поэтому числа описывают тот код, который получает сервис.

just bench-code

Подсчёт кода занимает минуту-две и требует valgrind. just bench-code 5000 измеряет на большем числе сообщений, чтобы число было устойчивее. just bench-code --save-baseline=main на main записывает базовый замер, а just bench-code --baseline=main на ветке сравнивает с ним.