Всем привет, я Никита Мунтян, QA Load Engineer в inDriver. Пришел в компанию в 2020 году развивать направление нагрузочного тестирования. В первую очередь познакомился с коллегами, выстроил план работы и начал планомерно создавать процессы и технические решения.

Тогда передо мной было пустое поле — делай как хочешь и как видишь, возможностей для творческой реализации много. Оставалось понять, что хотят увидеть от нагрузки, и какой подход использовать. Наша команда решила делать Load as a Service, об этом и расскажу под катом.

Начало

Все началось со встреч о том, что коллеги хотят увидеть от нагрузочного тестирования. В рамках этого этапа мы:

  1. Сконфигурировали тестовый стенд.

  2. Создали регулярные встречи с заинтересованными лицами.

  3. Пришли к выводу, что хотим оптимизировать систему и создать доступный и несложный инструмент, легко поддерживаемый и многофункциональный.

Также мы ввели понятие исследовательского тестирования сервисов, которое использовали как для оценки целесообразности внедрения стороннего софта, так и для разработки собственных решений. Оно применяется для оценки работоспособности сервиса, выделения самых долгих методов и тестирования новых микросервисов, которые активно переезжают с монолита.

Кроме того, мы предложили вариант гибких запусков тестирования: изменения критически важных методов проходят нагрузочное тестирование по запросу от команд, которые уже переехали или собираются переезжать. Периодически мы снимаем профиль и разбираем проблемные места.

В итоге было решено пойти по пути развития нагрузочного тестирования как автоматизированного инструмента для любого заинтересованного лица. Модное-молодежное Load as a Service. Тестировщик или разработчик сможет запускать тесты от команды — красота же! Наша задача, как команды нагрузочного тестирования, предоставить такой сервис. 

Для начала мы собрали профили нагрузки, определили критически важные модули и попытались ввести регламенты: при изменении каких методов требуется нагрузочное тестирование. А после этого сделали регламент заведения задач на нагрузочное тестирование. 

Вот как выглядит наш шаблон для заведения задачи на нагрузочное тестирование:

  • Зачем мы хотим нагрузочное тестирование на конкретном проекте.

  • Название системы и четкое описание работы.

  • Предполагаемые узкие места.

  • Ожидаемая нагрузка на систему: какие запросы должны выполняться их RPS. RPS должны быть стандартными и пиковыми (если пока непонятно, можно написать предположительную нагрузку).

  • Верхнеуровневая архитектура приложения (по возможности).

  • Описание по шагам, что должен сделать сценарий.

  • Кто от команды будет заниматься нагрузкой со стороны разработки.

  • Прикрепить задачу на подготовку стенда и настройке конфигов (от команды).

Также необходимы описания:

  • Интерфейса, который необходимо нагрузить.

  • Зависимостей.

  • Какую загрузку ресурсов мы ожидаем при плановых и пиковых нагрузках. 

  • Минимального периода тестирования (если это тестирование на стабильность).

Основной флоу работы теперь выглядел так:

1. Команда нагрузочного тестирования разрабатывает сценарии, поддерживает стенды, готовит профиль нагрузки и передает знания в команды, выделяя при этом ответственного внутри самой команды.

Например, мы просим техлида команды выделить человека, которого быстро обучат валидировать и обновлять сценарий JMeter. Запуски мы производим через TeamCity.

2. Создается job, который можно вызвать нажатием кнопки. Целью команды нагрузочного тестирования является создание центра экспертизы и помощь в разработке сценариев для команд. 

CI-интеграция

Все сценарии хранятся в нашем GitHub-репозитории. Оттуда с помощью Dockerfile и Charts создается loadtests-base-image-контейнер с JMeter в Kubernetes и нужным набором плагинов. А также loadtests-jmeter-job, который использует базовый image для старта job'ы в TeamCity. К сожалению, ямлики с charts и teamplates показать не могу, но эти шаблоны спокойно гуглятся для TeamCity.

Рецепт Dockerfile:

FROM openjdk:8-jdk-slim
#Переменные прокинутые в JMeter
ARG JMETER_VERSION=5.4.2
ENV JMETER_COUNTER='0'
ENV JMETER_SCENARIO=
ENV JMETER_THREADS='50'
ENV JMETER_TIMELINE='10'
ENV JMETER_DELAY='1000'
ENV JMETER_CONTRACTOR='50'
ENV JMETER_CUSTOMER='50'
ENV JVM_ARGS='-Xms16384m -Xmx16384m'
WORKDIR /jmeter
ADD ./scenario/. /jmeter/
Install Jmeter
RUN apt-get clean && apt-get update && apt-get -qy install wget telnet  iputils-ping unzip
RUN wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-JMETER_VERSION.tgz -C ./ && rm apache-jmeter-JMETER_VERSION/* ./
Install PluginsManager
RUN wget -q -O /tmp/jpgc-casutg-2.9.zip https://jmeter-plugins.org/files/packages/jpgc-casutg-2.9.zip
&& unzip -n /tmp/jpgc-casutg-2.9.zip && rm /tmp/jpgc-casutg-2.9.zip
&& wget -q -O lib/cmdrunner-2.2.jar http://search.maven.org/remotecontent?filepath=kg/apc/cmdrunner/2.2/cmdrunner-2.2.jar
&& java -cp lib/ext/jmeter-plugins-manager-1.3.jar org.jmeterplugins.repository.PluginManagerCMDInstaller
&& bin/PluginsManagerCMD.sh install jpgc-graphs-basic=2.0,jpgc-autostop=0.1,jpgc-graphs-additional=2.0,blazemeter-debugger=0.6,jpgc-functions=2.1,jpgc-graphs-dist=2.0,jpgc-dummy=0.4,jpgc-ffw=2.0,jmeter-grpc-request=1.2.1,jpgc-json=2.7,jpgc-graphs-vs=2.0,jpgc-perfmon=2.1,jpgc-plugins-manager=1.6,bzm-random-csv=0.7,jpgc-redis=0.3,jpgc-tst=2.5,websocket-sampler=1.0.2-SNAPSHOT,websocket-samplers=1.2.8,jmeter-core=5.4.2,jmeter-ftp=5.4.2,jmeter-http=5.4.2,jmeter-jdbc=5.4.2,jmeter-jms=5.4.2,jmeter-junit=5.4.2,jmeter-java=5.4.2,jmeter-ldap=5.4.2,jmeter-mail=5.4.2,jmeter-mongodb=5.4.2,jmeter-native=5.4.2,jmeter-tcp=5.4.2,jmeter-components=5.4.2
RUN bin/PluginsManagerCMD.sh status
ENV PATH /jmeter/bin:" class="formula inline">PATH
COPY entrypoint.sh /
RUN ["chmod", "+x", "/entrypoint.sh"]
ENTRYPOINT ["/entrypoint.sh"] 

Вид job, которым стартуют нагрузочные тесты:

Также мы параметризировали количество пользователей и время исполнения самого сценария, используя кастомные threadGroup. Из CI-системы можно было задать параметр, который передавался в JMeter и использовался там, где нужно:

Разработка сценариев

Решено было идти по пути наименьшего сопротивления — инструментом выбрали Apache JMeter. Мы же хотим обучать всех желающих :)

Причины выбора:

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

  • Доступность инструмента, огромное количество документации в интернете.

  • Легкая интеграция в CI.

У нас мобильное приложение, поэтому мы пошли по пути «эмулятор + сниффер для записи сценариев». 

Расскажу, как мы создаем сценарии:

1. Открываем Android Studio. У меня их 2 — для записи в один файл действий водителя и пассажира (записать одновременно в оба сертификат не даст, нужно поочередно):

2. Открываем Proxyman. Идем во вкладку Certificate → Install Certificate on Android → Emulators:

  1. Нажимаем на Override Emulator и записываем сертификат на оба устройства:

4. Если все успешно, мы увидим трафик с Remote Devices:

5. Работа с Android Studio + Proxyman:

  • Устанавливаем последнюю свежую или нужную сборку, и берем 2 устройства:

  • Возьмем водителя и пассажира, и увидем их запросы в сниффере. Выделяем нужные нам запросы и сохраняем в har file:

6. Используем конвектор har to jmx.

7. Конвертируем файл в jmx и получаем шаблон для работы в JMeter.

Итог

  • Подключили Grafana и смотрим там основные результаты (RPS, Responce Time и другие показатели).

  • Прикрутили дашборды на связке Influx + Grafana, подняли сервер, куда складываются стандартные html-отчеты JMeter.

  • Разместили стенд в Kubernetes, новые микросервисы, которые заходят в эксплуатацию, тестируются перед деплоем. Старые тестируются по запросу от команды при изменениях в определенных методах. Это необходимо для понимания, что будет с инстансом, а также для выявления узких мест. На тестовом стенде все интеграции прямые, с минимумом заглушек. 

  • Собираем системные метрики с помощью Prometheus и Zabbix.

  • Проводим исследовательские тестирования производительности и идем к полной автоматизации тестов перед деплоем ветки релиз-кандидата в прод.

В конце концов, встал вопрос о том, как сделать процессы более зрелыми. Но об этом я расскажу в следующей статье. Она будет посвящена тому, как мы меняли подходы к тестированию и строили заборы с пайплайнами.

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


  1. login40k
    21.04.2022 23:27

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

    Комментарии:

    1. Кажется, что сервисная история должна упрощать процессы и снижать бюрократизацию, судя по набору требований из таска к вашей команде там у команды появляется очень не сервисная активность в виде сбора и формализации кучи вещей, которые ещё и вероятно будут заставлять их заниматься уточняющей коммуникацией. Мы ходили по такой модели, лучший вариант - это ввести практики которые бы собирали за них весь этот набор или давали бы его в полуготовом виде.

    2. Сами UI-ые скрипты JMeter, конечно имеют преимущество над кодовыми решениями, но степень их поддерживаемости, переиспользуемости и прочих благ очень слабая. Чем больше вариантов каждого теста, чем больше продуктов это становится все сложнее. Нужно поменять креды юзера везде? Нашёл скрипт, открыл на локалке, поменял, закрыл, сохранил, залил. И так с каждым. С аналогичной проблемой сталкивались и мы, тут могу порекомендовать уехать на jmeter-java-dsl если хотите jmeter.

      Вопросы:

      1. Почему вы записываете сценарии а не нагружаете апишку в соответствии с тем количеством рпс которое приближено к проду. И если у вас сценарный подход то как вы матчите рпсы с прода и сценарии?

      2. Почему бы не тестировать каждый релиз и каждый сервис, вместо того чтобы рождать сущности в виде регламентом и устраивать охоту на ведьм когда кто-то идёт мимо него?

      3. А кто валидирует результаты тестов и ищет перформанс проблемы? Этому научить например функционального тестера очень ресурсоемко, а если заниматься этим самостоятельно то получиться что при большом количестве релизов вы будете постоянно находится в этом анализе. Мы эту проблему решили собственным анализатором результатов (Quality Gate) который не пустит в прод если есть проблема и сам ее максимально подсветит, чтобы была возможность команде ее самостоятельно решить.

      4. Почему тесты идут с минимумом заглушек? Если надо запустить 2 теста параллельно они ждут когда стенд освободиться? Если это блокирует релиз то это очень негативное влияние на тайм ту маркет

      5. Очень ещё интересно, а много вообще желающих этому обучаться внутри команд?

        Если могу помочь - приходи, телегу знаешь)

        В целом очень круто, выглядит как набор правильных решений на старте, а чтобы не было больно потом я надеюсь помогут комменты выше)


    1. Kavabungoz
      22.04.2022 12:49

      По вопросу №3 можно поподробнее как Вы это реализовали? Невольно вспоминается https://ru.wikipedia.org/wiki/Квартет_Энскомба при взятии в расчет только сухих цифр без анализа графиков.


  1. vasiksim88
    22.04.2022 09:19

    Звучит неплохо, надеюсь у вас получилось быстро всех организовать и было много заинтересованных ) Вопросы:

    1. Какие типичные нагрузки подаются в тестах / приходят в Прод? Знаю что Jmeter с синхронным движком много не выдерживает, вопрос - не сталкивались ли с этим

    2. Что с тестированием производительности БД - где проводите, делаете ли копии / наполнение БД прод данными и как ловите там баги производительности?