Ко всем новостям

Как сделать инструмент для запуска нагрузки одной кнопкой: показываем наш Pangoloader

Публикации в СМИ
01.10.2024
00d58fd62d4016425293605b07de22f0.jpeg

Привет! Меня зовут Дмитрий Королёв, я инженер по нагрузочному тестированию Platform V Pangolin — целевой СУБД в Сбере и не только. Эту статью я написал вместе с моим коллегой Алексеем Хорохориным. Наш продукт — специальная сборка PostgreSQL с доработками (крупных больше 30, а всего уже больше 70) в области безопасности, производительности, отказоустойчивости.

Условия для нас таковы: мы тестируем продукт целиком, в разных версиях, на разных ядрах. У нас работает три версии в параллель для восьми разных ОС, и тестировать нам нужно при использовании и неиспользовании разных фич. А теперь представьте, сколько тут интеграций… Автоматизировать нагрузку помогают разные инструменты. Но в них нам не хватало автоматизации прогона нагрузочных сценариев и составления итогового отчёта по завершении тестов. Поэтому мы сделали и развиваем свой нагрузчик — Pangoloader. В этой статье расскажем, как он устроен, что умеет и как мы собираемся доработать его в будущем. 

Как устроено нагрузочное тестирование очередного релиза Pangolin

Сначала тестируем максимум TPS (транзакции в секунду), подтверждаем его двухчасовым тестом. В тестировании максимума есть ступеньки: поднимаем нагрузку до стабильной ступеньки и гоняем два часа, чтобы убедиться в том, что это точно максимум. Потом 24-часово тест стабильности: смотрим утечки памяти и прочие проблемы, которые могут произойти. После него тест отказоустойчивости (failover). Если отказывает мастер (выходит из строя), то проверяем, насколько успешно и как долго происходит его смена, как реплика становится мастером (реплика — это как запасной парашют).

Раньше мы делали нагрузку самописными скриптами на Bash. Это простой и доступный способ, но он не позволял нам реализовать универсальный механизм для одновременного запуска множества сценариев тестирования. Что ещё важнее, с ним сложно сформировать итоговый отчёт по завершении тестирования. А собирать такой отчёт вручную долго, и ещё нужно не забыть включить всю информацию…Поэтому в конце 2022 года у нас появился свой инструмент для нагрузки.

Что представляет из себя наш Pangoloader

Это связка из двух инструментов:

  • Benchbase — open source-инструмент для проведения нагрузочных тестов для различных СУБД. Его мы доработали под наши требования. 
  • Pangoloader — инструмент на Python. Он позволяет подготавливать и запускать нагрузочные инструменты, такие как Benchbase, отслеживать их статус работы и собирать нам красивый итоговый отчёт на HTML-странице, куда выгружаются настройки СУБД, флаги сборки, графики за время тестирования, бизнес-метрики и системные метрики. 

Эта статья посвящена Pangoloader, но здесь коротко ответим на возможные вопросы про Benchbase и выбор первого решения в связке.Какие еще инструменты можно было использовать:

  • Pgbench содержит базовый сценарий нагрузки, но нам хотелось чего-то посложнее. К тому же pgbench — это встроенный бенчмарк для тестирования PostgreSQL, не получилось бы сравнить производительность на одном сценарии на разных СУБД/
  • Jmeter — у нас не было опыта работы с ним, а всю логику нагрузочного сценария и генерирования данных для него пришлось бы реализовывать на нём, что заняло бы довольно много времени.
  • HammerDB может нагружать различные СУБД для сравнения производительности, но у него всего два сценария нагрузки. 

Выбрали Benchbase, потому что:

  • он может нагрузить разные СУБД;
  • у него много подготовленных сценариев;
  • реализован на Java, у нас в ней есть опыт, можно внести свои доработки;
  • готовая база для создания своих сценариев нагрузки.

Вернёмся к Pangoloader. Вот как всё устроено. Перед запуском утилиты готовим файл конфигурации в формате YAML:

stand: stand_1: ssh_user: pprb_dev host: 65.32.1.29 postgresql: port: 5433 pgbouncer: port: 6544 benchmark: benchbase: host: 65.32.1.30 config: /tmp/tpcc_config.xml command: java -jar /home/pprb_dev/benchbase-postgres/benchbase.jar scalefactor: 2500 terminals: 250 time_load: 300 rate_load: 100 test_port: 6544

Прописываем серверы, на которых расположен тестовый стенд с СУБД, и хост с утилитой нагрузки:

ssh_user: pprb_dev: name: pprb_dev password: pprb_dev_pass postgres: name: postgres password: postgres_pass sql_role: postgres: name: postgres password: P@ssword pangoloader: name: postgres password: P@ssword pgbouncer: name: pgbouncer password: pgbpass

Вот секция для определения SSH- и SQL-пользователей. Они участвуют в тестировании:

grafana: host: 65.32.1.5 port: 3000 api_key: eyJrIjoiTTVhTHpSd... render_params: theme: light width: 1280 height: 720 var-interval: 2s render_processes: 4 prometheus: host: 65.32.1.4 port: 9090

Потом указываем хосты для утилит мониторинга Grafana и Prometheus. Выбираем некоторые параметры для рендера картинок с графиками, которые потом попадают в итоговый отчёт.

Главное требование к инструменту — возможность сохранять подготовленные файлы сценариев и впоследствии запускать их.Сценарий нагрузки выглядит так:

class tpcc_load(Scenario): dbname = 'First_db' time = 7200 rate = 1260 test_port = 'pgbouncer' test_generate_report = True Scenario.description = """Тест подтверждения максимальной нагрузки. Тест проводится на ступени нагрузки, предшествующей L0 (или на уровне нагрузки 90% от L0). Длительность стабильной нагрузки не менее 1 часа."""

Это класс, который представляет из себя сценарий тестирования. Здесь объявляются нужные в этом тесте параметры. Например:

  • dbname — имя тестовой базы данных в СУБД;
  • time — время нагрузки;
  • rate — интенсивность нагрузки;
  • test_port определяет, к какому порту будут подключаться тестовые клиенты;
  • test_generate_report определяет, нужно ли генерировать отчёт по завершении сценария тестирования;
  • Scenario.description — текстовое описание сценария и того, что в нём происходит. Потом это описание попадает в отчёт.

Класс наследуется от класса Scenario. Это абстрактный базовый класс, в нём содержится три метода:

  • setup — служит, например, для предварительной настройки тестируемого объекта. Установка корректных параметров, перезапуск базы, генерация тестовых данных и так далее.
  • execute — сам сценарий теста. Здесь запускается нагрузка, с которой нам надо получить результаты в виде итоговой производительности, метрик системных ресурсов и прочего. Отчёт будет содержать данные только в интервале работы этого метода.
  • teardown — выполняется по завершении нагрузки. Он восстанавливает параметры до исходных значений, чтобы вернуть тестируемый объект в исходное состояние.

Так выглядит метод execute для примера:

def execute(self): benchmark = utils.Benchmark() scalefactor = benchmark.scalefactor terminals = benchmark.terminals if tpcc_load.test_port == 'postgres': conn_string = ','.join(f'{pg.get_host()}:{pg.get_port()}' for pg in config.postgresql_list()) elif tpcc_load.test_port == 'pgbouncer': conn_string = ','.join(f'{pg.get_host()}:{pg.get_port()}' for pg in config.pgbouncer_list()) bench_cfg = benchmark.read_config('/home/pprb_dev/benchbase-postgres/config/postgres/tpcc_load.xml') bench_cfg.find('url').text = f'jdbc:postgresql://{conn_string}/{tpcc_load.dbname}?ApplicationName=tpcc&reWriteBatchedInserts=true&prepareThreshold=0&targetServerType=primary' bench_cfg.find('username').text = config.SQLRole('pangoloader').name bench_cfg.find('password').text = config.SQLRole('pangoloader').password bench_cfg.find('scalefactor').text = f'{scalefactor}' bench_cfg.find('loaderThreads').text = f'{tpcc_load.loaderThreads}' bench_cfg.find('terminals').text = f'{terminals}' bench_cfg.find('works').find('work').find('time').text = f'{tpcc_load.time}' bench_cfg.find('works').find('work').find('rate').text = f'{tpcc_load.rate}' bench_cfg.find('works').find('work').find('weights').text = f'{tpcc_load.weights}' benchmark.write_config('/tmp/tpcc_config.xml', bench_cfg) benchmark.run( "--bench tpcc", "--config /tmp/tpcc_config.xml", "--create=false", "--clear=false", "--load=false", "--execute=true", with_log = True, )

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

pangoloader --config config.yaml --report-template template/base.j2 --log-file pangoloader.log tests.tpcc_load

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

Что получилось в итоге

Pangoloader заметно упростил нам работу. Теперь мы можем:

  • запускать нагрузку одной кнопкой;
  • настраивать мониторинг на ВМках;
  • менять конфигурацию окружения, где тестируем, конфигурацию сценариев;
  • запускать несколько сценариев подряд;
  • собирать результаты по каждому виду теста и формировать подробные и удобные отчёты.

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

5477dd0d22d73da433b8c0afe9979c08.png

Итоговый отчёт

Фиксируем время теста, версию тестируемого объекта, хеш коммита, с которого он был собран. Здесь же выводится таблица с конфигурацией тестового стенда. Если будет несколько хостов, то они будут перечислены по порядку.

Ниже — информация по сценарию нагрузки: какой тестовый сценарий был запущен, с какими параметрами. Схема тестовой базы данных, размер таблиц и количество записей в них, размеры индексов для таблиц. 

И вот информация с результатами в виде графиков мониторинга — тут представлены графики системных метрик (CPU, RAM, disk), статистика интенсивности нагрузки (TPS, latency). Вся эта подробная информация скрыта под ссылками и открывается на отдельных страницах.

3f8055f7db370f21f2b5ce62c126fd54.png

Планы: что хотим добавить в наш нагрузчик

Собираемся и дальше развивать Pangoloader. Самая интересная и сложная фича, которую хотелось бы добавить, — автоматизированный анализ отчётов. Было бы здорово, если бы при открытии отчёта проблемные места автоматически подсвечивались красным цветом вверху страницы. Этого можно достичь, например, сравнив показатели с эталонными значениями и выделив несоответствия. Или сравнив результаты с предыдущими тестами. Но пока это лишь размышления, мы ещё не проверяли идею на практике. Начнём пробовать — будем понемногу рассказывать об этом в сообществе нашей команды, присоединяйтесь, если интересно. А если у вас есть такой опыт в автоматизации нагрузки, будем благодарны за комментарии. Спасибо за внимание!