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

00d58fd62d4016425293605b07de22f0.jpeg

Привет, Хабр! Меня зовут Дмитрий Королёв, я инженер по нагрузочному тестированию Platform V Pangolin — целевой СУБД в Сбере и не только. Эту статью я написал вместе с моим коллегой Алексеем Хорохориным @AlexeyHorohorin. Наш продукт — специальная сборка 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 заметно упростил нам работу. Теперь мы можем:

  • запускать нагрузку одной кнопкой;

  • настраивать мониторинг на ВМках;

  • менять конфигурацию окружения, где тестируем, конфигурацию сценариев;

  • запускать несколько сценариев подряд;

  • собирать результаты по каждому виду теста и формировать подробные и удобные отчёты.

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

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

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

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

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

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

3f8055f7db370f21f2b5ce62c126fd54.png

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

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

А если у вас есть такой опыт в автоматизации нагрузки, будем благодарны за комментарии. Спасибо за внимание!

© Habrahabr.ru