Как понять, что запрос тормозит?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Анализ производительности HTTP-запросов в Go
Понимание того, что запрос "тормозит", требует системного подхода к мониторингу и диагностике. Вот ключевые методы и инструменты:
1. Мониторинг метрик времени ответа
Установите пороговые значения для latency (задержки) и отслеживайте их через метрики:
import (
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
)
var requestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Duration of HTTP requests",
Buckets: []float64{0.1, 0.5, di.1, 2.0, 5.0},
},
[]string{"path", "method"},
)
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
duration := time.Since(start).Seconds()
// Если запрос длится > 1 секунды - потенциальная проблема
if duration > 1.0 {
log.Printf("SLOW REQUEST: %s %s took %.2fs",
r.Method, r.URL.Path, duration)
}
requestDuration.WithLabelValues(r.URL.Path, r.Method).Observe(duration)
})
}
2. Инструменты профилирования
Используйте встроенные инструменты Go для pprof:
# 1. Добавьте импорт pprof
import _ "net/http/pprof"
# 2. Запустите сервер отладки
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=10
# 3. Анализируйте flamegraph для CPU
go tool pprof -http=:8080 profile.out
3. Трассировка (Tracing)
Для распределенных систем используйте OpenTelemetry:
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
)
func handleRequest(ctx context.Context) {
tracer := otel.Tracer("myservice")
ctx, span := tracer.Start(ctx, "slow-operation")
defer span.End()
// Если span длится слишком долго, это видно в Jaeger/ tempo
time.Sleep(2 * time.Second) // Симуляция медленной операции
}
4. Анализ логов с временными метками
Структурированное логирование с context deadline:
func handlerWithTimeout(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
defer cancel()
done := make(chan bool)
go func() {
// Долгая операция
time.Sleep(4 * time.Second)
done <- true
}()
select {
case <-ctx.Done():
log.Printf("REQUEST TIMEOUT: %s - превышен лимит 3 секунды", r.URL.Path)
http.Error(w, "Timeout", http.StatusGatewayTimeout)
case <-done:
w.Write([]byte("OK"))
}
}
5. Практические индикаторы "тормозов"
Ключевые признаки медленных запросов:
- Перцентили P95/P99 значительно выше среднего
- Рост ошибок типа
context.DeadlineExceeded - Увеличение queue time в балансировщиках нагрузки
- Ступенчатый рост response time при увеличении нагрузки
- Разница между server-side и client-side timing
6. Проактивные проверки
Реализуйте health checks и canary deployments:
// Health check с проверкой зависимостей
func healthHandler(w http.ResponseWriter, r *http.Request) {
checks := map[string]func() error{
"database": checkDatabaseLatency,
"cache": checkRedisPing,
"external_api": checkExternalService,
}
for name, check := range checks {
if err := check(); err != nil {
log.Printf("HEALTH CHECK FAILED: %s - %v", name, err)
http.Error(w, "Service degraded", http.StatusServiceUnavailable)
return
}
}
}
7. Инструменты мониторинга
Настройте алертинг в системах:
- Prometheus + AlertManager для перцентилей
- Grafana dashboards с историческими данными
- APM системы (DataDog, NewRelic) для автоинструментации
Рекомендации по пороговым значениям
- Критично: > 3 секунд для API
- Предупреждение: > 1 секунды для внутренних сервисов
- Цели SLA: P95 < 500ms для пользовательских endpoints
Важно: "Тормозит" - понятие относительное. Определите бизнес.требования (SLA/SLO) и настройте мониторинг соответственно. Медленный запрос в 2 секунды может быть нормой для отчетного сервиса, но катастрофой для платежного шлюза.
Используйте комбинацию метрик + трассировка + логирование для триангуляции проблем. Часто "тормоза" вызваны не кодом приложения, а сетевыми задержками, блокирующими I/O операциями или конкурентным доступом к ресурсам.