Как определить причину медленной работы REST API при ответе через 20 секунд
Что проверяют
Есть ли у вас порядок диагностики или вы сразу предлагаете кэш. Интервьюер ждёт, что вы сначала локализуете задержку: сеть, приложение, база или внешний сервис. Следом часто спрашивают, почему именно 20 секунд, а не случайное число.
Как отвечать
Сначала уточните картину: все запросы или один эндпоинт, всегда или под нагрузкой, с какого момента, после какого релиза. Ровное время вроде 20 секунд почти всегда означает истёкший таймаут: ожидание соединения из пула, блокировка в базе, внешний вызов, DNS.
Дальше по слоям:
- снаружи:
curl -wсtime_namelookup,time_connect,time_starttransferпоказывает, где тратится время, до сервера или в нём; - трассировка: OpenTelemetry со спанами на HTTP-хендлер, запросы в базу и исходящие вызовы сразу показывает, какой шаг занял 19 секунд;
- метрики: гистограммы времени ответа в Prometheus, смотреть p99, а не среднее;
- профилирование:
net/http/pprof, профильgoroutineпокажет, где висят горутины. Профили блокировок и мьютексов включаются черезruntime.SetBlockProfileRateиruntime.SetMutexProfileFraction, по умолчанию они пустые; - пул соединений:
db.Stats()изdatabase/sqlотдаётWaitCountиWaitDuration. Рост ожидания значит, что пул мал или соединения утекают из-за незакрытыхrows; - база:
pg_stat_statements,EXPLAIN (ANALYZE, BUFFERS), блокировки вpg_locksиpg_stat_activity; - исходящие вызовы: у
http.DefaultClientтаймаута нет вообще. Нуженhttp.ClientсTimeoutилиcontext.WithTimeout, и обязательно закрытиеresp.Body, иначе соединения не переиспользуются.
В Kubernetes проверьте ещё CPU throttling от лимитов и GOMAXPROCS: старые версии Go не учитывают лимит контейнера, для них подключают automaxprocs.
Где спотыкаются
Начинают с оптимизаций: Redis, больше горутин, переписать на gRPC. Без замера это выстрел наугад.
Смотрят среднее время ответа. Среднее в 200 мс легко прячет один процент запросов по 20 секунд.
Открывают pprof на публичном порту без авторизации. Для диагностики его вешают на отдельный внутренний адрес.