Как диагностировать и отлаживать проблемы с производительностью сервиса?
Что проверяют
Есть ли у вас метод, а не набор инструментов: сначала измерить и локализовать, потом чинить. Интервьюер ждёт, что вы отличите медленную базу от заблокированного event loop и от вычислений, упёршихся в GIL. Следом обычно дают кейс: «p99 вырос с 200 мс до 2 секунд, ваши действия».
Как отвечать
Стройте ответ как воронку от симптома к строке кода:
- симптом в метриках: задержка по перцентилям, RPS, ошибки, загрузка CPU и памяти в Prometheus и Grafana. Смотрите, совпал ли рост с релизом, всплеском трафика или конкретным эндпоинтом;
- где тратится время: трассировка через OpenTelemetry показывает, какой спан медленный: запрос в базу, внешний HTTP или собственный код;
- база:
pg_stat_statementsдля тяжёлых запросов,EXPLAIN ANALYZEдля плана, поиск N+1 в ORM (select_relatedиprefetch_relatedв Django,selectinloadв SQLAlchemy), исчерпание пула соединений; - свой код на проде:
py-spyподключается к живому процессу без перезапуска,py-spy top --pidиpy-spy dumpпоказывают, где сидят потоки,py-spy recordстроит flame graph. Локально помогаютcProfileсоsnakevizиline_profilerдля конкретной функции; - память:
tracemallocилиmemray, если процесс растёт и уходит в OOM; - asyncio: режим отладки (
PYTHONASYNCIODEBUG=1) пишет в лог колбэки, которые держат цикл дольше 100 мс. Типичная причина: синхронныйrequestsили тяжёлый разбор JSON внутриasync def.
Гипотезу проверяете воспроизведением под нагрузкой (Locust, k6) и сравниваете метрики до и после исправления.
Где спотыкаются
Начинают оптимизировать код на глаз: переписывают цикл, хотя почти всё время запроса уходит на ожидание базы.
Смотрят на среднее время ответа. Среднее прячет хвост, а пользователи жалуются как раз на p99.
Лечат вычислительную нагрузку потоками. В стандартной сборке CPython потоки из-за GIL не ускоряют вычисления, нужны процессы, C-расширение или вынос работы в отдельный сервис.