Как выявить и проанализировать медленные HTTP-запросы в Go?

Ответ

Для анализа производительности HTTP-запросов используется комбинация логирования, метрик и профилирования.

1. Идентификация с помощью Middleware

Самый простой способ — написать middleware (промежуточное ПО), которое измеряет время выполнения каждого запроса и логирует информацию о медленных.

func LoggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()

        // Создаем обертку для ResponseWriter, чтобы перехватить статус код
        rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}

        next.ServeHTTP(rw, r)

        duration := time.Since(start)

        // Логируем, если запрос выполнялся дольше заданного порога
        if duration > 500*time.Millisecond {
            log.Printf(
                "SLOW REQUEST: method=%s path=%s duration=%v status=%d",
                r.Method,
                r.URL.Path,
                duration,
                rw.statusCode,
            )
        }
    })
}

// responseWriter - обертка для http.ResponseWriter для захвата статус кода
type responseWriter struct {
    http.ResponseWriter
    statusCode int
}

func (rw *responseWriter) WriteHeader(code int) {
    rw.statusCode = code
    rw.ResponseWriter.WriteHeader(code)
}

2. Глубокий анализ причин

Когда медленный запрос найден, нужно понять, почему он медленный. Для этого используются:


  1. Профилирование (pprof): Позволяет понять, на что тратятся ресурсы CPU и памяти во время выполнения запроса. Можно обернуть обработчик в pprof.Do для сбора профиля только для конкретного запроса.



  2. Распределенная трассировка (OpenTelemetry, Jaeger): Это лучший инструмент для анализа в микросервисах. Трассировка разбивает запрос на логические части (спаны), например: HTTP-запрос -> SQL-запрос к users -> SQL-запрос к orders -> gRPC-вызов. Вы сразу увидите, какой из спанов занял больше всего времени.



  3. Метрики (Prometheus): Собирайте агрегированные данные о времени ответа (например, гистограммы или перцентили p95, p99) для каждого эндпоинта. Это помогает отслеживать общую производительность системы и выявлять деградацию после очередного релиза.


Что обычно вызывает медленные запросы?

  • Неэффективные запросы к базе данных: Отсутствие индексов, N+1 проблема.
  • Долгие вызовы внешних API: Сетевые задержки или медленная работа стороннего сервиса.
  • Сложные вычисления: Операции, интенсивно использующие CPU.
  • Большой объем данных: Обработка или передача больших JSON/XML/файлов.