MAATRIX / Блог / Репетиция пика: нагрузочный тест за неделю до распродажи

Репетиция пика: нагрузочный тест за неделю до распродажи

MAATRIX

За неделю до распродажи хочется верить, что сервер выдержит — но «выдержит» и «выдерживал полгода назад на регулярном прогоне» это два разных утверждения. Профиль трафика на конкретную акцию не похож на усреднённую нагрузку: за первые 15 минут может прийти столько же пользователей, сколько обычно за сутки, а корзина и оплата нагружаются так, как не нагружаются никогда в обычные дни. Репетиция пика — это не абстрактный тест «а вдруг», а прогон, смоделированный по историческим данным именно этого события, ровно за неделю до него, чтобы результат отражал систему в её нынешнем состоянии.

Чем репетиция пика отличается от планового нагрузочного тестирования

Если в компании уже есть регулярная практика — скажем, нагрузочное тестирование раз в полгода — может показаться, что предпродажный тест дублирует эту работу. Это не так, и разница принципиальная.

Плановый прогон раз в полгода отвечает на вопрос «где вообще потолок системы», независимо от календаря: он использует условный синтетический профиль нагрузки (ступенчатый рост RPS без привязки к конкретному сценарию использования) и его цель — держать актуальную картину пределов системы в фоне, чтобы не узнавать о них случайно. Такой тест хорош как регулярная гигиена, но он ничего не знает о том, что 14 сентября у вас распродажа и что именно в этот день трафик придёт не равномерно распределённым RPS, а взрывным профилем: рекламная рассылка ушла в 12:00, пуш — в 12:00, и первые несколько минут — это не рост, а скачок.

Репетиция пика решает другую задачу — с конкретным адресатом:

Плановое тестирование раз в полгодаРепетиция перед конкретным пиком
Когдапо календарю, независимо от бизнес-событийза неделю до конкретной известной даты
Профиль нагрузкисинтетический, ступенчатый ростсмоделирован по историческим данным прошлого похожего пика
Что проверяетсяобщий потолок системыготовность именно к этому событию, с его сценариями
Сценариитипичные операции + тяжёлые эндпоинтыпуть покупки целиком: каталог → корзина → оформление → оплата
Что делать с находкамитикеты в бэклог, без жёсткого дедлайнафикс до дня X или явное решение, что риск принят

Если оба процесса в компании есть — это правильно, они не конкурируют. Плановый прогон держит общую картину пределов, а репетиция перед конкретным пиком проверяет, что система готова именно к этому дню, с этим сценарием, с этим кодом, который был задеплоен вчера. У читателя, который ищет именно предпродажный тест, обычно нет времени и мандата разворачивать целую программу регулярного тестирования — ему нужен один прогон, максимально приближенный к реальности, и именно об этом весь дальнейший текст.

Почему именно неделя, а не месяц

Соблазн протестировать пораньше понятен — за месяц до распродажи спокойнее, есть время на фиксы. Но у раннего теста фундаментальная проблема: он проверяет не ту систему, которая встретит реальный трафик.

За оставшийся месяц до дня X обычно происходит следующее:

  • Деплоятся новые фичи, в том числе те, что специально готовились к распродаже — новый баннер, изменённая логика скидок, новый способ оплаты.
  • Меняются данные — растёт каталог, добавляются акционные товары, разрастаются таблицы с историей заказов.
  • Меняется конфигурация инфраструктуры — кто-то поднял лимиты пула соединений, кто-то забыл откатить временный дебаг-логгинг.
  • Могут смениться внешние интеграции — новый эквайринг, новый сервис доставки, обновлённая версия SDK платёжного провайдера.

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

Неделя — это компромисс между двумя ограничениями:

  • Достаточно близко к событию, чтобы система была практически в финальном состоянии — код заморожен или почти заморожен, конфигурация окончательная, интеграции проверены.
  • Достаточно времени, чтобы успеть отреагировать на находки: пересмотреть индекс в базе, поднять лимиты, откатить рискованную фичу, а при необходимости — временно отключить некритичный функционал по аналогии с тем, что разобрано в статье что отключить на время пика, чтобы устояла корзина.

Тестировать за день до распродажи — уже поздно: если тест находит серьёзную проблему (например, конкурентная блокировка в таблице заказов при параллельных апдейтах), её физически не успеть исправить и протестировать повторно. Неделя даёт запас на цикл «нашли → исправили → перепроверили» хотя бы один раз, а в идеале — два, если первая находка была некритичной.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Как построить профиль нагрузки по историческим данным

Главное отличие репетиции пика от абстрактного нагрузочного теста — профиль нагрузки не выдумывается, а восстанавливается из того, что реально происходило на прошлом похожем событии. Если распродажа регулярная (сезонная, ежегодная акция, «чёрная пятница» аналог) — у вас почти наверняка есть логи и метрики с прошлого раза.

Источники данных для профиля:

  • Логи веб-сервера (nginx access log) с датой прошлого пика — из них восстанавливается реальная кривая RPS по минутам, а не средняя цифра за день.
  • Метрики APM/мониторинга — если снимался Prometheus/Grafana, там видна нагрузка по эндпоинтам: сколько запросов шло на каталог, сколько на корзину, сколько на оформление заказа.
  • Аналитика магазина — количество заказов по минутам, конверсия из просмотра в покупку, распределение по способам оплаты.
  • Данные CDN/балансировщика, если он логирует запросы отдельно от бэкенда — иногда там точнее видно исходный всплеск до кэширования.

Практический разбор лога прошлого пика:

# Распределение запросов по минутам за час старта прошлой акции
awk '{print substr($4, 2, 17)}' access.log \
  | uniq -c \
  | sort -k2

# Топ эндпоинтов по количеству запросов в первые 15 минут пика
awk -v start="14/Mar/2026:12:00" -v end="14/Mar/2026:12:15" \
  '$4 >= "["start && $4 <= "["end {print $7}' access.log \
  | sort | uniq -c | sort -rn | head -20

Из этого получается не абстрактная «нагрузка x3», а конкретная форма кривой: например, в первые 3 минуты — резкий скачок до 400% от обычного пикового RPS, дальше плато на 250% в течение часа, затем плавный спад. Именно эту форму, а не ровный рост, и нужно воспроизводить в тесте — потому что резкий скачок нагружает систему принципиально иначе, чем плавный: не успевает прогреться кэш, connection pool не успевает расшириться, автоскейлинг (если есть) не успевает среагировать.

Если исторических данных нет — первая распродажа, логи не сохранились — профиль строится по косвенным оценкам: размер рассылки, охват рекламы, известные паттерны похожих акций в отрасли. Такая оценка менее точна, но подход тот же: не ровный рост, а взрывной скачок в первые минуты, с явной пометкой в отчёте, что цифры ориентировочные.

Сценарий теста: путь покупки, а не отдельные эндпоинты

Плановое нагрузочное тестирование часто бьёт по отдельным ручкам — GET на каталог, GET на карточку товара. Для репетиции пика этого мало: реальный пользователь на распродаже проходит связную последовательность действий, и узкое место может быть не в отдельном запросе, а в их сочетании.

Минимальный сценарий на k6, воспроизводящий путь покупки целиком:

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  scenarios: {
    peak_replay: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '2m', target: 800 },   // резкий скачок как в первые минуты
        { duration: '20m', target: 800 },  // плато пика
        { duration: '10m', target: 300 },  // спад
        { duration: '5m', target: 50 },    // хвост
      ],
    },
  },
  thresholds: {
    http_req_failed: ['rate<0.02'],
    'http_req_duration{endpoint:checkout}': ['p(95)<1500'],
  },
};

export default function () {
  // 1. Заход в каталог
  let res = http.get('https://staging.example.com/catalog?sale=true');
  check(res, { 'catalog 200': (r) => r.status === 200 });
  sleep(Math.random() * 3 + 1);

  // 2. Карточка товара
  res = http.get('https://staging.example.com/product/1234', {
    tags: { endpoint: 'product' },
  });
  sleep(Math.random() * 2 + 1);

  // 3. Добавление в корзину
  res = http.post('https://staging.example.com/cart/add', JSON.stringify({ id: 1234, qty: 1 }), {
    headers: { 'Content-Type': 'application/json' },
    tags: { endpoint: 'cart' },
  });
  check(res, { 'cart 200': (r) => r.status === 200 });
  sleep(1);

  // 4. Оформление заказа (без реальной оплаты — тестовый режим провайдера)
  res = http.post('https://staging.example.com/checkout', JSON.stringify({ cart_id: 'test' }), {
    headers: { 'Content-Type': 'application/json' },
    tags: { endpoint: 'checkout' },
  });
  check(res, { 'checkout 200': (r) => r.status === 200 });
}

Важные детали конкретно для предпродажного сценария:

  • Оплата — в тестовом режиме провайдера, никогда не через боевой эквайринг. Большинство платёжных систем дают sandbox-окружение или тестовые карты именно для такого случая.
  • Разные веса на разные пути — не все пользователи доходят до оплаты; на реальной распродаже воронка обычно резко сужается на каждом шаге, и если это не отразить в тесте, чекаут будет нагружен нереалистично сильно (или слабо).
  • Промокоды и скидки — если распродажа завязана на купоны, стоит включить в сценарий именно эту логику: применение промокода часто идёт отдельным медленным запросом с обращением к базе правил.
  • Одновременная нагрузка на админку/бэкофис — если в день акции сотрудники активно смотрят дашборд заказов в реальном времени, это тоже нагрузка на ту же базу, и её стоит учитывать, а не тестировать только витрину в изоляции.

Что проверять отдельно: корзина, база и внешние интеграции

Общие метрики (CPU, память, p95/p99, доля ошибок) собираются так же, как на любом нагрузочном тесте — здесь принцип не отличается от того, что описано в статье про порог отказа под нагрузкой. Но у предпродажного теста есть свои специфические точки риска, которые стоит проверить прицельно.

Блокировки в базе при параллельном списании остатков. Если на распродаже ограниченное количество товара, а логика списания использует SELECT ... FOR UPDATE или похожую блокировку строки, при высокой конкурентности именно здесь возникает затор — сотни параллельных запросов ждут на одной строке. Проверить это можно, сгенерировав нагрузку на один и тот же товар с ограниченным остатком, и посмотреть на pg_stat_activity (для PostgreSQL) в момент теста:

SELECT pid, state, wait_event_type, wait_event, query
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY query_start;

Если видно много строк с wait_event_type = 'Lock' — это симптом именно такой блокировки, и её лучше найти на тесте, а не в момент, когда сотни реальных покупателей одновременно жмут «купить» на акционный товар.

Поведение кэша при холодном старте. Если перед пиком кэш (Redis, Memcached, CDN) очищается или перезапускается — например, вместе с релизом акционных цен — первые минуты пика идут мимо кэша прямо в базу. Стоит явно проверить сценарий «кэш пуст, трафик уже пиковый», а не только «кэш прогрет, трафик растёт постепенно».

Внешние интеграции под нагрузкой. Платёжный шлюз, служба доставки, SMS/push-провайдер для подтверждений заказа — у всех есть свои лимиты запросов в секунду. Стоит заранее уточнить у провайдера лимит вашего тарифа и либо убедиться, что пиковая нагрузка в него укладывается, либо заранее договориться о временном повышении на день акции.

Очередь и воркеры для отложенных операций. Если подтверждение заказа, письмо с чеком или синхронизация со складом идут через очередь (RabbitMQ, SQS, Redis-based), стоит проверить не только приём запроса, но и скорость разбора очереди под пиковым потоком — иначе письмо с подтверждением может прийти через час после покупки, а это заметно бьёт по доверию.

Итоговый чек-лист и что делать с результатом

Результат репетиции пика фиксируется так же дисциплинированно, как любой нагрузочный тест — с датой, конфигурацией на момент теста и найденной точкой отказа. Но здесь есть дополнительное требование: результат должен превратиться в конкретные решения до дня X, а не в список «когда-нибудь оптимизировать».

Чек-лист для отчёта за неделю до распродажи:

  • Профиль нагрузки был смоделирован по историческим данным (указать, по какому событию) или по оценке (указать, на основе чего).
  • Путь покупки протестирован целиком, а не отдельными эндпоинтами: каталог → карточка → корзина → чекаут → оплата (в тестовом режиме).
  • Проверено поведение при холодном кэше в момент старта пика.
  • Проверены блокировки в базе при параллельном списании остатков на популярные позиции.
  • Известны rate-лимиты внешних интеграций (платёжка, доставка, уведомления) и подтверждено, что пиковый трафик в них укладывается.
  • Проверена скорость разбора очередей отложенных задач под пиковой нагрузкой.
  • Для каждой находки — явное решение: фикс до дня X, временное отключение функциональности на время пика, или осознанно принятый риск с оговоренным планом действий, если он реализуется.
  • Назначен ответственный, который в день распродажи следит за теми же метриками, что снимались на тесте — чтобы сравнивать реальность с репетицией в реальном времени.

Если после теста остаются находки, которые не успеть исправить, но которые критичны — честный вариант не «понадеяться», а заранее решить, что отключить на время пика (по аналогии с разбором в статье о том, что отключить, чтобы устояла корзина). А если тест показал, что текущая конфигурация сервера в принципе не тянет ожидаемый профиль — стоит заранее пересчитать нужные ресурсы, например по методике из статьи как рассчитать конфигурацию сервера под нагрузку, и арендовать более мощный тариф на период акции, а не постфактум разбираться, во что обошёлся простой на пике.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли провести репетицию пика прямо на проде?

Можно, но только с явным тестовым режимом оплаты и с предупреждением команды — тестовые заказы не должны попасть в реальную аналитику продаж и на реальную отгрузку склада. Часто безопаснее использовать staging-окружение, максимально приближенное к проду по конфигурации и объёму данных, и дополнить его коротким контрольным прогоном на проде вне тестового трафика.

Что если исторических данных о прошлом пике нет вообще?

Стройте профиль по косвенным оценкам — размер рассылки, охват рекламы, опыт похожих акций в отрасли — и явно пометьте в отчёте, что цифры ориентировочные. После первой распродажи обязательно сохраните логи и метрики этого дня: следующая репетиция уже будет опираться на реальные данные, а не на догадки.

Нужна ли репетиция пика, если полгода назад уже проходило плановое нагрузочное тестирование?

Да, это разные проверки. Плановый тест показывает общий потолок системы на абстрактном профиле, репетиция пика — готовность именно к этому событию с реальным сценарием покупки и с кодом, который будет в проде в день акции. За полгода между плановым тестом и распродажей могли поменяться и код, и данные, и интеграции.

Что делать, если за неделю до пика тест нашёл критичную проблему, которую физически не успеть исправить?

Не рисковать основным сценарием покупки: временно отключить проблемную функциональность (например, сложную фильтрацию или необязательную интеграцию) на время акции, если это возможно, или заложить в дежурство ручной план действий на случай, если узкое место сработает. Худший вариант — узнать о проблеме впервые в момент реального пика.

Сколько раз стоит повторять репетицию перед одной распродажей?

Минимум один раз, за неделю. Если первый прогон нашёл серьёзные проблемы и на исправление ушло несколько дней — стоит успеть повторный контрольный прогон за 1-2 дня до старта, уже не полным профилем, а сокращённым, чтобы подтвердить, что фикс действительно снял находку и не завёл новую.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →