Тестирование производительности — это методика тестирования, позволяющая оценить скорость реакции и стабильность работы сервера, сети или приложения под нагрузкой. Этот метод обычно применяют в качестве нагрузочного тестирования. Сегодня все большую важность приобретает время предоставления услуг, которое теперь оценивается как время безотказной работы, а не объем выполненной. Чтобы поддерживать это время стабильным и на высоком уровне, нам необходимо знать свои проблемы с производительностью. Именно здесь на помощь приходит k6.
Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ
Что такое k6? Его преимущества
k6 был выпущен в 2021 году компанией Grafana Labs. Кратко его можно оценить как инструмент, используемый для тестирования производительности и передачи нам результатов этого процесса. K6 создавался с использованием современных технологий, что обеспечило ему ряд преимуществ в определенных областях по сравнению с аналогчными инструментами:
- Скорость и эффективность
- Масштабируемость
- Гибкость сценариев
- Обширные выходные данные и отчетность
В процессе тестирования производительности, как правило, упускается из виду один момент — роль ресурсов и активности, которые затрачиваются на запросы, поступающие в точку произведения измерений. Одним из существенных преимуществ k6 по сравнению с другими распространенными конкурентами, безусловно, является инфраструктура и язык, на котором он разработан.
Если говорить более конкретно, то JMeter по-прежнему занимает лидирующие позиции в этой методологии, но, к сожалению, ему сложно догнать достаточно новые разработки. В качестве примера можно привести сложность и временные затраты на вмешательство в сценарий с помощью PreProcessors и PostProcessors. Именно здесь на помощь приходит k6. Он делает этот процесс достаточно быстрым и понятным благодаря предоставленному CLI.

Концепции k6
В этом инструменте встречаются привычные параметры, которые мы используем во время тестирования производительности и определяем для его работы. Параметры, которые мы будем определять, касаются проведения теста и его результатов. Они задаются в объекте Options:
- VUs (Virtual Users). Количество пользователей, которые используются/будут использоваться во время тестирования.
- Итерация. Сколько раз каждый отдельный VU будет повторять один и тот же сценарий.
- Duration (Продолжительность). Сколько времени будет длиться тест. Значение указывается в миллисекундах (MS).
- Проверки. Привычные для мира тестов средства утверждения/проверки ответа.
- Threshold (Порог). Пороговое значение, которое мы будем определять во время тестирования. Если фактическое значение превысит его, тест будет считаться неудачным. Например:
thresholds: { http_req_duration: ['avg<150'] }
Пример k6
В примере с k6 мы будем использовать собственные API. Простейшая форма point-load-теста выглядит следующим образом:
import http from "k6/http";
import { check } from 'k6';
export const options = {
vus: 1,
duration : 1000,
thresholds: { http_req_duration: ['avg<150'] },
noConnectionReuse: true,
summaryTrendStats: ['avg','min','max','count']
};
export default function () {
const url = 'https://test-api.k6.io/public/crocodiles/';
const header = { headers: {
'Content-Type': 'application/json',
},};
const response = http.get(url,header);
check(response, {
'is status 200': (r) => r.status == 200,
});
}
Чтобы лучше понять структуру k6, давайте разделим ее на две части:
- Часть, в которой мы задаем поток теста и то, как он будет себя вести, — объект
options. - Часть, которая будет являться функцией, в которой будет выполняться тест.
Объект Options в его простейшей форме можно представить как конфигурацию.
export const options = {
vus: 1,
duration : 100, // in milliseconds
thresholds: { http_req_duration: ['avg<100'] },
noConnectionReuse: true,
summaryTrendStats: ['avg','min','max','count']
};
Для простого тестового сценария будет достаточно приведенного выше объекта options. Среди параметров внутри объекта:
Thresholdгарантирует, что среднее значение выполненных запросов будет больше или меньше определенного значения.NoConnectionReuseопределяет значение keep-alive теста.SummaryTrendStatsопределяет форматы значений выходных данных, выдаваемых по завершении тестирования.
Теперь под функцией мы можем назвать место, где будет выполняться тест.
const url = 'https://test-api.k6.io/public/crocodiles/';
const header = { headers: {
'Content-Type': 'application/json',
},};
const response = http.get(url,header);
check(response, {
'is status 200': (r) => r.status == 200,
});
В самом простом виде этот шаг выполняется путем добавления заголовка к сделанному нами запросу GET и проверки его статуса.
Структура сценариев и исполнителей в k6
В k6 исполнитель — это компонент, который определяет, как будет направлена нагрузка во время тестирования. Благодаря этому мы можем легко применять различные подходы тестирования производительности. Таким образом мы получаем возможность контролировать распределение реальных пользователей и увеличение нагрузки на приложение.
Как известно, методика, применяемая в качестве эксплуатационных испытаний, подразделяется на несколько подразделов. Кратко:
- Smoke: низкое значение VUs / 1-5 минут.
- Load: среднее значение VUs / 10-60 минут.
- Stress: высокое значение VUs / 1-2 часа.
- Spike: очень высокое значение VUs / +60 минут.
- Breakpoint: регулярное увеличение VU / +60 минут.

К некоторых случаях для компаний, находящихся на жизненном цикле, одной конечной точки или простого сценария может быть недостаточно для достижения желаемого результата. Чем более простым и базовым является применяемый сценарий, тем меньше разнообразие и вероятность обнаружения проблем.
Самое большое преимущество, которое мы получаем благодаря k6, — это контроль нагрузки внутри, контролируемое увеличение и уменьшение. Это существенно помогает нам в обнаружении проблем в приложении/системе.
export const options = {
stages: [
{ duration: '30s', target: 10 },
{ duration: '1m', target: 20 },
{ duration: '2m', target: 0 },
],
thresholds: { http_req_duration: ['avg<150'] },
noConnectionReuse: true,
summaryTrendStats: ['avg','min','max','count']
};
Согласно приведенным нами значениям, рабочая логика нашего сценария выглядит следующим образом:
- Общая продолжительность нашего теста составляет 3 минуты 30 секунд.
- В конце первых 30 секунд внутрь начинает передаваться 10 VUs. Затем в течение 1 минуты начинается увеличение нагрузки внутри с 10 до 20 VUs. По истечении 1 минуты начинается контролируемое уменьшение количества VUs внутри с 20 до 0 в течение 2 минут.
- Значения длительности фактически определяют темп нарастания и спада нагрузки, которую мы даем внутри.
- Таким образом, разделив реальную внутреннюю интенсивность на минуты, мы получаем выгоду от сценической составляющей.
Количество запросов в секунду
Другой сценарий, который мы можем создать, — это RPS (Requests per Second). Это тестовая структура, ориентированная на количество запросов в секунду для сценария, который происходит внутри.
export const options = {
scenarios: {
my_scenario1: {
executor: 'constant-arrival-rate',
duration: '1m', // test duration
rate: 60, // requests to be made according to the TimeUnit we give
preAllocatedVUs: 30, // maximum VUs to be used for the given rate value in the test
timeUnit: '1s', // how long the given rate value will be applied
},
}
};
Значение VUs, которое мы указываем, на самом деле не является числом, используемым в начале теста; скорее, в результате примененной скорости тест пытается применяться непрерывно в течение заданного периода времени. Если время отклика увеличивается, продолжает расти и внутреннее значение VUs, чтобы уловить значение скорости, которое мы задаем автоматически.
Стресс-тест
В примере, представленном в этом объекте параметров, мы фактически применяем методологию стресс-тестирования к нашему приложению.
export const options = {
stages: [
{ duration: '5m', target: 200 },
{ duration: '20m', target: 600 },
{ duration: '5m', target: 0 },
],
};
Тестирование точек останова
export const options = {
executor: 'ramping-arrival-rate', // parameter to control the load to the application
stages: [
{ duration: '40m', target: 4000 }, // the number of VUs to be reached at the end of the specified duration
],
};
Наблюдение за результатами метрики k6
Вместо того чтобы отслеживать и интерпретировать метрики, полученные в ходе тестирования, в текстовом виде, можно визуализировать их на локальной машине. Это позволяет считывать данные приложения в режиме реального времени, что помогает более оперативно выявлять потенциальные проблемы в ходе тестирования.
Мы можем легко создавать наши собственные панели метрик, выгружая выходные показатели k6 по умолчанию на панели мониторинга с помощью Grafana и Influx.
В нашем примере мы будем работать с Docker локально. Давайте настроим Influx на Docker.
Создадим сетевой мост для Docker:
$ docker network create --driver bridge influxdb-telegraf-net
Run Influx на Docker
docker run -d --name=influxdb \ -p 8086:8086 \ -v /tmp/testdata/influx:/root/.influxdb2 \ --net=influxdb-telegraf-net \ influxdb:2.0
Теперь Influx готов к работе на локальном хосте: 8086. При первом посещении этого адреса будет запрошена информация о хранилище и пользователе. Заполните их, чтобы завершить этот шаг.
Расширение k6 InfluxDB
Когда мы устанавливаем k6, он поставляется с поддержкой InfluxDB v1 по умолчанию. Однако в данном примере мы используем InfluxDB v2, поэтому применим расширение.
xk6 build - with github.com/grafana/xk6-output-influxdb
В результате будет создан двоичный файл, обеспечивающий поддержку InfluxDB v2. Далее мы запустим наши тесты с этим двоичным файлом.
Для этого мы можем использовать команду test start.
K6_INFLUXDB_ORGANIZATION=${organizationName} K6_INFLUXDB_BUCKET=${bucketName} K6_INFLUXDB_TOKEN=${TOKEN} ./k6 run -o xk6-influxdb=http://localhost:8086 ./testScript.js
Тесты, запущенные с этой переменной окружения, будут экспортированы в InfluxDB.
Grafana на Docker
С помощью этой команды вы можете запустить экземпляр Grafana по адресу localhost:3000.
docker run -d -p 3000:3000 --name=grafana grafana/grafana-enterprise
Теперь Influx работает на localhost:8086, а Grafana — на localhost:3000.
Давайте добавим источник данных Influx в Grafana.

После выполнения этих шагов мы сможем запросить Influx из Grafana.
Давайте создадим панель мониторинга. Для этого мы можем использовать данный шаблон. С его помощью мы можем увидеть основные метрики k6.

Теперь наши тесты k6 можно наблюдать через Grafana.
В заключение следует отметить, что тестирование производительности — это важнейшая методология тестирования, позволяющая оценить реакцию системы под нагрузкой и ее стабильность. k6 является мощным и эффективным инструментом для таких тестов. Его преимущества, такие как скорость, масштабируемость, гибкие сценарии, обширные выходные данные и отчетность, — лишь некоторые из важных факторов выбора k6. Благодаря этим преимуществам пользователи могут лучше понять и повысить производительность и стабильность своих приложений.
Рассмотренные нами фундаментальные концепции, установка, использование и различные структуры сценариев k6 являются большим подспорьем для эффективного проведения тестов производительности. Эти возможности обеспечивают успешное завершение тестирования и повышают устойчивость приложения. Помните, что правильное и эффективное тестирование производительности — это залог успеха приложения и удовлетворенности пользователей.
Перевод статьи «Performance Testing and k6».

Пингбэк: Автоматизация тестирования производительности с K6