Как понять пропускную способность приложения по максимальному и среднему времени ответа
Что проверяют
Понимаете ли вы, что пропускная способность не выводится из времени ответа напрямую, нужна ещё конкурентность. Интервьюер ждёт закон Литтла и скепсис к среднему и максимуму как метрикам. Следом обычно спрашивают, как бы вы провели нагрузочный тест и на какие перцентили смотрели бы.
Как отвечать
Начните с определений: throughput это число обработанных запросов в секунду (RPS), latency это сколько ждёт один запрос. Связывает их закон Литтла: среднее число запросов в системе равно пропускной способности, умноженной на среднее время ответа. Отсюда оценка потолка: пропускная способность примерно равна числу одновременно обслуживаемых запросов, делённому на среднее время ответа.
На Python это считается наглядно:
- синхронный Gunicorn: каждый sync-воркер держит один запрос. 8 воркеров при среднем ответе 50 мс дают потолок около 160 RPS. С
--threadsGunicorn переходит на gthread-воркеры и конкурентность растёт, но CPU-bound код упирается в GIL; - асинхронный стек: у Uvicorn с FastAPI конкурентность ограничивают пул соединений к базе, лимиты внешних API и CPU. Одна блокирующая операция в
async defстопорит event loop всего воркера; - среднее и максимум: максимум показывает один худший запрос, часто это прогрев, сборка мусора или сетевой сбой. Среднее прячет хвост. Смотрите p50, p95, p99.
Правильная методика: нагрузочный тест в Locust или k6 со ступенчатым ростом нагрузки. Пока система не насыщена, RPS растёт линейно, а latency почти не меняется. Точка, где RPS выходит на плато, а p95 резко растёт, и есть реальная пропускная способность. Параллельно смотрите CPU, пул соединений и очередь запросов.
Где спотыкаются
Делят длительность теста на максимальное время ответа и называют это пропускной способностью. Максимум это выброс, и цифра выходит бессмысленной.
Судят по среднему. При среднем 100 мс у каждого сотого пользователя может быть 3 секунды, а именно их жалобы и приходят в поддержку.
Гоняют нагрузку с одной машины, которая сама упирается в CPU, или генератором, который ждёт ответа перед следующим запросом. Тормозящий сервер тогда получает меньше нагрузки и выглядит лучше, чем есть: это coordinated omission.