awesome-everything EN
↑ Обратно к восхождению

Производительность

От инцидента к enforcement: SLO burn до верифицированного исправления за 35 минут

Суть Полный проработанный пример: SLO burn на /checkout, диагностированный через непрерывное профилирование и распределённые трейсы, исправленный за 35 минут и защищённый enforcement gates от возврата того же класса регрессий.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min

Алерт SLO burn срабатывает в 10:47. Без непрерывного профилирования и распределённых трейсов дежурный тратит день на угадывание. С ними она находит первопричину и выпускает исправление к 11:22. Окно в 35 минут — не удача; это возврат предыдущих инвестиций в observability под давлением.

Инцидент: /checkout p99 сжигает SLO

В 10:47 срабатывает алерт: “checkout SLO p99 burn rate 14x — 12 часов error budget сожжено за 6 часов.”

Дежурный инженер открывает единый дашборд. Деплоев в последний час нет. Трафик на базовом уровне. Это не спайк — что-то изменилось в downstream-сервисе.

Шаг 1: Observe — 60 секунд

Prometheus: /checkout p99 вырос с 240 мс до 1,4 с. Начался примерно два часа назад. RPS ровный. Error rate ровный. Чистая деградация латентности.

RUM: LCP на стороне клиента не затронут. Это server-side проблема, не bundle-регрессия.

Шаг 2: Profile — 90 секунд

Pyroscope, отфильтрованный по /checkout за последние два часа:

runtime.scanobject:   22%   (базовый: 4%)
runtime.mallocgc:      9%   (базовый: 2%)
encoding/json.Marshal: 24%  (базовый: 4%)
handlers.Checkout:      6%
pgx.Query:             12%

GC-фреймы выросли с 6% до 31%. JSON Marshal вырос с 4% до 24%. Что-то производит намного больше мусора и сериализует намного большие payload, чем прежде.

Шаг 3: Classify — 60 секунд

Allocation-bound (family: GC / фрагмент 04), причём overhead сериализации указывает на необычно большой ответ, производимый, а не только обрабатываемый. Это паттерн family N+1 (фрагмент 05), применённый к межсервисным payload: что-то upstream начало возвращать bulk-данные там, где было достаточно summary.

Амдал по совокупным фреймам GC + Marshal (55%): 1 / (1 - 0,55) = 2,2x. Это снизит p99 с 1,4 с до 636 мс — всё ещё выше SLO 200 мс. Первопричина — не просто “GC горячий”; это то, что вызывает давление GC и Marshal.

Шаг 4: Корреляция трейсов — 5 минут

Открыть Tempo, отфильтровать по медленным /checkout трейсам за последние два часа. Waterfall показывает:

[span] handle_request          1820мс
  [span] auth_check               5мс
  [span] order_query             340мс   (базовый: 12мс)
  [span] inventory_check         850мс   (базовый: 80мс)
  [span] payment_call            280мс   (базовый: 90мс)
  [span] serialise_response      340мс   (базовый: 8мс)

Каждый downstream span и шаг сериализации деградировали на один и тот же множитель. Это паттерн upstream-сервиса, возвращающего ответ намного больше ожидаемого — каждый потребитель раздувается пропорционально.

Проверить историю деплоев: inventory-service выпущен в 10:31 — за 16 минут до начала SLO burn. Diff: добавлено include_full_sku_details: true в ответ /inventory. Прежде возвращались только SKU ID; теперь — полные SKU-объекты. Payload ответа: 8 КБ → 85 КБ на вызов.

Сервис /checkout получает 85 КБ, десериализует (больше аллокаций), выбирает 0,1% нужных данных, затем сериализует собственный ответ с раздутыми данными инвентаря. Все три центра затрат — GC, Marshal, downstream latency — ведут к одной причине.

СигналНаблюдениеВывод
Pyroscope GC-фреймы6% → 31%Намного больше мусора на запрос
Pyroscope json.Marshal4% → 24%Намного больший payload сериализуется
Tempo: span inventory_check80мс → 850мсUpstream-сервис намного медленнее или возвращает больше
Лог деплоев: inventory-serviceДеплой в 10:31Payload вырос с 8 КБ до 85 КБ на вызов
В совокупностиВсе деградировавшие span коррелируютЕдинственная первопричина: деплой inventory-service

Шаг 5: Fix — 15 минут

Два параллельных действия:

  1. Откатить деплой inventory-service через консоль деплоев.
  2. Добавить защитную проверку в /checkout: отклонять любой ответ инвентаря более 64 КБ с ошибкой до обработки.

Оба выпущены в течение 15 минут.

Шаг 6: Verify — 10 минут

Pyroscope после отката: scanobject возвращается к 4%, mallocgc — к 2%, json.Marshal — к 4%. Профиль на базовом уровне.

Prometheus: /checkout p99 на 235 мс в течение 5 минут после завершения отката. Burn rate SLO падает до 0,1x.

Подтверждено улучшение и локального профиля, и headline-метрики.

Шаг 7: Enforce — следующий спринт

Три enforcement-действия, принятые в следующем спринте:

А. PR gate: размер межсервисного ответа. Любой PR к любому сервису, изменяющий схему ответа, должен пройти contract test, проверяющий, что размер тела не превышает 2x текущего медианного. PR, увеличивающие ответ более чем в 2 раза, требуют явного ревью SRE.

Б. Production alert: p99 размера payload на endpoint. Добавить метрику, отслеживающую p99 байт тела ответа на downstream вызов. Алерт при росте более чем на 50% за неделю. При первом срабатывании этого класса регрессии алерт маршрутизируется к дежурному ответственной команды до сгорания SLO.

В. Запись в runbook. “Спайк p99 на /checkout с пропорциональной деградацией всех span → проверить деплои upstream за последние 2 часа на изменения схемы ответа. Проверить inventory-service в первую очередь.” Следующий дежурный решит ту же задачу менее чем за 5 минут вместо начала с нуля.

Итого от алерта до исправления: 35 минут. Итого до enforcement: один спринт (1 неделя). Инженерных часов: ответ на инцидент + postmortem + enforcement: 6 часов. Без непрерывного профилирования + трейсов: оценочно 4–8 часов только на инцидент.

Почему это работает

Шаг enforcement — это то, что отличает дисциплину от пожаротушения. Инцидент занял 35 минут. Без gate тот же класс регрессии — другой сервис с неожиданно выросшим ответом — займёт ещё 35 минут через 3–6 месяцев. С gate каждый будущий PR, изменяющий схему ответа, проверяется. Разовая стоимость добавления gate — менее 4 инженерных часов. Повторяющаяся стоимость без него — 35+ минут на инцидент, потенциально десятки раз.

Числа по циклу инцидента
Время от алерта до верифицированного исправления (с полным стеком)
35 минут
Время от алерта до первопричины (без непрерывного профилирования)
4–8 часов
Рост payload inventory-service
8 КБ → 85 КБ
Деградация p99 на /checkout
240мс → 1820мс
p99 после отката (в течение 5 мин)
235мс
Инженерных часов на добавление enforcement gates
~4 часа
Среднее количество предотвращённых инцидентов на enforcement gate
3–8 в год
Викторина

В инциденте /checkout профиль показал спайки GC и json.Marshal. Наивная реакция — исправить allocation hotspot. Почему это неверно?

Викторина

Почему шаг enforcement (добавление CI gates и записей в runbook) важнее самого исправления?

Расставь шаги по порядку

Упорядочите диагностические шаги инцидента /checkout от первого наблюдения до подтверждённой первопричины:

  1. 1 SLO алерт: p99 1,4с, RPS ровный, RUM не затронут — только server-side
  2. 2 Профиль показывает GC-фреймы 6% → 31%, json.Marshal 4% → 24%
  3. 3 Classify: allocation-bound + serialisation-bound; первопричина должна быть upstream
  4. 4 Трейс: все downstream span деградировали пропорционально — upstream bulk payload
  5. 5 Лог деплоев: inventory-service выпущен в 10:31 с полными SKU-деталями в ответе
  6. 6 Откат inventory-service; профиль и p99 возвращаются к базовому уровню в течение 5 минут
Вспомните перед уходом
  1. 01
    Объясните, как каждый из пяти observability-сигналов поспособствовал разрешению инцидента /checkout.
  2. 02
    Инцидент /checkout объединял family 04 (GC) и family 05 (N+1/bulk payload). Как кросс-family идентификация меняет стратегию исправления?
  3. 03
    Каковы три enforcement-действия после инцидента /checkout и какой класс регрессий каждое предотвращает?
Итог

Инцидент /checkout прошёл от алерта до верифицированного исправления за 35 минут, потому что пятисигнальный стек observability был на месте. Метрики назвали сервис и серьёзность. RUM исключил client-side причины. Профили показали GC и давление сериализации — два следствия одной причины. Трейсы показали пропорциональную деградацию всех downstream span, указывая на upstream-сервис. История деплоев подтвердила рост payload inventory-service с 8 КБ до 85 КБ за 16 минут до начала SLO burn. Исправление — откат плюс защитная проверка размера. Шаг enforcement — PR gate, alert на размер payload, запись в runbook — предотвращает весь класс регрессий upstream payload от превращения в инциденты в будущем. Это и отличает дисциплину от пожаротушения: разбор инцидента завершается gate, а не только исправлением.

Связанные уроки
встречается в260
Продолжить восхождение ↑Культура, экономика и масштаб performance
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.