Перейти к содержимому

Systematic Troubleshooting

«Сервис лежит, что-то делаем» — режим, в котором команда два часа подряд меняет конфиги, рестартует поды и откатывает feature flags, пока в какой-то момент оно не «починилось само». Через неделю повторяется то же самое. Никто ведь не знает, что именно сработало в прошлый раз. Systematic Troubleshooting — это дисциплина разбора неизвестной поломки: формулируем гипотезу, выбираем измерение, которое её подтвердит или опровергнет, фиксируем результат, идём дальше. Без такой дисциплины опыт не накапливается даже у сильных инженеров — «починил наугад» не оставляет следа в голове. Этот лист про методологию (USE, RED, четыре золотых сигнала, работа от гипотезы, деление пополам, таймер на проверку), а не про конкретные инструменты.

Граница: Incident Responseкоординация разбора (роли, сводки, war room); здесь — как именно копать внутри своей роли. Performance & Profiling — разбор симптома «медленно» через профиль и flame graph; здесь — общая методология для любого симптома: медленно, падает, не подключается, теряет данные. Blameless Postmortem — разбор после; здесь — во время. Runbooks — что делать по известному алерту; здесь — что делать, когда runbook не помог или сценария нет вовсе.

Главный навык на уровне L4 — держать одну гипотезу за раз и ставить таймер на её проверку. По моим наблюдениям, типовая ошибка инцидента — менять три вещи одновременно «чтобы быстрее», а потом не знать, что из этого помогло, а что сломало. Опытный инженер отличается тем, что проговаривает вслух: «гипотеза — падает резолвер в kube-dns; проверяю запросом из соседнего пода; десять минут; не подтвердится — переключаюсь на ingress». Это не философия, а конкретная привычка говорить, и она видна прямо в переписке инцидентного канала.

L3

  • Различает симптом и причину: «клиенты получают 502» — симптом; «пул к вышестоящему сервису исчерпан» — следствие; «шторм повторов от соседа» — причина. Не путает «что я вижу» с «почему это происходит».
  • Применяет деление пополам: в цепочке клиент → балансировщик → ingress → приложение → база проверяет середину — участок «приложение — база», — чтобы одним шагом отсечь половину цепочки. Не идёт линейно от клиента.
  • Записывает каждую проверку в журнал инцидента со временем: что проверил, что увидел. Чтобы IC и сменщик видели, куда уже копали.

L4

  • Применяет четыре золотых сигнала (задержка, трафик, ошибки, насыщение) и RED (поток, ошибки, длительность) на уровне приложения, USE (загрузка, насыщение, ошибки) на уровне ресурса — первым проходом, ещё до чтения кода. По моим наблюдениям, бо́льшая часть ситуаций «непонятно что» снимается этим проходом за пять минут.
  • Формулирует гипотезу до измерения, а не наоборот: «думаю, что X, потому что Y; проверяю через Z». Если измерение не отвергает и не подтверждает гипотезу — оно бесполезно, надо менять.
  • Ставит таймер на каждую гипотезу, пятнадцать-тридцать минут. Не подтвердилась — следующая, а не «ещё чуть-чуть покопаю».
  • Не меняет два параметра сразу. Если нужно откатить фичу и перезапустить под — сначала одно, потом другое; иначе непонятно, что помогло.

L5

  • Различает простые, сложные, запутанные и хаотические ситуации по Cynefin (Dave Snowden). Простая — отработать runbook; сложная — привлечь эксперта; запутанная — несколько безопасных к провалу проб параллельно; хаотическая — любое действие, чтобы выйти из хаоса. Путаница между категориями — частая ошибка даже у опытных: копаться там, где сработает runbook, или гонять runbook по системе, которая давно вне его сценария.
  • Снимает снимок состояния до гашения: дамп кучи, дамп горутин, kubectl describe, выгрузка свежих метрик, dmesg. Перезапуск, добавление реплик и переключение часто уничтожают улики; опытный инженер помнит снять снимок заранее. Без него постмортем превращается в «не воспроизвели».
  • Помнит про базовые вероятности: слышишь топот — думай про лошадей, а не про зебр. Свежий деплой полчаса назад — начинать с него, а не с теории про космические лучи. Я регулярно вижу разборы, где гипотеза «сложное и новое» побеждает гипотезу «свежий коммит» только потому, что вторая скучная.
  • Различает триггер и причину: «деплой X сломал» — триггер; «у нас нет постепенной выкатки, поэтому любой плохой деплой сразу оказывается в проде» — причина. Постмортем по триггеру даёт «не делайте таких коммитов», постмортем по причине — системную меру.

L6+

  • Строит культуру разбора в команде: журнал инцидента как обязательный артефакт, структурированная передача смены, разбор после инцидента с вопросом «как мы копали», а не только «что чинили». Учит методу, а не починке конкретного бага.
  • Связывает разбор с базой постмортемов: видит повторяющиеся сюжеты между инцидентами (третий раз задержки в хвосте после деплоя — значит, нужна канарейка), а не считает каждый инцидент уникальным.
  • Поднимает Game Day и «колесо неудач» как тренировку: учебный инцидент отрабатывает методологию без риска для прода.
  • David J. Agans — Debugging: The 9 Indispensable Rules for Finding Even the Most Elusive Software and Hardware Problems (AMACOM, 2002). Каноническая короткая книга про методологию: понять систему, воспроизвести отказ, перестать думать и посмотреть, делить пополам, менять по одному, вести журнал, проверить, воткнута ли вилка, позвать свежий взгляд, убедиться, что действительно починил. Если выбирать одну — эту. Я регулярно ловлю себя на нарушении одного из правил прямо во время инцидента.
  • Betsy Beyer et al. — Site Reliability Engineering, глава 12 «Effective Troubleshooting» (O’Reilly, 2016). Разбор от Google: разделение симптома, причины и триггера, работа от гипотезы, чек-листы. Доступна онлайн бесплатно.
  • Brendan Gregg — Systems Performance: Enterprise and the Cloud (Addison-Wesley, 2-е изд., 2020). Метод USE описан здесь подробно, плюс конкретные методики для процессора, памяти, диска и сети. Пересекается с Performance & Profiling, но методологическая часть применима шире.
  • Sidney Dekker — The Field Guide to Understanding «Human Error» (CRC Press, 3-е изд., 2014). Не про отладку, но фундамент: почему «человек ошибся» — это симптом, а не причина, и почему разбор не должен останавливаться на «забыл --dry-run».
  • Brian Kernighan, Rob Pike — The Practice of Programming (Addison-Wesley, 1999). Глава про отладку — короткая, но классическая: как читать стек, как искать делением пополам в коде и почему «скорее всего, сломали недавние изменения» — разумная гипотеза по умолчанию.
  • John Allspaw — Trade-Offs Under Pressure: Heuristics and Observations of Teams Resolving Internet Service Outages (магистерская работа, Lund University, 2015). Полевое исследование того, как опытные инженеры разбирают инциденты в проде. Длинно, но если цель — вырастить у себя L5, читать обязательно.
  • Brendan Gregg — The USE Method. Один экран, один метод, применим к любой системе. Каноника.
  • Tom Wilkie — The RED Method: Key Metrics for Microservices Architecture (Weaveworks, 2018). Аналог USE на уровне приложения: поток, ошибки, длительность. По моим наблюдениям, RED — самый частый первый дашборд для нового сервиса.
  • Richard I. Cook — How Complex Systems Fail (1998, восемнадцать пунктов). Не про отладку напрямую, но задаёт фон: «корневая причина» — языковой конструкт, а не объективная категория. Это меняет то, как формулируются выводы.
  • Charity Majors — Observability — A 3-Year Retrospective (2020). Почему мониторинг известных проблем через дашборды — не то же самое, что разбор неизвестных через данные высокой кардинальности. Ровно эта граница и отделяет «есть runbook» от «нужен систематический разбор».
  • Dave Snowden — A Leader’s Framework for Decision Making (HBR, 2007). Cynefin для неакадемической аудитории, восемь страниц.

Этот лист про методологию, инструменты живут в соседних (Networking, Operating Systems, Shell & CLI Craft, Performance & Profiling). Но три штуки относятся к самому процессу разбора:

  • Журнал инцидента в общем документе, в холсте Slack или в выделенном канале — текстовая хроника с отметкой времени на каждой проверке. Это одновременно фиксация состояния, материал для передачи смены и сырьё для постмортема. Без него постмортем превращается в «вроде что-то делали».
  • Доска гипотез (маркерная доска, Miro или простой файл с чек-листом) — список гипотез с пометками «подтверждена», «опровергнута», «не проверяли». По моим наблюдениям, физически выписанный список спасает от типовой ошибки «прыгаем между тремя гипотезами и ни одну не закрываем».
  • Чек-листы методик — USE, RED и золотые сигналы под рукой: распечатка, страница в вики, закладка в Slack. Идея не в том, чтобы вспоминать в стрессе, что мерить, а в том, чтобы пробежать готовый список.
  • Анти-инструмент: «крутим конфиги наугад без гипотезы». Не инструмент, а антипаттерн. Самый частый источник историй «починили, но не знаем чем».

Главный публичный кейс — исследование Allspaw на материале Etsy. Сначала как технический директор Etsy, потом в Adaptive Capacity Labs, John Allspaw задокументировал: опытные инженеры во время инцидентов не «знают ответ» — они быстрее остальных формулируют рабочую гипотезу, быстрее её опровергают и переходят к следующей. Это не интуиция и не «больше опыта», а конкретная привычка проговаривать, и она тренируется. «Колесо неудач» в Google (см. SRE Book) — институционализированная форма такой тренировки: новичок получает учебный инцидент, опытный играет роль системы и отвечает на вопросы. Тренируется тут методология, а не знание конкретного бага.

Из этого вырастают четыре правила, которые я считаю базовыми. Гипотеза идёт до измерения: если не получается сформулировать, что именно подтвердит или опровергнет очередная команда, — не набирайте её. «Посмотрю логи» — не гипотеза. Меняется одно за раз, потому что одновременный откат вместе с перезапуском и переключением флага честно приводит к «починилось, не знаем чем».

Третье правило дороже всего стоит, когда его нарушают. Снимок состояния снимается до гашения: дамп кучи, свежие метрики, kubectl describe, dmesg — всё до того, как перезапуск сотрёт следы. Тридцать секунд сейчас экономят неделю разговоров «не воспроизвели». И последнее — таймер. По пятнадцать-тридцать минут на гипотезу, дальше следующая; без таймера полчаса незаметно превращаются в два часа в кроличьей норе.

Симптом, причина и триггер — три разных вопроса. Симптом — то, что видит клиент или дашборд: «502 от ingress», «p99 вырос до восьми секунд», «отставание потребителя Kafka растёт». Причина — почему так происходит на уровне системы: «ingress ловит таймаут, потому что в приложении кончился пул, потому что база держит блокировки». Триггер — что в этот раз запустило цепочку: «деплой полчаса назад добавил запрос в цикле». Я регулярно вижу разборы, где IC останавливается на триггере, а команда теряет причину — «у нас нет канареечной выкатки, поэтому любой плохой деплой сразу падает в прод». Разбор по триггеру даёт правило «не делайте таких коммитов», разбор по причине даёт системное изменение. См. Blameless Postmortem.

Деление пополам важнее линейного обхода. В цепочке клиент → CDN → балансировщик → ingress → приложение → кеш → база инстинкт велит идти от клиента: проверить DNS, потом TLS, потом балансировщик. За шаг исключается один компонент. Деление пополам — проверить участок «приложение — база» напрямую: за один шаг ровно половина цепочки либо здорова, либо нет. Топология неважна. Стек неважен. Размер системы тоже, и именно поэтому приём переносится с монолита на десяток сервисов без единой поправки, а разница в скорости разбора, по моим наблюдениям, кратная.

USE, RED и золотые сигналы дополняют друг друга, а не конкурируют. Это просто разные уровни. USE (Brendan Gregg) — про ресурсы: для процессора, памяти, диска и сети смотрим загрузку, насыщение и ошибки. RED (Tom Wilkie) — про сервисы и их ручки: поток, ошибки, длительность. Четыре золотых сигнала из SRE Book — синтез: задержка, трафик, ошибки, насыщение. Я регулярно вижу, как команда берёт один метод и считает, что этого достаточно. На деле USE говорит «диск в полке», RED — «вот эти ручки деградировали в этот период», золотые сигналы — «сведи одно с другим и сравни с SLO».

Не доверяй ощущению «тут всё работало, проверять не надо». Allspaw зафиксировал у опытных инженеров любопытный приём: они специально перепроверяют то, что считают исправным. «Я уверен, что с балансировщиком порядок — значит, проверю его первым». Это контринтуитивно: тратишь время на заведомо здоровое. Зато снимает слепое пятно. По моим наблюдениям, «непонятно почему» часто прячется именно в компоненте, который никто не смотрит, потому что «он же работает».

Починил — проверь, что действительно починил. Главное правило Агенса: не убедился — значит, не починил. После гашения идёт проверка: воспроизвести исходный симптом, если это безопасно, увидеть, что SLI вернулся к норме, убедиться, что не вылезли вторичные ошибки. Я регулярно вижу инциденты, которые закрыли, а через двадцать минут открыли снова: гашение замаскировало симптом, но не тронуло причину.

Проговорить свою модель вслух — бесплатный приём, которым мало кто пользуется. Вслух или письменно в журнал опишите, как, по-вашему, устроен путь запроса: идёт через X, потом Y, потом Z. Часто на середине фразы выясняется, что модель разошлась с реальностью — Z выпилили полгода назад, и никто этого не помнит. Опытные так делают, начинающие стесняются.

Не всякая поломка — отладка. Если runbook уже есть, ситуация простая: отработать сценарий и не тратить время на «понять». Если знает эксперт — позвать эксперта, а не изобретать. Если не понимает никто и система ведёт себя нелинейно, работает другой режим: несколько безопасных проб параллельно — канарейка с одним флагом, минимальный откат, добавление реплик. А если всё горит и думать некогда, сначала любое действие, лишь бы выйти из хаоса. Ошибаются в обе стороны и опытные тоже: начинают исследовать там, где есть готовый сценарий, или гоняют сценарий по системе, которая давно за его пределами.

  • Incident Response — координация во время инцидента (роли IC, оператора, коммуникации); здесь — методология, которую применяет тот, кто копает.
  • Blameless Postmortem — разбор после; разделение симптома, причины и триггера там и здесь одно и то же.
  • Runbooks — готовый сценарий по известному алерту; систематический разбор начинается там, где сценарий не помог или его нет.
  • Performance & Profiling — разбор «медленно» через flame graph и профиль; здесь — общая методология для любого симптома.
  • Networking — сетевая диагностика как поддомен; tcpdump, mtr, dig — инструменты, методология применения та же.
  • Operating Systems — то, что снимают до гашения на уровне системы: dmesg, /proc, данные eBPF.
  • SLI-based Alerting / Symptom vs Cause Alerting — алерт сообщает симптом; задача разбора — пройти от симптома к причине.
  • Game Day — тренировка методологии на учебном инциденте, без риска для прода.
  • Postmortem Database — узнавание повторяющихся сюжетов; на уровне L6 разбор опирается на историю, а не только на «здесь и сейчас».

Три темы просятся в отдельные листья. Разбор в распределённых системах (TBD) — трассировка как инструмент, частичные отказы, обнаружение расщепления кластера, восстановление причинно-следственной цепочки между сервисами. Сбор состояния до гашения (TBD) — что именно снимать: дампы кучи, горутин и потоков, снимки eBPF, логи до ротации; сейчас это один пункт в L5, а материала там на целый лист. Когнитивные искажения при разборе (TBD) — привязка к первой версии, перевес свежих событий, поиск подтверждений — и как ловить это в коллеге и в себе.

Чего я не знаю — как правильно тренировать этой методологии новичков, не пуская их в реальные инциденты. «Колесо неудач» — один путь. Если есть другие, расскажите через PR.