Нагрузить монолит просто: бьёшь по одному эндпоинту, измеряешь один процесс. С микросервисами иначе. Одно действие пользователя может развернуться в десятки downstream-вызовов, и тестирование сервисов по отдельности пропускает именно те режимы отказа, которые на самом деле кладут системы.
Почему тестов на уровне сервиса недостаточно
Прогнать каждый сервис на 1 000 RPS в изоляции — почти ничего не узнать о том, как поведёт себя система, когда сервис A вызывает B, а тот вызывает C: каждый добавляет латентность, каждый способен на каскадный сбой.
Нужны сквозные (end-to-end) нагрузочные тесты, которые прогоняют систему через реальные пользовательские сценарии.
Паттерн 1: тестирование пользовательских сценариев
Моделируйте реалистичные пользовательские потоки вместо отдельных эндпоинтов:
import http from 'k6/http';
import { sleep, group } from 'k6';
export default function () {
group('Browse catalog', () => {
http.get(`${BASE_URL}/api/products`);
sleep(1.5);
http.get(`${BASE_URL}/api/products/42`);
sleep(0.5);
});
group('Add to cart', () => {
http.post(`${BASE_URL}/api/cart`, JSON.stringify({ productId: 42, qty: 1 }));
sleep(1);
});
group('Checkout', () => {
http.post(`${BASE_URL}/api/orders`);
sleep(2);
});
}
Так возникает реалистичное распределение трафика по сервисам — каталог получает в 3 раза больше нагрузки, чем сервис заказов.
Паттерн 2: хаос + нагрузка
Чистые нагрузочные тесты говорят о ёмкости в устойчивом состоянии. Комбинируйте их с chaos engineering, чтобы найти режимы отказа:
- Убейте реплику посреди теста — трафик перенаправится чисто?
- Впрысните 200 мс латентности в платёжный сервис — таймауты выше по цепочке каскадируют?
- Заполните очередь — backpressure распространяется корректно?
Частые подводные камни
Thundering herd на разгоне: плавное наращивание VU спасает пулы соединений от исчерпания на старте.
Отсутствие think time: реальные пользователи не долбят API без пауз — добавляйте sleep(), чтобы имитировать реалистичный темп.
Конкуренция за общие тестовые данные: несколько VU, пишущих в одни и те же записи, создают lock contention, которого нет в продакшне. Используйте уникальные данные на каждого VU.
Игнорирование асинхронных потоков: если действие ставит работу в очередь, тест должен проверить, что очередь разгребается — а не только что enqueue вернул 202.