Как генерировать запросы с постоянной частотой в k6 с новым API сценариев?

https://habr.com/ru/company/otus/blog/524604/
  • Блог компании OTUS. Онлайн-образование
  • Тестирование IT-систем
  • JavaScript
  • Тестирование веб-сервисов
  • Тестирование мобильных приложений


Привет, хабровчане. В преддверии старта курса «Нагрузочное тестирование» подготовили для вас перевод еще одного интересного материала.



Введение


Релиз 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


При написании тестового скрипта следует учитывать следующие моменты:

  1. Поскольку k6 отслеживает перенаправления (редиректы), количество перенаправлений добавляется к общему количеству запросов в секунду в выводе результатов. Если вам это не нужно, вы можете отключить это глобально, установив maxRedirects: 0 в своих опциях. Вы также можете настроить максимальное количество перенаправлений для самого http запроса, которое переопределит глобальный maxRedirects.
  2. Сложность имеет значение. Поэтому старайтесь, чтобы выполняемая функция была простой, желательно, выполняя лишь несколько запросов, избегая по возможности дополнительных обработок или вызовов sleep().
  3. Для достижения желаемых результатов вам понадобится изрядное количество виртуальных пользователей, в противном случае вы столкнетесь с варнингами, подобными следующему. В этом случае просто увеличьте preAllocatedVU и/или maxVU, но имейте в виду, что рано или поздно вы достигнете максимальный предел машины, на которой выполняется тест, когда ни preAllocatedVU, ни maxVU уже не будут иметь никакого значения.

    WARN[0005] Insufficient VUs, reached 100 active VUs and cannot initialize more  executor=constant-arrival-rate scenario=constant_request_rate

  4. Как вы можете видеть в приведенных выше результатах, там есть drop_iterations, а количество iterations и http_reqs меньше указанной частоты. Наличие множества dropped_iterations означает, что не было достаточно инициализированных виртуальных пользователей, чтобы выполнить некоторые из итераций. Как правило, эту проблему можно решить, увеличив preAllocatedVU. Точное значение требует небольшого количества проб и ошибок, поскольку оно зависит от различных факторов, включая время ответа конечной точки, пропускную способность сети и другие связанные задержки.
  5. Во время тестирования вы можете встретить следующие варнинги, которые означают, что вы достигли пределов своей операционной системы. В таком случае рассмотрите возможность тонкой настройки вашей операционной системы:

    WARN[0008] Request Failed
  6. Помните, что API сценариев не поддерживает глобальное использование duration, vus и stages, хотя их все еще можно использовать. Это также означает, что вы не можете использовать их вместе со сценариями.


Заключение


До релиза v0.27.0 у k6 не было достаточной поддержки для генерации запросов с постоянной скоростью. Поэтому мы реализовали временное решение на JavaScript, вычисляя время, необходимое для выполнения запросов на каждой итерации скрипта. С v0.27.0 в этом больше нет необходимости.

В этой статье я рассказал, как k6 может достичь постоянной частоты запросов с помощью нового API сценариев с использованием constant-arrival-rate исполнителя. Этот исполнитель упрощает код и предоставляет средства для достижения фиксированного количества запросов в секунду. Это контрастирует с предыдущей версией той же статьи, в которой я описал другой метод достижения практически тех же результатов путем расчета количества виртуальных пользователей, итераций и продолжительности с использованием формулы и некоторого шаблонного JavaScript кода. К счастью, этот новый подход работает так, как задумано, и нам больше не нужно использовать какие-либо хаки.

Надеюсь, вам было приятно читать эту статью. Я буду рад услышать ваши отзывы.



Читать ещё:


Currently unrated

Recent Posts

Archive

2020
2019
2018
2017
2016
2015
2014

Categories

Authors

Feeds

RSS / Atom