PRO

Как оптимизировать производительность (профилирование async кода)?

Оптимизацию FastAPI начинают с измерений: p95/p99 latency, throughput, error rate, event loop lag, время SQL и внешних HTTP-вызовов. В async-коде особенно важно находить блокирующие операции, N+1-запросы, неэффективные connection pools и слишком большие payload; исправления подтверждают повторным нагрузочным тестом.
Подробный ответ

Сначала измерения

Нельзя оптимизировать FastAPI только по ощущениям. Нужно определить SLI и SLO, собирать p50, p95 и p99 latency, RPS, error rate, CPU, память, число соединений с базой, event loop lag и время внешних зависимостей.

Где искать узкие места

  • медленные SQL-запросы, отсутствие индексов и N+1;

  • блокирующий синхронный код внутри async def;

  • долгие HTTP-вызовы без корректных тайм-аутов и connection pooling;

  • слишком большие JSON-ответы и дорогая сериализация;

  • неверный размер database pool или слишком много workers;

  • CPU-bound вычисления в web-процессе.

Профилирование async-кода

Для production используют distributed tracing, например OpenTelemetry, и APM, чтобы видеть путь запроса через API, базу и внешние сервисы. Для локального анализа применяют профилировщики Python, такие как py-spy или scalene, а также логи медленных SQL и EXPLAIN ANALYZE в PostgreSQL.

Блокирующие вызовы

Синхронный запрос к сети, файловой системе или синхронной базе внутри async def блокирует event loop. Нужно заменить его асинхронной библиотекой, выполнить в threadpool через asyncio.to_thread() или изменить endpoint на обычный def, если весь используемый стек синхронный.

import asyncio


@app.get('/report')
async def build_report():
    report = await asyncio.to_thread(build_cpu_or_blocking_report)
    return report

База и внешние запросы

Для базы нужно профилировать запросы, добавлять индексы по фактическим фильтрам, устранять N+1 и использовать connection pool. Для внешних HTTP-вызовов нужен один переиспользуемый async client, connect/read timeout, ограничения на retries и circuit breaker для нестабильных зависимостей.

Нагрузочное тестирование

После изменения проводят воспроизводимый нагрузочный тест с реалистичным распределением endpoints, payload и конкурентности. Сравнивают метрики до и после, следят за saturation базы и проверяют, что оптимизация не ухудшила корректность или отказоустойчивость.

Как ответить на собеседовании

Я начинаю с метрик и tracing, чтобы найти конкретный узкий участок: SQL, внешний сервис, блокировку event loop или сериализацию. В async FastAPI отдельно проверяю, нет ли синхронного блокирующего кода внутри async def. Затем оптимизирую целевой участок, например запросы и пулы БД, и подтверждаю результат повторным нагрузочным тестом по p95/p99 и throughput.

Оцени свой прогресс

Честно оцени своё понимание этого вопроса, чтобы мы могли построить твой учебный трек максимально эффективно.
Читать в блоге