Услуги по нагрузочному тестированию и Chaos Engineering

Нагрузочное тестирование: k6, JMeter, Gatling, Locust, wrk. Chaos Engineering (Chaos Monkey, LitmusChaos). Стресс-тесты, soak-тесты и анализ bottleneck'ов.

Наши компетенции:

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

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1523
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1351
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1069
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1326
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    766
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1071

Почему нагрузочное тестирование проваливается даже после успешного релиза?

Релиз прошёл гладко. Через три дня — промо-акция, трафик вырастает в 10 раз. Через четыре часа после старта акции база данных встаёт на lock wait timeout, API возвращает 504, и поддержка тонет в тикетах. При этом staging прошёл нагрузочный тест «успешно» — потому что тестировали 50 пользователей, а реальный трафик дал 5000. Такая ситуация повторяется в каждом втором проекте, который к нам приходит. Мы видим одни и те же ошибки: тесты пишутся на один сценарий, не учитываются медленные запросы при cache miss, и полностью игнорируется поведение системы при отказе зависимых сервисов. Нагрузочное тестирование — это не галочка перед релизом. Это процесс нахождения точки, где система начинает деградировать, и понимания, почему именно там. Наши инженеры с 10-летним опытом в performance testing гарантируют, что после работы с нами вы точно будете знать предел своей системы.

k6: от простого скрипта до production-grade теста

k6 — наиболее удобный инструмент для написания нагрузочных тестов в виде кода. JavaScript-синтаксис, встроенные метрики, нативная интеграция с Grafana через k6 cloud или xk6-output-prometheus-remote.

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

Пример: тест с авторизацией и зависимыми запросами:

import http from 'k6/http'; import { check, sleep } from 'k6'; import { SharedArray } from 'k6/data'; const users = new SharedArray('users', function () { return JSON.parse(open('./users.json')); }); export const options = { scenarios: { warm_up: { executor: 'ramping-vus', startVUs: 0, stages: [ { duration: '2m', target: 100 }, { duration: '5m', target: 100 }, { duration: '2m', target: 0 }, ], }, spike: { executor: 'ramping-arrival-rate', startRate: 0, timeUnit: '1s', preAllocatedVUs: 500, stages: [ { duration: '30s', target: 500 }, { duration: '1m', target: 500 }, { duration: '30s', target: 0 }, ], startTime: '9m', }, }, thresholds: { http_req_duration: ['p(95)<500', 'p(99)<1500'], http_req_failed: ['rate<0.01'], }, }; export default function () { const user = users[Math.floor(Math.random() * users.length)]; const loginRes = http.post(`${__ENV.BASE_URL}/api/auth/login`, JSON.stringify({ email: user.email, password: user.password, }), { headers: { 'Content-Type': 'application/json' } }); check(loginRes, { 'login 200': (r) => r.status === 200 }); const token = loginRes.json('access_token'); if (!token) return; const headers = { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }; const catalogRes = http.get(`${__ENV.BASE_URL}/api/catalog?page=1`, { headers }); check(catalogRes, { 'catalog 200': (r) => r.status === 200 }); sleep(Math.random() * 2 + 1); } 

Несколько важных деталей в этом скрипте. SharedArray загружает данные один раз на все VU, а не копирует в каждый — при 500 VU и файле на 10000 строк разница в памяти ощутима. ramping-arrival-rate симулирует реальную нагрузку по RPS, а не по количеству пользователей — это важно: 100 VU с sleep(1) дадут ~100 RPS, но 100 VU без sleep могут дать тысячи, что не соответствует реальному поведению.

Thresholds — главный инструмент pass/fail. p(95)<500 означает: 95% запросов должны укладываться в 500ms. Если порог не пройден, k6 завершается с кодом 1 — CI-пайплайн может это поймать.

k6 run --out influxdb=http://localhost:8086/k6 script.js — стриминг метрик в реальном времени. В связке с Grafana-дашбордом (ID 2587 из grafana.com) получаем live-картину теста: RPS, latency по перцентилям, количество ошибок, активные VU.

Что выбрать: JMeter, Gatling или k6?

Инструмент Язык скриптов Потребление ресурсов Масштабирование Сообщество
k6 JavaScript Низкое (Go-based) Встроенное, Kubernetes-native Активное, open-source
JMeter XML/Java GUI Высокое (Java-потоки) Distributed (jmeter-server) Крупное, корпоративное
Gatling Scala DSL Среднее (JVM, но эффективнее JMeter) Distributed (injectors) Растущее, Java/Scala

Выбор инструмента часто определяется не техническими характеристиками, а тем, кто пишет тесты: разработчики привыкли к коду (k6/Gatling), QA-команды — к GUI (JMeter). k6 потребляет примерно в 5 раз меньше памяти, чем JMeter при равном количестве виртуальных пользователей, что делает его лучшим выбором для непрерывного тестирования в CI/CD.

Chaos Engineering: сломать контролируемо, чтобы не сломалось неожиданно

Chaos Engineering — это следующий уровень после нагрузочного тестирования. Нагрузка проверяет, что система держит трафик. Chaos проверяет, что система правильно деградирует при отказе компонентов.

Chaos Engineering — наиболее зрелый инструмент для Kubernetes. Устанавливается как CRD и управляется через YAML или Web UI.

Сценарий: что происходит с приложением, когда один из трёх инстансов базы данных перестаёт отвечать?

apiVersion: chaos-mesh.org/v1alpha1 kind: NetworkChaos metadata: name: db-network-delay namespace: production spec: action: delay mode: one selector: namespaces: - production labelSelectors: app: postgresql delay: latency: "200ms" correlation: "25" jitter: "50ms" duration: "10m" scheduler: cron: "@every 1h" 

Этот манифест добавляет 200ms задержки сети к одному случайному поду с меткой app: postgresql раз в час на 10 минут. Запускается параллельно с нагрузочным тестом — смотрим, как меняется p(99) latency приложения.

PodChaos для проверки устойчивости к перезапускам:

apiVersion: chaos-mesh.org/v1alpha1 kind: PodChaos metadata: name: api-pod-kill spec: action: pod-kill mode: fixed-percent value: "33" selector: namespaces: [production] labelSelectors: app: api-service gracePeriod: 0 duration: "5m" 

33% подов api-service убиваются мгновенно (без graceful shutdown) раз в прогоне. Ожидаемый результат: метрика ошибок временно растёт, но Kubernetes восстанавливает поды, и через 30–60 секунд ошибки уходят. Если ошибки не уходят — есть проблема с readiness probe или деплойментом.

Принцип GameDay: Chaos-эксперименты нужно проводить в рабочее время при участии команды, не ночью в одиночку. Цель — не сломать prod, а выработать мышечную память реакции на инциденты.

Что проверять с помощью Chaos Engineering в первую очередь?

  • Отказ одной зоны доступности (NetworkChaos на весь namespace одной AZ)
  • Нехватка памяти у ключевого сервиса (StressChaos с memoryWorkers: 4, memoryBytes: "1GB")
  • Latency к внешнему API (HTTPChaos с задержкой на исходящие запросы)
  • Заполнение диска (IOChaos + дополнительный контейнер, пишущий мусор)

Chaos Engineering — не про то, чтобы всё сломать. Это про то, чтобы знать заранее, что именно сломается и в каком порядке. Наши сертифицированные инженеры провели более 50 таких экспериментов на production-проектах.

Как интерпретировать результаты load-теста?

Тест закончился, цифры есть. После завершения мы анализируем три ключевых сценария.

p(50) нормальный, а p(99) — катастрофа. Это говорит о хвосте распределения — запросах, которые попадают на медленный path. Часто это cache miss, полный table scan при определённых параметрах, или GC pause в JVM.

Ошибки connection reset by peer под нагрузкой — исчерпан лимит соединений. Смотреть на ulimit -n на сервере, SOMAXCONN, keepalive настройки в Nginx/HAProxy, pool size в connection pool приложения.

Нагрузка линейно растёт, latency стабильна до 60% CPU, потом резко растёт — классический признак CPU-bound узкого места. Профилировщик (async-profiler для JVM, py-spy для Python) покажет, что именно занимает CPU. Такая диагностика позволяет снизить стоимость облачной инфраструктуры в среднем в 2 раза у наших клиентов.

Что входит в работу по нагрузочному тестированию?

  • Анализ архитектуры и бизнес-сценариев (выявляем критичные экшенпоинты)
  • Написание и отладка скриптов (k6/JMeter/Gatling)
  • Smoke-тест, load-тест, spike-тест, soak-тест
  • Проведение Chaos-экспериментов (если требуется)
  • Детальный отчёт с графиками: latency по перцентилям, RPS, ошибки, bottleneck-компоненты
  • Рекомендации по оптимизации (конфиги, инфраструктура, код)
  • Интеграция тестов в ваш CI/CD (GitLab CI / GitHub Actions)
  • Пост-релизная поддержка: выполнение замеров на проде

Сроки и формат работы

Тип тестирования Масштаб Срок
Smoke + load тест 1–3 сценария, один сервис 1–2 дня
Полное нагрузочное тестирование 10+ сценариев, микросервисы 1–2 недели
Chaos Engineering Kubernetes, 5–10 экспериментов 1–3 недели
Continuous performance testing Интеграция в CI/CD 2–4 недели

Стоимость рассчитывается индивидуально после анализа архитектуры и целей тестирования. Оценим ваш проект — свяжитесь с нами для консультации. Закажите нагрузочное тестирование под ключ и получите гарантированное выявление узких мест до того, как их найдёт ваш прод.