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

Когда система начинает «тормозить», первое желание — подправить конфиг, добавить кэша или «дать побольше ресурсов». Иногда это помогает, но чаще превращается в серию случайных действий: сегодня стало лучше, завтра — хуже, а причина так и не найдена.
Подходы Брендана Грегга ценны тем, что дают командам не набор трюков, а воспроизводимый способ думать о производительности. Грегг много лет исследует поведение Linux и продакшен‑систем и сформулировал простые методологии (например, USE и RED), которые помогают быстро сузить круг поиска и не утонуть в метриках.
Практический бонус: когда у команды появляется единый язык и алгоритм расследований, становится проще автоматизировать рутину — от типовых дашбордов до небольших внутренних инструментов. Например, такие вещи удобно быстро собирать в TakProsto.AI: через чат‑интерфейс можно накидать веб‑панель для просмотра RED/USE сигналов, сервис для хранения «симптом → причина → фикс», или утилиту для запуска контролируемых нагрузочных проверок без долгого программирования и согласований.
В сложных системах (микросервисы, очереди, базы, сеть, виртуализация) симптом и причина редко совпадают. Медленный ответ API может быть следствием ожидания блокировок в БД, проблем с диском, нехватки сокетов, таймаутов на соседнем сервисе или неожиданных пауз из‑за сборщика мусора. Интуиция обычно опирается на прошлый опыт и «самые частые» причины, но продакшен любит редкие и комбинированные.
Методологии превращают расследование в алгоритм:
Это особенно важно в командной работе: меньше споров «мне кажется», больше проверяемых фактов.
Дальше в статье эти слова будут опорными: USE помогает быстро проверить ресурсы, RED — сфокусироваться на качестве сервиса для пользователя.
Задержка — это не «сколько обычно», а «что чувствует пользователь в худшие моменты». Среднее значение легко сделать красивым: достаточно, чтобы большинство запросов проходили быстро. Но именно редкие медленные запросы ломают опыт: страница «подвисла», оплата не прошла, поиск думает вечность.
Начинайте с определения метрики.
SLI — конкретное измерение, например: «время ответа /api/search». SLO — цель по этому SLI: «p95 < 300 мс». SLA — внешнее обязательство с последствиями.
Важно, чтобы SLI отражал реальный путь пользователя: не только серверное время, но и то, что влияет на итог (очереди, зависимости, холодные кэши).
p50 (медиана) отвечает на вопрос «как у половины запросов». p95/p99 — «как у самых медленных 5%/1%». Именно эти «хвосты» чаще всего создают жалобы и всплески ошибок.
Пример: p50 = 40 мс, p99 = 2 с. Формально «в среднем быстро», а фактически каждый сотый запрос — заметная боль.
Полезно думать о задержке как о сумме:
Эта модель помогает перестать спорить «CPU или база?» и начать измерять вклад каждого компонента.
Если сервис интерактивный (UI, поиск, платежи), стабильность p95/p99 часто важнее максимального throughput: лучше чуть меньше запросов в секунду, но без секундных провалов.
Если задача пакетная (ETL, фоновые джобы), throughput может быть приоритетом, а хвосты допустимы — пока они не создают очереди, влияющие на другие компоненты.
Метод USE (Utilization, Saturation, Errors) — это способ быстро «пробежать глазами» по базовым ресурсам системы и понять, где именно искать проблему производительности. Он хорош тем, что не требует догадок и не заставляет сразу прыгать в глубокое профилирование: сначала — короткая инвентаризация, потом — точечная работа.
Utilization (Утилизация) — насколько ресурс занят полезной работой.
Saturation (Насыщение) — есть ли очередь/ожидание из‑за нехватки ресурса (даже если средняя утилизация невысокая).
Errors (Ошибки) — происходят ли сбои, ретраи, дропы, коррекция ошибок, которые «съедают» время и пропускную способность.
Базовый набор почти всегда одинаковый: CPU, память, диск/хранилище, сеть и очереди (планировщик, очереди I/O, очереди в приложении/брокере, пул соединений и т.п.). В USE важно помнить: очереди — это отдельный объект наблюдения, а не «где‑то внутри».
Для каждого ресурса задайте короткие вопросы:
Вместо «смотрим всё сразу» вы получаете карту: где есть насыщение или ошибки — туда и идём дальше. Часто достаточно найти одну доминирующую очередь (например, очередь диска или пул соединений), чтобы сузить расследование до 1–2 подсистем и уже там применять более детальные методы и инструменты.
Метод RED — это практичный способ смотреть на сервис так, как его «видит» пользователь. Вместо того чтобы тонуть в десятках системных метрик, мы фиксируем три сигнала, которые почти всегда объясняют, почему клиент доволен или раздражён: Rate, Errors, Duration.
RED идеально ложится на сервисы и API, где есть чёткая операция «запрос → ответ». Но он не менее полезен для фоновых воркеров и конвейеров задач, если корректно определить «операцию» (например, обработка одного джоба).
Для HTTP/gRPC:
Для очередей задач:
RED помогает быстро ответить на главный вопрос: мы медленные из‑за нагрузки, ошибок или длительности? Это напрямую переводится в SLO: например, «p95 Duration < 300 мс при Errors < 0,5%». Если Rate растёт и одновременно ухудшается Duration — вероятна перегрузка или блокировки. Если Errors растут без изменения Rate — ищите деградацию зависимости, конфигурации или релиза. Такой треугольник сигналов упрощает алерты и делает разборы инцидентов предметными.
Когда «что-то тормозит», самая частая ошибка — сразу хвататься за любимый инструмент и надеяться, что график сам подскажет ответ. Подход Грегга дисциплинирует: сначала выбираем режим расследования, затем ставим проверяемые гипотезы и двигаемся маленькими шагами.
USE — это быстрый скрининг ресурсов: CPU, память, диски, сеть. Он отвечает на вопрос: «Есть ли явная перегрузка или конкуренция за ресурс, которая объясняет симптом?» Это удобно, когда система «задыхается» целиком или вы не уверены, где искать.
RED — это взгляд со стороны сервиса: Rate (поток запросов), Errors (ошибки), Duration (длительность). Он отвечает на вопрос: «Что именно видит пользователь и на каком участке сервиса становится хуже?» RED особенно полезен при локальных деградациях, когда ресурсов вроде бы хватает.
На практике удобно стартовать с RED (симптом в терминах сервиса), а затем переходить к USE, чтобы подтвердить ресурсную причину. Или наоборот — если тревога пришла по CPU/IO.
Хорошая гипотеза звучит так: «Рост p99 Duration вызван ожиданием диска на узле X; если это так, то при пике увеличатся iowait и очередь диска, а на другом узле без очереди p99 будет нормальным». Здесь есть измеримые признаки и условия, при которых гипотеза рухнет.
Меняйте один фактор и фиксируйте эффект: один флаг, один лимит, один узел, один тип нагрузки. Иначе вы получите улучшение (или ухудшение), но не узнаете, что именно его вызвало — и не сможете повторить результат в следующий инцидент.
Профайлер — не «волшебная кнопка ускорить», а способ честно ответить на вопрос, куда уходит время (и ресурсы). Важно не путать его с трассировкой и логированием: это разные инструменты для разных задач.
Профилирование показывает статистическую картину: какие функции/стеки чаще всего «держат» CPU, где чаще происходят аллокации, какие блокировки тормозят. Оно отлично отвечает на «почему медленно?» через распределение затрат.
Трассировка (tracing) показывает путь конкретного запроса: где именно он задержался по таймлайну. Она особенно полезна для «где теряем время в конкретной операции?» и для понимания взаимодействия сервисов.
Логи фиксируют события и контекст. Они полезны для диагностики ошибок и редких сценариев, но для задержек часто дают слишком шумную и неполную картину.
Сэмплинг снимает «срезы» стека с заданной частотой: обычно достаточно точен, дешевле по накладным расходам и безопаснее для продакшена.
Инструментирование добавляет измерения в конкретные точки (функции/события): точнее для выбранных участков, но дороже, рискованнее и требует дисциплины (чтобы не превратить сервис в генератор телеметрии).
Если вопрос звучит как «почему медленно?» — начните с on-CPU и/или heap‑профиля (сэмплинг). Если вопрос «где теряем время ожидания?» — нужен off‑CPU или lock/contention‑профиль. А когда важно разложить задержку по этапам конкретного запроса — подключайте трассировку и сверяйте её выводы с профилем, чтобы не гадать.
Flame graph (пламенный граф) — это способ быстро увидеть, где именно процесс тратит CPU‑время. Он помогает перестать спорить «кажется, тормозит база» и перейти к конкретным функциям и путям исполнения.
Он показывает распределение CPU‑сэмплов по стекам вызовов: какие цепочки функций чаще всего оказываются «на горячем пути».
Но он не отвечает на вопрос «почему запрос медленный», если задержка уходит в ожидание: блокировки, I/O, сеть, планировщик, очереди. В таких случаях CPU‑flame graph может выглядеть «спокойным», хотя пользователи страдают — это просто другой класс проблем.
Инлайнинг может «спрятать» логические функции, и граф покажет родителя вместо ожидаемого виновника.
Если нет символов (или неправильные), вы увидите безликие адреса — выводы будут шаткими.
Важны и агрегации: иногда разные пути сливаются в один блок и создают иллюзию «одного узкого места».
И наконец, короткие всплески: если проблема длится секунды, а вы собирали профиль минуту, пик растворится в среднем — нужен правильный интервал и точка измерения.
Соберите flame graph в момент симптома.
Сравните «до/после» изменения (или «плохой/хороший» период) — ищите изменившиеся широкие участки.
Сформулируйте гипотезу («эта функция съедает CPU из‑за X») и подтвердите её отдельным измерением: метрикой, логом, тестом нагрузки или повторным профилированием. Это дисциплина, которая экономит дни споров и случайных оптимизаций.
Иногда графики выглядят «спокойно»: CPU занят на 20–30%, памяти хватает, ошибок нет — а пользователи жалуются на тормоза. Это классическая ситуация «нагрузка есть — а CPU не занят»: процесс не считает, а ждёт. И именно ожидания часто формируют хвосты задержки.
Off‑CPU время — это всё, что происходит, когда поток не выполняется на процессоре. Причины обычно приземлённые:
Сфокусируйтесь на трёх местах, где «прячется» время:
Диск/файловая система: latency и очереди I/O, время в iowait, частые sync/fsync.
Сеть: RTT, потери, retransmits, очередь сокета, задержки на стороне зависимостей.
Scheduler: рост runnable threads, длительные задержки планирования (scheduling latency), пики load average при низком CPU.
Полезно видеть две составляющие в одной картине:
Ожидание нужно «приземлить» до конкретного места:
Тогда вместо абстрактного «медленно» появляется конкретная цель: например, блокировка вокруг кэша, исчерпанный пул соединений или медленный DNS/диск.
eBPF полезен, когда обычные метрики и логи показывают «что-то не так», но не отвечают на вопрос «где именно теряется время». Его ценность — в доступе к системным событиям (планировщик, системные вызовы, сеть, блокировки) с очень низким overhead при правильной настройке. То есть вы можете наблюдать «на уровне ядра», не превращая диагностику в отдельную нагрузку.
Сетевые задержки. Можно измерять время на этапах TCP/UDP, очереди в стеке, ретрансляции, задержки при accept/connect и увидеть, где именно образуется хвост.
Системные вызовы и I/O. eBPF помогает понять, какие syscalls «виснут», сколько времени уходит на чтение/запись, fsync, работу с диском или сетевым хранилищем.
Contention и ожидания. Когда CPU «не занят», но запросы медленные, часто причина — ожидание: блокировки, очереди, конкуренция за ресурсы. eBPF умеет подсветить эти точки, включая off‑CPU время.
Начинайте как с хирургического инструмента, а не как с постоянного мониторинга:
Важно также учесть права доступа (capabilities), версии ядра и стандартизировать запуск через понятные процедуры, чтобы диагностика была повторяемой.
Если проблема очевидна на уровне приложения (например, медленный запрос к базе виден в APM), или узкое место хорошо ловится метриками (CPU%, iowait, ошибки, saturation) и профилями приложения — eBPF может быть лишним. Используйте его, когда требуется доказательная детализация «почему хвост растёт» и где именно система ждёт.
Продакшен — лучшее место, чтобы увидеть реальную задержку и реальные «хвосты», но и самое рискованное. Хорошая диагностика здесь должна быть управляемой: заранее ограниченной по времени и объёму, безопасной для пользователей и повторяемой, чтобы результату можно было доверять.
Перед тем как запускать профилирование или точечный сбор, договоритесь о базовых правилах:
Так вы контролируете стоимость (CPU, I/O, объём логов) и снижаете шанс случайно ухудшить SLO.
Самая частая ошибка — собирать «всё на всякий случай». Двигайтесь от гипотезы:
Минимальный набор данных должен отвечать на вопрос: подтверждаем или опровергаем гипотезу? Если нет — сбор лишний.
Чтобы результат можно было повторить и проверить, фиксируйте в одном шаблоне:
симптом → данные → причина → фикс → эффект.
Важно хранить не только графики, но и условия эксперимента: время, выборка, версии, лимиты, команды/параметры. Тогда следующий инженер сможет воспроизвести и убедиться, что улучшение не случайность.
Диагностика не должна превращаться в утечку: не тяните персональные данные в логи/трейсы/профили. Если без payload не обойтись — маскируйте, агрегируйте, сокращайте срок хранения и ограничивайте доступ. Это дешевле, безопаснее и дисциплинирует процесс.
Ниже — три ситуации, в которых подход Грегга хорошо «приземляется» на реальные инциденты. Идея одна: сначала быстро описываем проблему языком RED (со стороны сервиса), затем проверяем «железо и ОС» языком USE (со стороны ресурсов), и только потом углубляемся профилированием.
Симптом: среднее время ответа почти не меняется, но p99 (или p95) растёт — пользователи жалуются «иногда очень долго».
Что собрать по RED:
Что проверить по USE:
Чем подтвердить: сверить хвосты по трассировкам/спанам и наложить на моменты насыщения ресурсов. Если p99 растёт только на одной ноде — это почти всегда указатель на локальную проблему (соседние noisy workloads, деградация диска, сетевые потери).
Симптом: после выкладки деградировали почти все запросы, графики выглядят «приподнятыми» целиком.
Что собрать по RED:
Что проверить по USE:
Чем подтвердить: дифф профилей (до/после) и дифф ключевых счётчиков (например, QPS к БД, количество сериализаций, количество обращений к внешнему API). Если деградация линейна относительно нагрузки — чаще ищите «дорогую» операцию на запрос; если скачкообразна — ищите блокировки/очереди.
Симптом: раз в N минут сервис «подвисает», потом возвращается в норму. Средние значения мало что показывают.
Что собрать по RED:
Что проверить по USE:
Чем подтвердить: сопоставить пики задержки с событиями рантайма (паузы GC), ожиданием I/O или ожиданием блокировок. Практический маркер: если CPU низкий, но p99 высокий — часто виноваты ожидания (I/O, локи, сеть), а не «нехватка процессора».
Методологии Грегга работают лучше всего, когда становятся «скучной нормой»: любой инженер знает, какие графики открыть, какие вопросы задать и какие данные собрать — без героизма и охоты за случайными метриками.
Закрепите единый «порядок действий» для типовых ситуаций: рост задержки, деградация конкретного сервиса, периодические пики. Важно, чтобы USE/RED и профилирование были не отдельной экспертизой одного человека, а шагами в командном чек‑листе.
Практики, которые обычно приживаются:
Минимальный набор лучше, чем «стена графиков». Для старта держите два слоя:
Пользовательский слой (RED): RPS/трафик, доля ошибок, перцентили задержки (p95/p99) по ключевым эндпоинтам или операциям.
Ресурсный слой (USE): CPU, память, диск, сеть — но с акцентом на насыщение и очереди/ожидания, а не на средние значения.
Алерты делайте «редкими, но точными»: триггер на устойчивый рост p95/p99 + подтверждение ростом ошибок или очередей. Иначе команда быстро перестанет им доверять.
Если не хватает времени на инфраструктуру вокруг наблюдаемости (внутренние панели, небольшие админки, сервисы для заметок по инцидентам), имеет смысл разгрузить команду за счёт быстрых инструментов. В TakProsto.AI, например, такие прикладные вещи можно собрать через чат: веб‑интерфейс на React, бэкенд на Go и PostgreSQL, с возможностью развернуть, подключить домен, а при неудачных изменениях — откатиться через снапшоты и rollback. Это не заменяет APM, но помогает закрывать «пустоты» между процессом и практикой.
После любого заметного инцидента проведите 20–30 минут:
Главная цель — сделать следующий разбор быстрее, а не написать «идеальный отчёт».
По мере усложнения системы добавляйте слои: распределённую трассировку для критичных путей, регулярные профили (в том числе off‑CPU), затем аккуратное использование eBPF в продакшене. Важно внедрять по одному улучшению за раз и проверять, что оно реально сокращает время до нахождения причины, а не просто увеличивает объём данных.
Методологии дают воспроизводимый алгоритм расследования вместо серии «подкрутим и посмотрим». Они помогают:
Среднее прячет редкие, но болезненные «хвосты». Для пользовательского опыта чаще критичны p95/p99:
Практика: алертить и оптимизировать в первую очередь перцентили на критичных ручках/операциях, а не только среднее.
Зафиксируйте:
/api/search);Важно, чтобы SLI соответствовал реальному пути пользователя: учтите очереди, зависимости, холодные кэши и таймауты.
Думайте о задержке как о сумме:
Дальше измеряйте вклад каждой части: wall time vs CPU time, очереди/пулы, latency диска/сети.
USE — это быстрый скрининг ресурсов по трём вопросам к каждому ресурсу:
Проверяйте CPU, память, диск, сеть и очереди/лимиты (они часто и есть узкое место).
RED фокусируется на том, что «видит» клиент:
Это удобно для API/сервисов, чтобы быстро понять: проблема в росте нагрузки, ошибках или времени выполнения.
Обычно начинайте с RED, чтобы описать симптом в терминах сервиса (что ухудшилось и где). Затем переходите к USE, чтобы проверить ресурсную причину (насыщение/очереди/ошибки).
Если алерт пришёл по ресурсу (CPU/IO), можно сделать наоборот: USE → затем RED для оценки влияния на пользователей.
CPU-flame graph показывает распределение CPU-сэмплов по стекам вызовов:
Он не объяснит задержки, если сервис в основном ждёт (I/O, локи, сеть). Тогда нужны off-CPU/lock-профили и метрики очередей.
Когда CPU невысокий, а p99 растёт, часто виноваты ожидания:
Практика: сравните wall time и CPU time, посмотрите очереди/пулы, снимите off-CPU/lock-профиль в момент симптома.
Используйте eBPF как «хирургический» инструмент:
Если проблему уже хорошо видно в APM/метриках/профиле приложения, eBPF может быть излишним.