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

На митапе обсудили, как автоматизировать запуски тестирования производительности в Kubernetes с помощью GitLab CI и объяснили, почему нельзя просто взять и нагрузить Kubernetes. Затронули применение деструктивных тестов в рамках нагрузочного тестирования и разобрали деструктивное тестирование на примере одной из систем. В конце встречи провели круглый стол на тему «Тренды нагрузочного тестирования в 2023 году».

Автоматизация запуска тестирования производительности в Kubernetes

Сергей Данилов рассказал о предпосылках внедрения Kubernetes и нагрузочного тестирования в нем, разобрал путь от идеи до решения и проблем, с которыми столкнулись. А еще рассказал, как реализовали процесс в Gitlab CI в нашей команде.

Стек технологий нагрузочного тестирования
Стек технологий нагрузочного тестирования

Предпосылки внедрения:

  • Сложности доставки аппаратных ресурсов в короткий срок и их оптимизация.

  • Решение вопросов масштабирования.

  • Унификация запуска нагрузочного тестирования после внедрения k8s. Можно использовать те же ресурсы и бонусы, что и ваше приложение от размещения в нем.

Все объекты k8s задаются с помощью конфигурационных файлов, которые описывают структуру сущности объектов:

Pod — минимальный абстрактный объект k8s, содержит в себе один или несколько контейнеров.

Service объединяет поды в группу и определяет доступ к ним.

Ingress описывает правила проксирования трафика от внешнего пользователя до сервисов внутри k8s.

Пример работы приложения: есть внешний клиент и кластер k8s. Клиент отправляет трафик в Ingress, тот по своим правилам routing rule перенаправляет трафик в нужный сервис, у сервиса есть поды, которые ему отвечают. Подов может быть больше, два — минимальное количество для поддержки отказоустойчивости
Пример работы приложения: есть внешний клиент и кластер k8s. Клиент отправляет трафик в Ingress, тот по своим правилам routing rule перенаправляет трафик в нужный сервис, у сервиса есть поды, которые ему отвечают. Подов может быть больше, два — минимальное количество для поддержки отказоустойчивости

Чтобы протестировать нагрузку на сервис, нужно вместо клиента подставить какой-то инструмент, например Gatling. Потом сгенерировать пользовательский трафик, отправить его на Ingress. Если все работает — данные уходят в сервис, поды реагируют.

Выше описан пример простого тестового приложения, но если возьмем продовую среду — там все намного сложнее.

За Ingress находится несколько сервисов, у них разное количество подов, все работает. Допустим, мы решили нагрузить Service1: отправляем нагрузку, Gatling генерирует трафик, отправляет его в Ingress, а тот передает все в Service1. Если в какой-то момент начнутся проблемы — увеличится время ответа, появятся ошибки и негативное влияние пойдет не только на Service1, но и на Service2 и на Service N, может случиться полная недоступность
За Ingress находится несколько сервисов, у них разное количество подов, все работает. Допустим, мы решили нагрузить Service1: отправляем нагрузку, Gatling генерирует трафик, отправляет его в Ingress, а тот передает все в Service1. Если в какой-то момент начнутся проблемы — увеличится время ответа, появятся ошибки и негативное влияние пойдет не только на Service1, но и на Service2 и на Service N, может случиться полная недоступность

Чтобы избежать полной недоступности, мы решили отправлять трафик в обход Ingress, нагружать напрямую Service и запускать тесты внутри namespase.

Еще несколько полезных абстракций:

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

Job — предназначен для выполнения разовых задач, например миграций или бэкапов.

ConfigMap — ресурс для хранения и внедрения конфигурации в контейнеры, можно передавать как Key value, так и списком параметры из файла.

 

Процесс внедрения в запуск нагрузки
Процесс внедрения в запуск нагрузки

Проблемы, с которыми столкнулись при внедрении.

Проблема: сборка docker image — один docker image не подходит для более чем 150 проектов. Проекты и скрипты могут изменяться, и неясно, как это поддерживать.

Решение: собрать проект внутри docker image. Пакуем туда Gatling и различные утилиты, а сами скрипты нагрузочного тестирования копируем на этапе выполнения нагрузочного контейнера.

Пример выполнения команды
Пример выполнения команды

Проблема: как деплоить и что выбрать в качестве сущности деплоя — deployment или job. Кроме того, могут существовать дополнительные требования по поводу деплоймента: например, создавать deployment минимум с двумя подами, и тогда появляется проблема для анализа результатов.

Решение: попробовали использовать deployment, но необходимо дополнительно удалять созданные артефакты. Job выполняет задачу один раз и удаляет артефакты сам.

Проблема: как разделить различные окружения — запуск нагрузочного тестирования в dev- и prod-окружениях. Создавать отдельные docker image и манифесты под каждый стенд слишком затратно.

Решение: использовать Kustomize — инструмент для настройки объектов Kubernetes с помощью конфигурационных файлов, разложенных по слоям. Еще используем утилиту SED — редактор для преобразования текстовых данных, чтобы автоматически подставлять нужные нам параметры.

Структура директорий, которая определяет работу Kustomize. Есть базовый манифест, где описаны общие свойства объектов для всех средств — dev и prod — и overlays, который определяет частные случаи. После запуска базовый манифест патчится с соответствующим образом
Структура директорий, которая определяет работу Kustomize. Есть базовый манифест, где описаны общие свойства объектов для всех средств — dev и prod — и overlays, который определяет частные случаи. После запуска базовый манифест патчится с соответствующим образом

Проблема: как передавать параметры из Gitlab CI в k8s, потому что иначе эти параметры не знают о существовании друг друга.

Решение: создать скриптом ConfigMap и добавить его в манифест.

Пример кода для передачи параметров
Пример кода для передачи параметров

Проблема: логи Gatling. Когда мы запускаем нагрузку, в Gatling пишется очень много логов. Корневой раздел внутри docker-контейнера в нашей инсталляции k8s только read-only, потому что, если записывать в корень данные неконтролируемо, можно получить переполнение дискового пространства на хосте.

Решение: использовать Volume emptyDir. Отличие emptyDir в том, что он живет, пока живет под, который его использует. Еще переопределили параметры запуска sbt: если параметры не определить, то запись будет идти в домашнюю директорию.

Переопределение параметров запуска sbt
Переопределение параметров запуска sbt

Реализация в Gitlab CI по упрощенной схеме выглядит так:

Проверяем версии компонентов, версии кода и компиляции в compline и validate, в custom script пользователь может выполнить свои действия, например сгенерировать параметры или данные. В debug test — тест на несколько итераций, чтобы понять, что система работает и корректно отвечает. Далее идет блок с тестами: например, тесты на поиск максимальной производительности или тест-стабильности и тесты, которые работают с Kubernetes. Потом все данные уходят в Cosmos — систему хранения результатов анализов тестов
Проверяем версии компонентов, версии кода и компиляции в compline и validate, в custom script пользователь может выполнить свои действия, например сгенерировать параметры или данные. В debug test — тест на несколько итераций, чтобы понять, что система работает и корректно отвечает. Далее идет блок с тестами: например, тесты на поиск максимальной производительности или тест-стабильности и тесты, которые работают с Kubernetes. Потом все данные уходят в Cosmos — систему хранения результатов анализов тестов

Подробнее про Cosmos от Иоанна Ахальцева:

В планах — сделать следующие шаги автоматическими: 

  • Запуск тестового стенда для нагрузочного тестирования в k8s.

  • Проведение нагрузочного тестирования.

  • Сохранение результатов.

  • Удаление тестового стенда.

Так экономится значительное количество ресурсов, потому что нам не нужно держать отдельную нагрузочную станцию для Gatling и сам стенд будет запускаться только при необходимости.

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

Почитать про Gatling можно в подборке статей на Хабре:

  1. Использование Gatling. Введение

  2. Использование Gatling. Разбираемся в тестировании HTTP

  3. Gatling. Тестирование JDBC

  4. Использование Gatling. Тестирование gRPC

  5. Gatling. Тестирование Kafka

  6. Использование Gatling. Тестирование AMQP

Деструктивное тестирование в рамках тестирования производительности

Руслан Гимазиев, старший инженер по нагрузочному тестированию в Performance Lab, рассказал о деструктивном тестировании, что оно собой представляет, чем отличается от нагрузочного и какие трудности бывают в деструктивном тестировании.

Деструктивный тест — это проверка системы в различных разрушительных условиях. Такие тесты помогают понять поведение системы в разных состояниях инфраструктуры, предоставить дополнительную информацию о проблемах и разработать рекомендации по полученным данным. А еще деструктивные тесты могут уменьшить время простоя системы и сохранить деньги бизнесу.

Главное отличие деструктивного тестирования от нагрузочного — условия, в которых проводится тестирование. Задача деструктивного тестирования — ухудшить условия работы системы так, как это может случиться в реальной жизни, и посмотреть, что произойдет.

Взаимодействия с инфраструктурой — сетевые взаимодействия или отказ одной из нод. Серверная категория содержит все, что может произойти с сервером. Приложение (система) — поведение самого приложения в тех или иных обстоятельствах. Последняя категория свободная, зависит от особенностей разработки
Взаимодействия с инфраструктурой — сетевые взаимодействия или отказ одной из нод. Серверная категория содержит все, что может произойти с сервером. Приложение (система) — поведение самого приложения в тех или иных обстоятельствах. Последняя категория свободная, зависит от особенностей разработки

Пример деструктивного тестирования системы N

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

Нагрузочный контур сформировали из Perfomance Center и NGINX, приложение развернули на Linux, создали две ноды, написали приложение на Java и завернули в докер-контейнеры
Нагрузочный контур сформировали из Perfomance Center и NGINX, приложение развернули на Linux, создали две ноды, написали приложение на Java и завернули в докер-контейнеры

Чтобы провести деструктивное нагрузочное тестирование, мы разработали:

  • 50 скриптов для эмуляции работы сервисов;

  • 2 эмулятора Wiremock — 156 API-эмуляторов и IBM MQ client. Реализовали два разных ответа для разных счетов клиентов и один объемный ответ;

  • 3 развернутые сервисные внешние системы — Kafka, IBM MQ и Logstash;

  • 3 системы мониторинга для двух БД — Telegraf, Oracle Enterprise Manager и Lab128;

  • 5 сценариев для наполнения БД и три сценария для проведения тестов.

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

  1. С разными значениями latency от клиента.

Тестирование показало, что система справляется, только немного выросло время откликов
Тестирование показало, что система справляется, только немного выросло время откликов
  1. С медленными ответами внешних систем.

На графике стабильной подачи нагрузки видно, что когда замедлилось время отклика внешних систем, стали появляться ошибки в бизнес-процессах
На графике стабильной подачи нагрузки видно, что когда замедлилось время отклика внешних систем, стали появляться ошибки в бизнес-процессах

3. С различной шириной канала передачи входящих и исходящих пакетов от клиента:

На графиках суммарные интенсивности успешных и неуспешных операций. На графике стабильной подачи теста № 1 видны ошибки, вызванные ограничением канала передачи
На графиках суммарные интенсивности успешных и неуспешных операций. На графике стабильной подачи теста № 1 видны ошибки, вызванные ограничением канала передачи

Проведенные тесты показали, что скорость для нормальной работы нашего приложения должна быть не менее 512 Кбит/с, задержка latency до 1000 мс и время ожидания клиента не меньше 120 секунд.

Деструктивное тестирование помогает подложить подушку безопасности и понять, в правильном ли месте она установлена.

Вместо заключения

После выступления спикеров провели круглый стол про тренды нагрузочного тестирования в 2023 году. Борис Селезнев, Вячеслав Смирнов и Иоанн Ахальцев обсудили, как выглядят процессы нагрузочного тестирования со стороны бизнеса и команд, которые этим занимаются. Поговорили о том, как бизнес хочет видеть команду тестирования, и ответили на вопросы в чате.

Послушать выступление целиком или скачать презентации спикеров можно на странице мероприятия.

Мы в Тинькофф не только активно применяем, но и много разрабатываем различные инструменты по тестированию производительности. Также мы развиваем наше комьюнити, обмениваемся кейсами и экспертизой, проводим профессиональные встречи и ведем чатик по QA в нашем Телеграме. Чувствуйте себя свободно и не бойтесь задавать вопросы в комментариях. 

Комментарии (0)