API Load Testing: Apache JMeter, Gatling, K6 полное руководство

Ваш API падает под нагрузкой? Не знаете, сколько пользователей выдержит система? В этом руководстве мы разберем 3 лучших инструмента для нагрузочного тестирования API: Apache JMeter, Gatling и K6. Вы узнаете, как проводить load testing, анализировать метрики (RPS, latency, p99) и выявлять узкие места в вашем API.

📋 Содержание

  1. Что такое Load Testing и зачем он нужен?
  2. Ключевые метрики Load Testing
  3. Apache JMeter: универсальный инструмент
  4. Gatling: Scala DSL для highload
  5. K6: JavaScript для DevOps
  6. Сравнение JMeter vs Gatling vs K6
  7. Best Practices для Load Testing
  8. Анализ узких мест
  9. FAQ: Часто задаваемые вопросы

🎯 Что такое Load Testing и зачем он нужен?

Load Testing (нагрузочное тестирование) — это процесс проверки производительности API под различной нагрузкой, чтобы определить, как система ведет себя при большом количестве одновременных запросов.

✅ Что вы узнаете из Load Testing:

Типы нагрузочного тестирования

📊 Ключевые метрики Load Testing

🚀 RPS (Requests Per Second)

Количество запросов в секунду — основная метрика throughput. Показывает, сколько запросов API обрабатывает за секунду.

Целевые значения:

⏱️ Latency (Response Time)

Время отклика — сколько времени занимает обработка одного запроса.

Целевые значения p99:

📈 Throughput

Пропускная способность — количество данных, передаваемых в единицу времени (KB/s, MB/s).

❌ Error Rate

Процент ошибок — доля запросов, завершившихся ошибкой (4xx, 5xx коды).

Допустимые значения:

🔧 Apache JMeter: универсальный инструмент

Apache JMeter — самый популярный open-source инструмент для нагрузочного тестирования, существует с 1998 года. Поддерживает HTTP, HTTPS, SOAP, REST API, WebSocket, JDBC, LDAP.

✅ Преимущества JMeter:

❌ Недостатки JMeter:

Установка JMeter

# macOS (Homebrew)
brew install jmeter

# Linux (Ubuntu)
sudo apt update
sudo apt install jmeter

# Windows
# Скачайте с https://jmeter.apache.org/download_jmeter.cgi
# Распакуйте и запустите bin/jmeter.bat

# Проверка установки
jmeter --version

Создание первого теста в JMeter

Способ 1: Через GUI

# Запустите GUI
jmeter

Пошагово:

  1. Создайте Thread Group (виртуальные пользователи)
  2. Добавьте HTTP Request Sampler
  3. Настройте URL и метод (GET/POST)
  4. Добавьте View Results Tree для просмотра результатов
  5. Добавьте Summary Report для метрик
  6. Запустите тест

Способ 2: JMX файл (для CI/CD)

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="API Load Test">
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Users">
        <intProp name="ThreadGroup.num_threads">100</intProp>
        <intProp name="ThreadGroup.ramp_time">10</intProp>
        <longProp name="ThreadGroup.duration">60</longProp>
      </ThreadGroup>
      <hashTree>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="GET /api/users">
          <stringProp name="HTTPSampler.domain">api.example.com</stringProp>
          <stringProp name="HTTPSampler.path">/api/users</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
        </HTTPSamplerProxy>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

Запуск JMeter в CLI (для CI/CD)

# Запуск теста без GUI
jmeter -n -t test-plan.jmx -l results.jtl -e -o report-folder

# Параметры:
# -n : non-GUI mode
# -t : путь к JMX файлу
# -l : файл результатов
# -e : генерировать HTML отчет
# -o : папка для отчета

# С параметрами (переменные)
jmeter -n -t test-plan.jmx \
  -JUSERS=500 \
  -JDURATION=300 \
  -l results.jtl \
  -e -o report

Пример теста API с POST запросом

// HTTP Request в JMeter
Method: POST
Path: /api/users
Headers:
  Content-Type: application/json
Body:
{
  "name": "Test User",
  "email": "test@example.com"
}

⚡ Gatling: Scala DSL для highload

Gatling — современный инструмент для нагрузочного тестирования, написанный на Scala. Использует асинхронную архитектуру (Akka) для максимальной производительности.

✅ Преимущества Gatling:

❌ Недостатки Gatling:

Установка Gatling

# Скачайте с https://gatling.io/open-source/
wget https://repo1.maven.org/maven2/io/gatling/highcharts/gatling-charts-highcharts-bundle/3.10.3/gatling-charts-highcharts-bundle-3.10.3-bundle.zip

unzip gatling-charts-highcharts-bundle-3.10.3-bundle.zip
cd gatling-charts-highcharts-bundle-3.10.3

# Или через Maven/Gradle проект

Создание первого теста в Gatling

// src/test/scala/simulations/ApiLoadTest.scala
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._

class ApiLoadTest extends Simulation {

  // HTTP Protocol Configuration
  val httpProtocol = http
    .baseUrl("https://api.example.com")
    .acceptHeader("application/json")
    .contentTypeHeader("application/json")

  // Scenario 1: Get Users
  val getUsersScenario = scenario("Get Users")
    .exec(
      http("GET /api/users")
        .get("/api/users")
        .check(status.is(200))
    )

  // Scenario 2: Create User
  val createUserScenario = scenario("Create User")
    .exec(
      http("POST /api/users")
        .post("/api/users")
        .body(StringBody("""{"name":"Test","email":"test@example.com"}"""))
        .check(status.is(201))
    )

  // Load Simulation
  setUp(
    getUsersScenario.inject(
      rampUsers(100) during (10 seconds),  // 100 пользователей за 10 секунд
      constantUsersPerSec(50) during (60 seconds)  // 50 RPS в течение 60 секунд
    ),
    createUserScenario.inject(
      rampUsers(50) during (10 seconds)
    )
  ).protocols(httpProtocol)
   .assertions(
     global.responseTime.max.lt(1000),  // max response time < 1000ms
     global.successfulRequests.percent.gt(95)  // 95%+ успешных запросов
   )
}

Запуск Gatling теста

# Запуск через CLI
./bin/gatling.sh

# Выберите simulation из списка

# Или напрямую
./bin/gatling.sh -s simulations.ApiLoadTest

# В Maven проекте
mvn gatling:test -Dgatling.simulationClass=simulations.ApiLoadTest

Продвинутые паттерны Gatling

// Сложный сценарий с feeders и думающим временем
class AdvancedApiTest extends Simulation {

  val httpProtocol = http.baseUrl("https://api.example.com")

  // Feeder — CSV файл с тестовыми данными
  val userFeeder = csv("users.csv").random

  val scn = scenario("Complex User Journey")
    .feed(userFeeder)  // Подставляем данные из CSV
    .exec(
      http("Login")
        .post("/api/auth/login")
        .body(StringBody("""{"email":"${email}","password":"${password}"}"""))
        .check(jsonPath("$.token").saveAs("authToken"))
    )
    .pause(1, 3)  // Думающее время 1-3 секунды
    .exec(
      http("Get Profile")
        .get("/api/users/me")
        .header("Authorization", "Bearer ${authToken}")
    )
    .pause(2)
    .exec(
      http("Update Profile")
        .put("/api/users/me")
        .header("Authorization", "Bearer ${authToken}")
        .body(StringBody("""{"name":"${name}"}"""))
    )
    .doIf(session => session("authToken").as[String].nonEmpty) {
      exec(
        http("Logout")
          .post("/api/auth/logout")
          .header("Authorization", "Bearer ${authToken}")
      )
    }

  setUp(
    scn.inject(
      atOnceUsers(10),  // 10 пользователей сразу
      rampUsers(100) during (60 seconds),
      constantUsersPerSec(20) during (5 minutes)
    )
  ).protocols(httpProtocol)
}

🚀 K6: JavaScript для DevOps

K6 — современный open-source инструмент для нагрузочного тестирования от Grafana Labs. Написан на Go, использует JavaScript (ES6) для написания тестов.

✅ Преимущества K6:

❌ Недостатки K6:

Установка K6

# macOS (Homebrew)
brew install k6

# Linux (Debian/Ubuntu)
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6

# Windows (Chocolatey)
choco install k6

# Docker
docker pull grafana/k6

# Проверка установки
k6 version

Создание первого теста в K6

// api-load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

// Test configuration
export const options = {
  stages: [
    { duration: '30s', target: 20 },   // Ramp up to 20 users
    { duration: '1m', target: 100 },   // Ramp up to 100 users
    { duration: '2m', target: 100 },   // Stay at 100 users
    { duration: '30s', target: 0 },    // Ramp down to 0 users
  ],
  thresholds: {
    http_req_duration: ['p(95)<500', 'p(99)<1000'],  // 95% < 500ms, 99% < 1s
    http_req_failed: ['rate<0.01'],  // Error rate < 1%
  },
};

export default function () {
  // GET request
  const res = http.get('https://api.example.com/api/users');

  // Assertions
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500,
    'has users': (r) => JSON.parse(r.body).length > 0,
  });

  // Think time
  sleep(1);
}

Запуск K6 теста

# Запуск теста
k6 run api-load-test.js

# С параметрами
k6 run --vus 100 --duration 30s api-load-test.js

# С переменными окружения
k6 run -e API_URL=https://staging.api.com api-load-test.js

# С выводом метрик в InfluxDB
k6 run --out influxdb=http://localhost:8086/k6 api-load-test.js

# Docker
docker run --rm -v $(pwd):/scripts grafana/k6 run /scripts/api-load-test.js

Продвинутый K6 тест с несколькими сценариями

// advanced-api-test.js
import http from 'k6/http';
import { check, group, sleep } from 'k6';
import { Rate, Trend, Counter } from 'k6/metrics';

// Custom metrics
const loginFailureRate = new Rate('login_failures');
const apiResponseTime = new Trend('api_response_time');
const apiRequests = new Counter('api_requests');

export const options = {
  scenarios: {
    // Scenario 1: Constant load
    constant_load: {
      executor: 'constant-vus',
      vus: 50,
      duration: '5m',
    },
    // Scenario 2: Spike testing
    spike_test: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '10s', target: 200 },  // Spike to 200 users
        { duration: '10s', target: 0 },    // Drop to 0
      ],
      startTime: '5m',  // Start after 5 minutes
    },
  },
  thresholds: {
    http_req_duration: ['p(99)<1000'],
    login_failures: ['rate<0.05'],
    api_requests: ['count>10000'],
  },
};

const BASE_URL = __ENV.API_URL || 'https://api.example.com';

export function setup() {
  // Setup code (runs once)
  console.log(`Testing API: ${BASE_URL}`);
  return { startTime: Date.now() };
}

export default function (data) {
  // User journey
  group('User Authentication', () => {
    const loginRes = http.post(`${BASE_URL}/api/auth/login`, JSON.stringify({
      email: 'test@example.com',
      password: 'password123',
    }), {
      headers: { 'Content-Type': 'application/json' },
    });

    const success = check(loginRes, {
      'login status is 200': (r) => r.status === 200,
      'has auth token': (r) => JSON.parse(r.body).token !== undefined,
    });

    loginFailureRate.add(!success);
    apiResponseTime.add(loginRes.timings.duration);
    apiRequests.add(1);

    if (success) {
      const token = JSON.parse(loginRes.body).token;

      group('Get User Profile', () => {
        const profileRes = http.get(`${BASE_URL}/api/users/me`, {
          headers: { 'Authorization': `Bearer ${token}` },
        });

        check(profileRes, {
          'profile status is 200': (r) => r.status === 200,
        });

        apiResponseTime.add(profileRes.timings.duration);
        apiRequests.add(1);
      });
    }
  });

  sleep(Math.random() * 3 + 1);  // 1-4 seconds think time
}

export function teardown(data) {
  // Teardown code (runs once)
  const duration = (Date.now() - data.startTime) / 1000;
  console.log(`Test completed in ${duration}s`);
}

📊 Сравнение JMeter vs Gatling vs K6

Критерий Apache JMeter Gatling K6
Язык Java Scala Go (тесты на JavaScript)
GUI ✓ Есть ✗ Нет ✗ Нет
Синтаксис тестов XML или GUI Scala DSL JavaScript (ES6)
Производительность Средняя (JVM overhead) Высокая (Akka async) Очень высокая (Go native)
Потребление памяти Высокое (~500MB+) Среднее (~200MB) Низкое (~50MB)
Max RPS (1 сервер) ~10,000 RPS ~60,000 RPS ~30,000 RPS
Сообщество Огромное Среднее Растущее
Плагины Много Средне Средне
Отчеты HTML + Plugins Красивые HTML CLI + JSON + InfluxDB
CI/CD интеграция ✓✓
Протоколы HTTP, SOAP, JDBC, LDAP, FTP, etc. HTTP, WebSocket, SSE HTTP, WebSocket, gRPC
Кривая обучения Низкая (GUI) Высокая (Scala) Средняя (JavaScript)
Лучше для Enterprise, QA teams Highload, Java/Scala teams DevOps, Cloud-native, CI/CD
Open Source ✓ Apache 2.0 ✓ Apache 2.0 ✓ AGPL
Cloud версия BlazeMeter (платно) Gatling Enterprise (платно) K6 Cloud (freemium)

🎯 Когда что использовать?

Используйте Apache JMeter если:

Используйте Gatling если:

Используйте K6 если:

✅ Best Practices для Load Testing

1. Тестируйте в production-like окружении

2. Начинайте с базового теста

3. Используйте реалистичные сценарии

4. Мониторьте не только API, но и инфраструктуру

5. Запускайте тесты из нескольких регионов

6. Автоматизируйте Load Testing в CI/CD

⚠️ Важные ограничения

🔍 Анализ узких мест

Как выявить bottleneck по метрикам

Высокий Latency + Низкий CPU

Проблема: Медленные запросы к БД или внешним API

Решение:

Высокий CPU + Нормальный Latency

Проблема: CPU-intensive вычисления

Решение:

Высокий Memory + Out of Memory Errors

Проблема: Memory leaks или большие объекты в памяти

Решение:

Растущий Error Rate

Проблема: Система не справляется с нагрузкой

Решение:

Пример анализа результатов

# K6 результаты
     ✓ status is 200
     ✓ response time < 500ms

     checks.........................: 98.50% ✓ 9850      ✗ 150
     data_received..................: 45 MB  150 kB/s
     data_sent......................: 12 MB  40 kB/s
     http_req_blocked...............: avg=2.1ms   min=0s     med=1ms   max=150ms  p(90)=4ms   p(95)=8ms
     http_req_connecting............: avg=1.2ms   min=0s     med=0s    max=80ms   p(90)=2ms   p(95)=5ms
     http_req_duration..............: avg=245ms   min=100ms  med=220ms max=2.5s   p(90)=400ms p(95)=600ms
       { expected_response:true }...: avg=240ms   min=100ms  med=215ms max=1.2s   p(90)=390ms p(95)=580ms
     http_req_failed................: 1.50%  ✓ 150       ✗ 9850
     http_req_receiving.............: avg=5ms     min=1ms    med=4ms   max=50ms   p(90)=10ms  p(95)=15ms
     http_req_sending...............: avg=2ms     min=0s     med=1ms   max=30ms   p(90)=4ms   p(95)=8ms
     http_req_tls_handshaking.......: avg=0s      min=0s     med=0s    max=0s     p(90)=0s    p(95)=0s
     http_req_waiting...............: avg=238ms   min=95ms   med=210ms max=2.4s   p(90)=385ms p(95)=590ms
     http_reqs......................: 10000  333.33/s
     iteration_duration.............: avg=1.24s   min=1.1s   med=1.22s max=3.5s   p(90)=1.4s  p(95)=1.6s
     iterations.....................: 10000  333.33/s
     vus............................: 100    min=100     max=100
     vus_max........................: 100    min=100     max=100

# Анализ:
# ✅ p(95) = 600ms — хорошо (< 1s)
# ⚠️  p(max) = 2.5s — есть outliers, нужно исследовать
# ❌ Error rate 1.5% — выше нормы (должно быть < 0.1%)
# ✅ RPS 333/s — стабильный throughput

🔍 FAQ: Часто задаваемые вопросы

❓ Что такое Load Testing и зачем он нужен для API?
Load Testing (нагрузочное тестирование) — это процесс проверки производительности API под различной нагрузкой. Позволяет определить:
  • Максимальное количество одновременных пользователей
  • Время отклика при разных нагрузках
  • Узкие места в системе (БД, CPU, сеть)
  • Точку отказа (когда система начинает падать)
  • Поведение при пиковых нагрузках
Без Load Testing вы рискуете узнать о проблемах производительности только в production!
❓ Какой инструмент для Load Testing выбрать: JMeter, Gatling или K6?
JMeter — лучший выбор для enterprise и GUI:
  • QA команды без опыта программирования
  • Нужна запись трафика из браузера
  • Тестирование разных протоколов (не только HTTP)
Gatling — для Scala/Java проектов и highload:
  • Нужна максимальная производительность (60K+ RPS)
  • Команда знает Scala
  • Красивые отчеты важны
K6 — для современных DevOps команд:
  • JavaScript знаком команде
  • Cloud-native проекты
  • Легкая интеграция в CI/CD
❓ Какие метрики важны в Load Testing?
Ключевые метрики:
  • RPS (Requests Per Second) — количество запросов в секунду
  • Latency (p50, p95, p99) — время отклика (p99 самая важная!)
  • Throughput — пропускная способность в байтах/сек
  • Error Rate — процент ошибок (должен быть <0.1%)
  • Concurrent Users — одновременные пользователи
Целевые значения p99 latency: <100ms отлично, 100-300ms хорошо, >1s плохо.
❓ Чем Load Testing отличается от Stress Testing?
Load Testing проверяет поведение системы под ожидаемой нагрузкой (например, 1000 RPS, которые вы ожидаете в production). Цель: убедиться что система справляется.

Stress Testing проверяет предельные возможности — постепенно увеличивает нагрузку до отказа системы. Цель: найти точку разрушения (breaking point) и понять, как система деградирует под экстремальной нагрузкой.
❓ Как часто нужно проводить Load Testing?
Load Testing должен проводиться:
  • Перед каждым major релизом — убедиться что новые фичи не ухудшили производительность
  • При изменении архитектуры — новая БД, cache, infrastructure
  • Регулярно в CI/CD — smoke tests на каждый коммит, полные тесты раз в неделю
  • После оптимизаций — проверить что улучшения действительно работают
  • Перед Black Friday/пиками — убедиться что выдержите нагрузку
❓ Можно ли использовать Mock API для Load Testing?
Да! Mock API (например, LightBox API) полезен для:
  • Load Testing frontend без нагрузки на production backend
  • Тестирование клиентского кода под нагрузкой (обработка ответов, error handling)
  • Изоляции тестов — тестировать компоненты независимо
Однако: для тестирования реальной производительности backend нужен production-like environment (staging с той же инфраструктурой).

Протестируйте свой API сейчас

LightBox API — создайте Mock API для тестирования без нагрузки на production

Начать бесплатно →

📝 Выводы

В этой статье мы рассмотрели 3 лучших инструмента для нагрузочного тестирования API:

  1. Apache JMeter — универсальный инструмент с GUI, лучший для enterprise и QA команд
  2. Gatling — Scala DSL, максимальная производительность для highload (60K+ RPS)
  3. K6 — JavaScript, DevOps-friendly, легкая интеграция в CI/CD

🎯 Главное:

Related Articles

← Вернуться к статьям