Как обнаружить, что процесс начал занимать больше времени
Что проверяют
Есть ли у вас наблюдаемость как привычка: метрики с распределением, алерты на деградацию и понимание, как потом найти причину. Следом обычно спрашивают, как отличить медленный код от медленной зависимости, базы или внешнего API.
Как отвечать
Разделите ответ на обнаружение и поиск причины. Обнаружение:
- гистограмма, а не среднее:
prometheus.NewHistogramVecизclient_golangс меткой операции, в PromQLhistogram_quantile(0.99, sum by (le) (rate(op_duration_seconds_bucket[5m]))). Среднее прячет хвост, а деградация часто начинается именно с него; - алерт на рост: текущий p99 сравнивают с тем же временем неделю назад через
offset 1wили с порогом из SLO, правило в Prometheus, доставка через Alertmanager; - фоновые задачи: длительность каждого прогона и время последнего успешного завершения пишут в метрику, для коротких задач через Pushgateway;
- трейсинг: OpenTelemetry со спанами в Jaeger или Tempo показывает, какой участок вырос: SQL, HTTP-вызов или свой код.
Поиск причины:
- pprof:
import _ "net/http/pprof"регистрирует обработчики наDefaultServeMux,go tool pprofснимает CPU-профиль. Два профиля сравнивают флагом-baseи видят, что именно выросло; - блокировки: профили
blockиmutexпо умолчанию пустые, их включаютruntime.SetBlockProfileRateиruntime.SetMutexProfileFraction; - рантайм: число горутин, паузы GC и размер кучи есть в стандартных метриках
go_*. Рост горутин обычно означает утечку или зависшие вызовы безcontextс таймаутом; - постоянное профилирование: Grafana Pyroscope хранит историю, и профиль «до деградации» у вас уже есть.
Где спотыкаются
Берут Gauge для длительности. Он хранит последнее значение, распределение теряется, всплески между скрейпами не видны.
Ограничиваются log.Printf с time.Since. Для одного случая годится, но тренд за неделю из логов без агрегации не построить.
Открывают pprof на внешнем порту. Там видны стеки и внутренности сервиса, а снятие профиля нагружает процесс, поэтому эндпоинт держат на внутреннем порту.