Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.
Методология
Как ruststream-sqs-sns измеряет себя: три цикла, прогон на конечной точке SQS, арифметика
«упирается в брокер» и подсчёт кода. Процедура общая для всего фреймворка
(методология RustStream),
а эта страница говорит, как она выглядит на SQS.
Три цикла
Один процесс прогоняет каждый сценарий трижды, тремя циклами, которые различаются одним: тем, что переносит сообщения.
- Сырой клиент.
aws-sdk-sqs, напрямую: получить десять сообщений за вызов, декодировать каждое, удалить каждое. Пока цикл завершает пакет, который держит, одно получение остаётся в работе, как у задачи приёма этого крейта. - Крейт брокера. Этот крейт и ничего над ним: брокер подключается, дескриптор
SqsQueueоткрывает подписку, а цикл забирает доставки из её потока, декодирует их и подтверждает. - RustStream. Сервис, который пишет пользователь: обработчик
#[subscriber]и приложение вокруг него.
Всё остальное в трёх циклах одинаково: конфигурация AWS, тайм-аут попытки 25 секунд, получение
десяти сообщений с ожиданием 20 секунд, DeleteMessage на каждое сообщение, декодирование в ту же
структуру, байты тела, рантайм tokio с четырьмя рабочими потоками и бинарник.
Тело сообщения - 512 байт JSON. Оно декодируется в структуру из двух целочисленных полей, поэтому декодирование ничего не выделяет, и число говорит об этом крейте, а не о парсере JSON.
Прогон
- Новая очередь на каждый прогон. Очередь создаётся перед прогоном и удаляется после него, поэтому прогон никогда не видит того, что оставил предыдущий.
- Потребитель подключается первым. Затем восемь издателей заполняют очередь, по одному
SendMessageна сообщение, и опережают потребителя не больше чем на 4096 сообщений. - Окно открывается на первой доставке и закрывается, когда обработана последняя, во всех трёх циклах. Создание очереди, сборка клиентов и открытие подписки в него не входят.
- Число сообщений даёт пробный замер скорости сырого цикла, поэтому измеряемый прогон на любой машине длится не меньше пяти секунд.
- Циклы чередуются: сырой, крейт, RustStream, три круга. Каждый цикл сообщает свой лучший, медианный и худший круг.
Строка получает пометку «упирается в брокер», когда обмены с конечной точкой занимают не меньше
половины времени доставки. Это арифметика. Пробный замер засекает самый короткий запрос, на
который отвечает конечная точка, на собственном клиенте, по 2000 вызовам. Доставка стоит одного
обмена на свой DeleteMessage и десятой доли ReceiveMessage, в ответе на который пришёл её
пакет. Строка получает пометку, когда их произведение достигает половины измеренного времени на
сообщение. Круговая задержка публикуется вместе с машиной, так что арифметику можно проверить.
Подсчёт кода
Каждый сценарий графика стоимости - сервис, который пишет
пользователь, на SqsBroker против той же конечной точки,
собранный без фичи testing и запущенный на однопоточном рантайме. Другой поток заполняет очередь
до того, как открывается измеряемая область, и этот поток не учитывается.
Инструкции даёт callgrind, выделения памяти - DHAT. Сценарий прогоняется на одной доставке, затем на 1000, затем на 2000. Разность двух последних - установившаяся стоимость сообщения, а одна доставка - холодный старт.
Счёт охватывает всё, что выполняет поток сервиса: рантайм, этот крейт и AWS SDK с его стеком HTTP. Потоки, которые SDK запускает сам, не учитываются, как и сторона конечной точки в каждом обмене. Четыре прогона одного бинарника совпадают по инструкциям с точностью до половины процента, потому что то, как отвечает конечная точка и как делятся чтения из сокета, немного меняется между прогонами. Прогон против сохранённого базового замера падает, если сценарий тратит на два процента больше инструкций. Выделения памяти на каждом прогоне сверяются с порогом, который объявляет каждый сценарий: наибольшее наблюдённое число плюс десятая доля процента.
Как запустить самому
just bench
Рецепт поднимает стенд LocalStack из 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 на ветке сравнивает с ним.