Привет, хабровчане. В преддверии старта курса «Нагрузочное тестирование» подготовили для вас перевод еще одного интересного материала.
Релиз v0.27.0 принес нам новый механизм выполнения и множество новых исполнителей, которые нацелены удовлетворить ваши конкретные требования. Он также включает новое API сценариев с множеством различных опций для настройки и моделирования нагрузки на тестируемую систему (system under test — SUT). Это результат полутора лет работы над печально известным #1007 пул реквестом.
Для генерации запросов с постоянной скоростью мы можем использовать
Давайте рассмотрим ключевые параметры, используемые в k6 для описания тестовой конфигурации в сценарии, в котором используется
Вместе эти параметры образуют сценарий, который является частью опций конфигурации теста. Приведенный ниже фрагмент кода является примером
В этой конфигурации у нас есть
Имейте в виду, что инициализация виртуальных пользователей во время теста может оказаться сложной задачей для ЦП и тем самым исказить результаты тестирования. В целом, лучше, чтобы
Пример генерации запросов с постоянной частотой с
В предыдущем руководстве мы продемонстрировали, как рассчитать постоянную частоту запросов. Давайте рассмотрим его еще раз, с учетом того, как работают сценарии:
Предположим, что вы ожидаете, что ваша тестируемая система будет обрабатывать 1000 запросов в секунду в конечной точке. Предварительное выделение 100 виртуальных пользователей (максимум 200) позволяет каждому виртуальному пользователю отправлять примерно 5~10 запросов (основываясь на количестве в 100~200 виртуальных пользователей). Если выполнение каждого запроса занимает более 1 секунды, вы в конечном итоге будете делать меньше запросов, чем ожидалось (больше
В этом сценарии каждый предварительно выделенный виртуальный пользователь будет делать 10 запросов (
Результат выполнения этого сценария будет следующим:
При написании тестового скрипта следует учитывать следующие моменты:
До релиза v0.27.0 у k6 не было достаточной поддержки для генерации запросов с постоянной скоростью. Поэтому мы реализовали временное решение на JavaScript, вычисляя время, необходимое для выполнения запросов на каждой итерации скрипта. С v0.27.0 в этом больше нет необходимости.
В этой статье я рассказал, как k6 может достичь постоянной частоты запросов с помощью нового API сценариев с использованием
Надеюсь, вам было приятно читать эту статью. Я буду рад услышать ваши отзывы.
Введение
Релиз v0.27.0 принес нам новый механизм выполнения и множество новых исполнителей, которые нацелены удовлетворить ваши конкретные требования. Он также включает новое API сценариев с множеством различных опций для настройки и моделирования нагрузки на тестируемую систему (system under test — SUT). Это результат полутора лет работы над печально известным #1007 пул реквестом.
Для генерации запросов с постоянной скоростью мы можем использовать
constant-arrival-rate
исполнителя. Этот исполнитель запускает тест с итерациями с фиксированной частотой в течение указанного времени. Это позволяет k6 динамически изменять количество активных виртуальных пользователей (virtual users — VU) во время выполнения теста с целью достижения указанного количества итераций за единицу времени. В этой статье я собираюсь объяснить, как использовать этот сценарий для генерации запросов с постоянной частотой.Основы опций конфигурации сценариев
Давайте рассмотрим ключевые параметры, используемые в k6 для описания тестовой конфигурации в сценарии, в котором используется
constant-arrival-rate
исполнитель:- executor (исполнитель):
Исполнители — это рабочие лошадки механизма выполнения k6. Каждый из них планирует VU и итерации по-разному — вы выбираете их, основываясь на типе трафика, который вы хотите смоделировать для тестирования своих сервисов. rate
(количество) иtimeUnit
(единица времени):
k6 пробует запускатьrate
итераций каждыйtimeUnit
период.
Например:
rate: 1
,timeUnit: '1s'
означает «пробовать запускать одну итерацию каждую секунду»rate: 1
,timeUnit: '1m'
означает «пробовать запускать одну итерацию каждую минуту»rate: 90
,timeUnit: '1m'
означает «пробовать запускать 90 итераций в минуту», то есть 1,5 итераций/с, или пытаться начать новую итерацию каждые 667 мс,rate: 50
,timeUnit: '1s'
означает «пробовать запускать 50 итераций каждую секунду», то есть 50 запросов в секунду (requests per second — RPS), если в нашей итерации есть один запрос, т.е. пытаться запускать новую итерацию каждые 20 мс
- duration (продолжительность):
Общая продолжительность сценария, исключаяgracefulStop
. preAllocatedVUs
:
Количество предварительно выделенных виртуальных пользователей до начала теста.maxVUs
:
максимальное количество виртуальных пользователей, разрешенное для тестового прогона.
Вместе эти параметры образуют сценарий, который является частью опций конфигурации теста. Приведенный ниже фрагмент кода является примером
constant-arrival-rate
сценария.В этой конфигурации у нас есть
constant_request_rate
сценарий, который представляет собой уникальный идентификатор, используемый в качестве метки для сценария. В этом сценарии используется constant-arrival-rate
исполнитель и выполняется в течение 1 минуты. Каждую секунду (timeUnit
) будет выполняться 1 итерация (rate
). Пул предварительно выделенных виртуальных пользователей содержит 20 экземпляров и может достигать 100 штук, в зависимости от количества запросов и итераций.Имейте в виду, что инициализация виртуальных пользователей во время теста может оказаться сложной задачей для ЦП и тем самым исказить результаты тестирования. В целом, лучше, чтобы
preAllocatedVU
было достаточным для запуска нагрузочного теста. Поэтому не забудьте выделить побольше виртуальных пользователей в зависимости от количества запросов в вашем тесте, и показателя частоты, с которой вы хотите запускать тест.export let options = {
scenarios: {
constant_request_rate: {
executor: 'constant-arrival-rate',
rate: 1,
timeUnit: '1s',
duration: '1m',
preAllocatedVUs: 20,
maxVUs: 100,
}
}
};
Пример генерации запросов с постоянной частотой с constant-arrival-rate
В предыдущем руководстве мы продемонстрировали, как рассчитать постоянную частоту запросов. Давайте рассмотрим его еще раз, с учетом того, как работают сценарии:
Предположим, что вы ожидаете, что ваша тестируемая система будет обрабатывать 1000 запросов в секунду в конечной точке. Предварительное выделение 100 виртуальных пользователей (максимум 200) позволяет каждому виртуальному пользователю отправлять примерно 5~10 запросов (основываясь на количестве в 100~200 виртуальных пользователей). Если выполнение каждого запроса занимает более 1 секунды, вы в конечном итоге будете делать меньше запросов, чем ожидалось (больше
dropped_iterations
), что является признаком проблем с производительностью вашей тестируемой системы или нереалистичных ожиданий. В таком случае вам следует исправить проблемы с производительностью и запустить тестирование заново, или же умерить свои ожидания, поправив timeUnit
.В этом сценарии каждый предварительно выделенный виртуальный пользователь будет делать 10 запросов (
rate
делится на preAllocatedVU
). Если запросы не поступают в течении 1 секунды, например, для получения ответа потребовалось более 1 секунды или вашей тестируемой системе потребовалось более 1 секунды для выполнения задачи, k6 увеличит количество виртуальных пользователей для компенсации пропущенных запросов. Следующий тест генерирует 1000 запросов в секунду и выполняется в течение 30 секунд, что примерно составляет 30 000 запросов, как вы можете видеть ниже в выходных данных: http_reqs
и iterations
. Кроме того, k6 использовал только 148 виртуальных пользователей из 200.import http from 'k6/http';
export let options = {
scenarios: {
constant_request_rate: {
executor: 'constant-arrival-rate',
rate: 1000,
timeUnit: '1s', // 1000 итераций в секунду, т.е.1000 запросов секунду
duration: '30s',
preAllocatedVUs: 100, // насколько большой начальный пул виртуальных пользователей
maxVUs: 200, // если preAllocatedVU недостаточно, мы можем инициализировать еще, но больше этого количества
}
}
};
export default function () {
http.get('http://test.k6.io/contacts.php');
}
Результат выполнения этого сценария будет следующим:
$ k6 run test.js
/\ |‾‾| /‾‾/ /‾/
/\ / \ | |_/ / / /
/ \/ \ | | / ‾‾\
/ \ | |‾\ \ | (_) |
/ __________ \ |__| \__\ \___/ .io
execution: local
script: test.js
output: -
scenarios: (100.00%) 1 executors, 200 max VUs, 1m0s max duration (incl. graceful stop):
* constant_request_rate: 1000.00 iterations/s for 30s (maxVUs: 100-200, gracefulStop: 30s)
running (0m30.2s), 000/148 VUs, 29111 complete and 0 interrupted iterations
constant_request_rate ✓ [======================================] 148/148 VUs 30s 1000 iters/s
data_received..............: 21 MB 686 kB/s
data_sent..................: 2.6 MB 85 kB/s
*dropped_iterations.........: 889 29.454563/s
http_req_blocked...........: avg=597.53µs min=1.64µs med=7.28µs max=152.48ms p(90)=9.42µs p(95)=10.78µs
http_req_connecting........: avg=561.67µs min=0s med=0s max=148.39ms p(90)=0s p(95)=0s
http_req_duration..........: avg=107.69ms min=98.75ms med=106.82ms max=156.54ms p(90)=111.73ms p(95)=116.78ms
http_req_receiving.........: avg=155.12µs min=21.1µs med=105.52µs max=34.21ms p(90)=147.69µs p(95)=190.29µs
http_req_sending...........: avg=46.98µs min=9.81µs med=41.19µs max=5.85ms p(90)=53.33µs p(95)=67.3µs
http_req_tls_handshaking...: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...........: avg=107.49ms min=98.62ms med=106.62ms max=156.39ms p(90)=111.52ms p(95)=116.51ms
*http_reqs..................: 29111 964.512705/s
iteration_duration.........: avg=108.54ms min=99.1ms med=107.08ms max=268.68ms p(90)=112.09ms p(95)=118.96ms
*iterations.................: 29111 964.512705/s
vus........................: 148 min=108 max=148
vus_max....................: 148 min=108 max=148
При написании тестового скрипта следует учитывать следующие моменты:
- Поскольку k6 отслеживает перенаправления (редиректы), количество перенаправлений добавляется к общему количеству запросов в секунду в выводе результатов. Если вам это не нужно, вы можете отключить это глобально, установив
maxRedirects: 0
в своих опциях. Вы также можете настроить максимальное количество перенаправлений для самого http запроса, которое переопределит глобальныйmaxRedirects
. - Сложность имеет значение. Поэтому старайтесь, чтобы выполняемая функция была простой, желательно, выполняя лишь несколько запросов, избегая по возможности дополнительных обработок или вызовов
sleep()
. - Для достижения желаемых результатов вам понадобится изрядное количество виртуальных пользователей, в противном случае вы столкнетесь с варнингами, подобными следующему. В этом случае просто увеличьте
preAllocatedVU
и/илиmaxVU
, но имейте в виду, что рано или поздно вы достигнете максимальный предел машины, на которой выполняется тест, когда ниpreAllocatedVU
, ниmaxVU
уже не будут иметь никакого значения.
WARN[0005] Insufficient VUs, reached 100 active VUs and cannot initialize more executor=constant-arrival-rate scenario=constant_request_rate
- Как вы можете видеть в приведенных выше результатах, там есть
drop_iterations
, а количествоiterations
иhttp_reqs
меньше указанной частоты. Наличие множестваdropped_iterations
означает, что не было достаточно инициализированных виртуальных пользователей, чтобы выполнить некоторые из итераций. Как правило, эту проблему можно решить, увеличивpreAllocatedVU
. Точное значение требует небольшого количества проб и ошибок, поскольку оно зависит от различных факторов, включая время ответа конечной точки, пропускную способность сети и другие связанные задержки. - Во время тестирования вы можете встретить следующие варнинги, которые означают, что вы достигли пределов своей операционной системы. В таком случае рассмотрите возможность тонкой настройки вашей операционной системы:
WARN[0008] Request Failed
- Помните, что API сценариев не поддерживает глобальное использование duration, vus и stages, хотя их все еще можно использовать. Это также означает, что вы не можете использовать их вместе со сценариями.
Заключение
До релиза v0.27.0 у k6 не было достаточной поддержки для генерации запросов с постоянной скоростью. Поэтому мы реализовали временное решение на JavaScript, вычисляя время, необходимое для выполнения запросов на каждой итерации скрипта. С v0.27.0 в этом больше нет необходимости.
В этой статье я рассказал, как k6 может достичь постоянной частоты запросов с помощью нового API сценариев с использованием
constant-arrival-rate
исполнителя. Этот исполнитель упрощает код и предоставляет средства для достижения фиксированного количества запросов в секунду. Это контрастирует с предыдущей версией той же статьи, в которой я описал другой метод достижения практически тех же результатов путем расчета количества виртуальных пользователей, итераций и продолжительности с использованием формулы и некоторого шаблонного JavaScript кода. К счастью, этот новый подход работает так, как задумано, и нам больше не нужно использовать какие-либо хаки.Надеюсь, вам было приятно читать эту статью. Я буду рад услышать ваши отзывы.