Как расследовать проблему медленной работы сервиса и какие метрики и инструменты использовать
Что проверяют
Есть ли у вас метод, а не набор инструментов: сначала локализовать, где теряется время, потом копать в конкретный слой. Следом обычно дают сценарий вроде «p99 вырос в пять раз, CPU в норме» и просят рассуждать вслух.
Как отвечать
Идти стоит сверху вниз:
- симптом в метриках: RED по эндпоинтам (rate, errors, duration) через
prometheus/client_golangс гистограммами. Смотреть p95 и p99, среднее прячет хвост. Выяснить, когда началось и совпало ли с релизом, ростом трафика или изменениями у зависимостей; - ресурсы: в Kubernetes отдельно троттлинг CPU (
container_cpu_cfs_throttled_periods_total), сервис упирается в лимит при низкой средней загрузке. С Go 1.25GOMAXPROCSна Linux учитывает CPU-лимит cgroup, раньше для этого ставилиautomaxprocs; - где время: трейсинг через OpenTelemetry в Jaeger или Tempo показывает, какой спан растёт: база, внешний вызов или свой код;
- рантайм Go: число горутин, паузы и частота GC (
GODEBUG=gctrace=1,go_gc_duration_seconds), аллокации; - пул соединений:
db.Stats()уdatabase/sql, поляWaitCountиWaitDurationпоказывают, что запросы ждут соединение, а не выполняются; - профилирование:
net/http/pprofиgo tool pprofна/debug/pprof/profile?seconds=30для CPU,heapиallocsдля памяти,goroutineдля утечек. Блокировки видны вblockиmutex, но их включают черезruntime.SetBlockProfileRateиruntime.SetMutexProfileFraction. Задержки планировщика и GC показываетgo tool trace.
Для постоянной картины подходит continuous profiling, например Grafana Pyroscope. Гипотезу подтверждают нагрузкой через k6 или vegeta, сравнивая метрики до и после правки.
Где спотыкаются
Сразу оптимизируют код, не доказав, что время теряется в нём, а не в базе или сети.
Снимают только CPU-профиль, когда сервис ждёт. Ожидание на I/O, мьютексе или соединении из пула в CPU-профиле не видно.
Смотрят на среднее время ответа и не замечают, что тормозит один процент запросов, например с большим телом или от конкретного клиента.