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

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

Методология

Как ruststream-gcp-pubsub измеряет себя: три цикла, прогон на эмуляторе, арифметика упора в брокер и подсчёт кода. Процедура принадлежит самому фреймворку (методология RustStream), а эта страница говорит, какой она получается на Pub/Sub.

Три цикла​

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

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

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

Все числа сняты на локальном эмуляторе, который поднимает docker-compose.test.yml, и ни одно из них - на облачном сервисе.

Прогон​

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

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

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

Каждый сценарий графика стоимости - сервис в том виде, в каком его пишет пользователь: он построен на PubSubBroker и запущен против эмулятора того же стенда. Сервис работает в одном потоке, и в счёт идёт всё, что в этом потоке делается: диспетчеризация фреймворка, код этого крейта и клиент google-cloud-pubsub, у которого там же работают streaming pull, подтверждения, продление сроков подтверждения и запросы на публикацию. Эмулятор - отдельный процесс, и в число он не входит. Сообщения публикуются из другого потока до начала разбора очереди, и эта работа в число тоже не входит.

Инструкции считает callgrind, выделения памяти - DHAT. И те и другие даны на сообщение в установившемся режиме: это наклон между прогоном на 1000 доставок и прогоном на 2000. Холодный старт - то, во что один раз обошлись запуск сервиса и первая доставка.

Клиент подтверждает сообщения пакетами и продлевает сроки подтверждения по таймерам, поэтому от прогона к прогону подсчёт немного плавает: за пять прогонов инструкции на сообщение совпали с точностью до 5 процентов, а выделения памяти в самом длинном прогоне - с точностью до 3500 в строке ответа и до 440 в двух других. just bench-code падает, если выделений больше порога, объявленного сценарием: это наибольший увиденный подсчёт плюс запас не меньше этого разброса и не меньше десятой доли процента. С --baseline=main он падает ещё и на приросте инструкций больше двух процентов. Запрос на слияние, который меняет цену, приводит свои числа.

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

just bench

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

just bench-code

Рецепт поднимает эмулятор, подсчитывает график кода под valgrind, снова гасит эмулятор и переписывает раздел code того же документа. Это занимает несколько минут. Кроме Docker, ему нужен valgrind. Исполнитель бенчмарков должен быть того же выпуска gungraun, что закреплён в Cargo.lock: рецепт сам ставит его в target/ при первом запуске и снова, когда выпуск меняется.

Число после имени рецепта задаёт, сколько доставок в измеряемом прогоне (just bench-code 500). Опубликованные числа сняты при значении по умолчанию, 1000. Остальные аргументы уходят исполнителю бенчмарков, например --save-baseline=main или --baseline=main. Прогон, который превысил предел, всё равно проходит все сценарии и печатает таблицу. Под ней он перечисляет каждый превышенный предел: значение, с которым сравнивали, и рядом новое. После этого прогон завершается ошибкой.