Как расследовать деградацию производительности по метрикам. Пошаговый подход

8 минут чтения
Средний рейтинг статьи — 4.9

Когда пользователи начинают жаловаться на медленную работу сервиса, первое желание — сразу искать проблему в логах или перезапускать приложение. Однако такой подход редко помогает быстро найти истинную причину.

Эффективное расследование начинается с анализа метрик. Они позволяют определить, когда началась деградация, какой компонент стал узким местом и как проблема распространялась по системе.

Ниже — последовательность из восьми шагов, которая помогает локализовать источник проблемы, не перебирая серверы наугад.

Шаг 1. Подтвердите деградацию по пользовательским метрикам

Прежде чем анализировать инфраструктуру, важно понять, действительно ли ухудшилось качество обслуживания запросов.

В первую очередь стоит посмотреть четыре золотых сигнала:

  • время ответа (latency);
  • количество запросов (traffic);
  • долю ошибок (errors);
  • насыщение ресурсов (saturation).

Например, если время ответа выросло с 200 мс до 2 секунд, а доля ошибок осталась прежней, это деградация производительности, а не отказ приложения. Сценарии расследования у них разные.

Если метрик приложения под рукой нет, минимальную картину даст curl — он разложит время запроса по стадиям:

curl -o /dev/null -s -w 'dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' \
  https://example.com/api/orders

Если ttfb большой, а connect и tls в норме — проблема в обработке запроса, а не в сети или сертификатах.

Шаг 2. Сузьте область: какой сегмент трафика деградировал

Это шаг, который чаще всего пропускают. Средние значения по всему трафику прячут проблему одного эндпоинта: если медленным стал /api/report, дающий 3% запросов, общий график почти не шелохнётся, а жалобы будут.

Полезно разложить время ответа по:

  • эндпоинтам и HTTP-методам;
  • клиентам или тенантам;
  • географии и точке входа;
  • версии релиза, если выкатка была частичной;
  • статусу кэша (hit или miss).

В Prometheus это обычно один запрос:

topk(5,
  histogram_quantile(0.99,
    sum by (le, handler) (rate(http_request_duration_seconds_bucket[5m]))))

Если деградировал один сегмент — дальше нужно расследовать только его. Если все сразу — проблема ниже по стеку: в общей зависимости, ресурсах хоста или сети.

Шаг 3. Идите по цепочке запроса и найдите, что изменилось первым

После подтверждения проблемы не стоит анализировать все серверы одновременно. Лучше двигаться по маршруту запроса:

Пользователь → балансировщик → веб-сервер → приложение → база данных → внешние сервисы

На каждом этапе нужно ответить на один вопрос: что изменилось раньше остального?

Nginx помогает разделить эти этапы, если в лог добавлены тайминги:

log_format timing '$remote_addr $status $request_method $uri '
                  'rt=$request_time uct=$upstream_connect_time '
                  'uht=$upstream_header_time urt=$upstream_response_time';

Разница между $request_time и $upstream_response_time — это время, потраченное вне приложения: на чтение тела запроса и отдачу ответа клиенту. Если растёт именно она, приложение ни при чём, и смотреть надо в сторону сети и медленных клиентов.

Шаг 4. Анализируйте перцентили, а не средние значения

Среднее время ответа остаётся почти неизменным даже тогда, когда часть пользователей уже ждёт по несколько секунд.

Поэтому смотреть нужно на медиану, p95 и p99. Высокие перцентили растут раньше среднего и показывают деградацию на ранней стадии.

Практический ориентир: если p99 превышает медиану больше чем в 10 раз, у системы есть выраженный «хвост» — очередь, блокировка, пауза сборщика мусора или неудачный запрос к базе на редком наборе данных.

Отдельно стоит следить за скоростью сжигания бюджета ошибок — она отвечает на вопрос, требует ли текущая деградация немедленной реакции.

Шаг 5. Проверяйте не утилизацию ресурсов, а их насыщение

Если приложение отвечает медленно, причина не всегда в коде. Но и загрузка CPU сама по себе мало что говорит: важнее, есть ли очередь за ресурсом.

vmstat 1 5     # колонка r — процессы в очереди на CPU, b — заблокированные на I/O
sar -q 1 5     # runq-sz и load average в динамике
iostat -x 1 3  # await и %util по устройствам

Здесь важна одна деталь: load average в Linux — это не только очередь на процессор. В неё входят и процессы в состоянии непрерываемого ожидания (D-state), то есть ждущие диск или сетевую файловую систему. Поэтому высокий load average при загрузке CPU в 60% чаще указывает на проблемы с дисковой подсистемой, чем на нехватку вычислительных ресурсов.

Отдельно проверьте насыщение пулов, которые не видны в системных метриках:

  • занятость пула соединений с базой;
  • очередь задач у воркеров;
  • количество занятых worker-процессов веб-сервера;
  • лимит открытых файловых дескрипторов.

Пул, занятый больше чем на 80%, уже создаёт ожидание — даже если процессор при этом простаивает.

Шаг 6. Проверьте зависимости

Во многих приложениях время ответа зависит не столько от собственного кода, сколько от того, что происходит вокруг:

  • база данных и её блокировки;
  • кэш и процент попаданий;
  • очереди задач;
  • внешние API;
  • DNS-резолвинг.

Замедление стороннего сервиса на несколько сотен миллисекунд заметно бьёт по всему приложению, если вызовы к нему синхронные и последовательные.

Две частые причины, которые стоит проверять целенаправленно: паузы сборщика мусора и утечки соединений к базе — обе дают именно постепенную деградацию, а не резкий отказ.

Шаг 7. Постройте таймлайн и сопоставьте его с изменениями

Когда подозреваемый компонент найден, вернитесь к графикам и выпишите последовательность событий с точным временем:

13:05  вырос RPS на /api/search
13:06  p99 базы данных ушёл с 40 мс до 900 мс
13:07  пул соединений занят на 100%, появились 504
13:08  первые жалобы пользователей

Такой список сразу отделяет первопричину от последствий. Дальше его нужно сопоставить с тем, что делали с системой:

  • релизы и миграции;
  • изменения конфигурации;
  • автоматическое масштабирование;
  • изменения сетевых правил.

Совпадение по времени с изменением — самая быстрая гипотеза. И полезная привычка: сравнивать не только с «до инцидента», но и с тем же часом неделю назад, чтобы не принять обычный вечерний пик за аномалию.

Шаг 8. Убедитесь, что аномалия — причина, а не следствие

Во время инцидента легко принять симптом за источник. Рост использования памяти может быть не причиной, а результатом того, что запросы стали обрабатываться дольше и в памяти скопились незавершённые.

Перед выводами стоит проверить три вещи:

  • какая метрика изменилась первой;
  • какие события последовали за ней;
  • объясняет ли найденная аномалия остальные изменения.

Если гипотеза объясняет только часть картины — расследование не закончено.

Если внутренних метрик не хватило

Бывает, что графики в норме, а пользователи всё равно жаловались. Тогда проблема была за пределами инфраструктуры: у провайдера, на маршруте, в CDN или DNS. Здесь помогают только независимые проверки снаружи — они фиксируют время ответа и доступность так, как их видит клиент.

Отдельный случай — сбой, который закончился раньше, чем началось расследование. Про такие мы написали разбор: как определить причину кратковременного сбоя постфактум.

Частые вопросы

С каким шагом хранить метрики, чтобы расследование было возможным?

Для оперативного анализа достаточно шага 10–15 секунд с хранением 2–4 недели, дальше данные можно агрегировать до минуты или пяти. Метрики, усреднённые до 5 минут сразу, скрывают короткие всплески — а именно они чаще всего оказываются началом деградации.

Что делать, если деградация видна только у части пользователей?

Искать общий признак: регион, устройство, тариф, тенант, версия клиента. Если такой признак нашёлся, дальше расследуется только соответствующий путь запроса — например, конкретная реплика базы или один узел балансировщика.

Чем деградация отличается от инцидента?

Формально — тем, что сервис продолжает отвечать. Практически граница определяется через SLI и SLO: если целевой показатель нарушен и бюджет ошибок сжигается быстрее плана, деградацию нужно разбирать как инцидент.

Заключение

Расследование деградации строится не на поиске «подозрительного графика», а на последовательном сужении области поиска:

  1. Подтвердить проблему по пользовательским метрикам.
  2. Найти сегмент трафика, который деградировал.
  3. Пройти по цепочке запроса и найти первый изменившийся компонент.
  4. Смотреть перцентили, а не средние.
  5. Проверить насыщение ресурсов и пулов, а не только их утилизацию.
  6. Проверить зависимости.
  7. Построить таймлайн и сопоставить его с изменениями.
  8. Убедиться, что найденная аномалия объясняет всю картину.

Такой порядок экономит больше всего времени на шаге 2: чем раньше найден сегмент, в котором проблема действительно есть, тем меньше графиков придётся пересмотреть.

Опубликовано 20 июля 20268 минут чтенияДенис Коршунов
Средний рейтинг статьи — 4.9

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний