← Назад к вопросам

Расчитывал ли количество требуемых приложению ресурсов с помощью нагрузочных тестов

2.0 Middle🔥 61 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Нагрузочное тестирование и расчёт ресурсов: мой практический опыт

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

Проект: E-commerce платформа

Контекст

Мы планировали запуск сезонной распродажи, которая по прогнозам должна была привести 10x рост трафика (с 5k RPS до 50k RPS). Это большой скачок, и неправильная калькуляция ресурсов привела бы либо к:

  • Collapse приложения и потери денег
  • Переплата за неиспользуемые ресурсы

Мне дали задачу: определить точно, сколько серверов нам нужно.

Моя методология

Шаг 1: Определение критических сценариев

Не все операции одинаково важны. Я выделил:

// Критические сценарии
1. Browse products (40% трафика) - GET запросы, cache-friendly
2. Add to cart (35% трафика) - POST, write операции
3. Checkout (20% трафика) - тяжелые операции, платежи, БД
4. Admin operations (5% трафика) - не должны влиять на пользователей

Шаг 2: Определение метрик успеха

Я согласовал с бизнесом и DevOps:

  • Response Time (p95): <= 200ms
  • Response Time (p99): <= 500ms
  • Error Rate: < 0.1%
  • CPU Utilization: < 70% (headroom для spikes)
  • Memory Utilization: < 80%

Шаг 3: Выбор инструмента

Я использовал JMeter - мощный open-source инструмент.

# Установка
kafka_2.13-3.0.0/bin/kafka-topics.sh
jmeter -v  # проверка установки

Альтернативы, которые я рассматривал:

  • Gatling - лучше для программистов (Scala DSL)
  • Locust - простой Python интерфейс
  • Apache Bench - слишком простой для моего use case
  • k6 - современный, хорошие возможности

Выбрал JMeter потому что:

  • Богатый UI для построения сценариев
  • Встроенные assertions для проверки корректности
  • Хорошая интеграция с CI/CD
  • Большое сообщество

Шаг 4: Создание сценариев нагрузочного тестирования

Сценарий 1: Ramping up (постепенное увеличение)

Заправка с 0 до 50k RPS за 10 минут
Затем держим 50k RPS 20 минут
Затем спадаем в течение 5 минут

Время: 35 минут

Сценарий 2: Spike test (внезапный скачок)

Нормальная нагрузка 5k RPS
Внезапно скачок до 50k RPS на 2 минуты
Верзёмся к 5k RPS

Проверяем: может ли система справиться с spike
Время: 10 минут

Сценарий 3: Stress test (до отказа)

Постепенно увеличиваем нагрузку
100 RPS -> 500 RPS -> 1000 RPS -> 5000 RPS -> 10000 RPS -> ...

Увеличиваем, пока система не начнёт падать
Это покажет нам breaking point

Шаг 5: Создание JMeter скрипта

Базовая структура

// Thread Group - имитирует пользователей
Num Threads: 1000
Ramp-up Period: 600 seconds (10 минут)
Loop Count: -1 (бесконечно)

// HTTP Requests
1. GET /api/products?page=1
   Assert: Response code = 200
   Assert: Response time < 200ms

2. POST /api/cart
   Body: {"productId": "${productId}", "qty": 1}
   Assert: Response code = 200
   
3. POST /api/checkout
   Body: payment и shipping info
   Assert: Response code = 200

Реальный пример

<jmeterTestPlan>
  <hashTree>
    <ThreadGroup name="Load Test">
      <elementProp name="ThreadGroupElement">
        <stringProp name="ThreadGroup.num_threads">1000</stringProp>
        <stringProp name="ThreadGroup.ramp_time">600</stringProp>
        <elementProp name="ThreadGroup.main_controller"/>
      </elementProp>
    </ThreadGroup>
    
    <HTTPSamplerProxy name="Browse Products">
      <stringProp name="HTTPSampler.domain">api.example.com</stringProp>
      <stringProp name="HTTPSampler.port">443</stringProp>
      <stringProp name="HTTPSampler.protocol">https</stringProp>
      <stringProp name="HTTPSampler.path">/api/v1/products</stringProp>
      <stringProp name="HTTPSampler.method">GET</stringProp>
    </HTTPSamplerProxy>
    
    <ResponseAssertion name="Response Code Check">
      <intProp name="Assertion.test_type">1</intProp>
      <stringProp name="Assertion.test_strings">200</stringProp>
    </ResponseAssertion>
    
    <ResultCollector name="Aggregate Report">
      <filename>/tmp/jmeter-results.jtl</filename>
    </ResultCollector>
  </hashTree>
</jmeterTestPlan>

Шаг 6: Запуск тестов

На staging окружении (идентичное production)

jmeter -n -t ecommerce-load-test.jmx \
  -l results.jtl \
  -j jmeter.log \
  -Jserver.host=staging.api.example.com \
  -Jserver.port=443

Мониторинг во время теста

Важно одновременно смотреть метрики серверов:

# SSH на приложение сервер и мониторим
top           # CPU, Memory
iostat -x 1   # I/O, Disk
netstat -an   # Network connections

# Или через инструменты:
Prometheus   # metrics
Grafana      # visualization
jaeger       # distributed tracing

Шаг 7: Анализ результатов

JMeter Aggregate Report

        Samples  Avg   Min   Max   Std Dev Error%  Throughput
Browse  500000   150   45    1200  80     0.02%   16.67/sec
Cart    440000   200   60    1500  120    0.05%   14.67/sec
Checkout 220000  450   100   3000  250    0.1%    7.33/sec
Total   1160000  250   45    3000  150    0.06%   38.67/sec

Что я видел из результатов

Проблема 1: Checkout слишком медленный (450ms avg, p99 > 2s)

Рут кауза: n+1 query в БД при обработке платежей.

Исправление:

// ДО
Order order = createOrder(user);
for (CartItem item : order.getItems()) {
    Product product = productRepository.findById(item.getProductId()); // N queries!
}

// ПОСЛЕ
Order order = createOrder(user);
Set<Long> productIds = order.getItems().stream()
  .map(CartItem::getProductId)
  .collect(Collectors.toSet());
List<Product> products = productRepository.findAllById(productIds); // 1 query

Проблема 2: Memory leak - используемая память растёт

Рут кауза: HttpSession'ы не очищаются.

Исправление: настроил session timeout в web.xml.

Стресс тест: breaking point

И обнаружил, что при 150k RPS (3x от целевого):

  • Response time растёт экспоненциально
  • Error rate >5%
  • API возвращает 503 Service Unavailable

Это дало мне информацию о максимальной capacity одного сервера: ~50k RPS.

Шаг 8: Расчёт ресурсов

Формула

Требуемые серверы = (целевая нагрузка / throughput на сервер) * коэффициент страховки

Требуемые серверы = (50,000 RPS / 50,000 RPS) * 2 = 2 сервера

Коэффициент страховки = 2:

  • 1x для спайков (внезапное увеличение нагрузки)
  • 1x для обновлений (когда один сервер offline на развёртывание)

Детальная калькуляция

Исходные данные:
- Целевой throughput: 50,000 RPS
- Throughput на один сервер: 50,000 RPS (из нагрузочного теста)
- Max acceptable response time (p95): 200ms
- Коэффициент страховки: 2.0
- Коэффициент spike: 1.5 (максимальный spike может быть 1.5x среднего)

Расчёт:
- Среднее требуемых RPS: 50,000
- Максимальное (с spike): 50,000 * 1.5 = 75,000
- Требуемые серверы: 75,000 / 50,000 = 1.5, округляем к 2 серверам
- С failover запасом: 2 * 1.5 = 3 сервера

Вывод: нужно 3 сервера для уверенности

Калькуляция памяти и CPU

Из результатов стресс-теста я заметил:

На 50k RPS:
- CPU: 65% (хорошо, есть headroom)
- Memory (heap): 3.5GB из 4GB (нужно мониторить)
- GC pauses: 100-200ms каждые 10 секунд

Я рекомендовал:

Кождый сервер:
- CPU: 8 cores (было достаточно 4, но headroom)
- Memory: 8GB heap (-Xmx8g), 16GB total
- SSD: 500GB (для логов, кеша)

Шаг 9: Сравнение с production метриками

После запуска сезонной продажи я проверил реальные метрики:

Прогнозирано:     Реально:
50k RPS          ~52k RPS     ✓ (в пределах погрешности)
Response (p95): 200ms       180ms       ✓ (лучше, чем ожидалось)
Error rate: <0.1%          0.03%       ✓ (отлично)
CPU: 65%                   62%         ✓ (как и ожидалось)

Мои расчёты были точны! Экономия: платили за ровно столько ресурсов, сколько нужно.

Best practices, которые я использую

  1. Тестируй на production-like окружении - staging обычно слабее
  2. Мониторь дополнительные метрики - память, дискс, сеть, GC
  3. Используй realistic data - реальные объёмы, реальные скорости
  4. Включай warmup phase - JVM нужно разогреться (JIT compilation)
  5. Проводи несколько итераций - результаты могут варьироваться
  6. Документируй результаты - для будущих улучшений

Инструменты, которые я используюю в связке

  • JMeter / Gatling - генерация нагрузки
  • Prometheus - сбор метрик
  • Grafana - визуализация
  • ELK Stack - логирование
  • Jaeger - distributed tracing
  • Custom monitoring scripts - специфичные для приложения метрики

Вывод

Нагрузочное тестирование - это не просто "что-то что нужно сделать". Это инженерный инструмент для принятия правильных инфраструктурных решений. С его помощью я могу предсказать требуемые ресурсы, выявить узкие места в коде и убедиться, что приложение готово к production нагрузкам.

Мой подход: тестировать рано и часто, использовать realistic сценарии, мониторить все метрики и документировать результаты для будущего использования.

Расчитывал ли количество требуемых приложению ресурсов с помощью нагрузочных тестов | PrepBro