Как искать информацию Поиск во время отладки: отдельный жанр
0%

Поиск во время отладки: отдельный жанр

Поиск во время отладки: отдельный жанр

Всё, что было в предыдущих главах, применимо к отладке — но применимо в особом режиме, потому что у отладочного поиска четыре отличия.

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

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

Есть давление. Отладка часто идёт под сроком, а иногда под инцидентом. Давление систематически ухудшает качество поиска: сужается внимание, растёт склонность хвататься за первое похожее объяснение.

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

Нулевой шаг: до первого запроса

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

Вопрос Зачем
Что именно наблюдается? Точная формулировка, без интерпретации «Тормозит» и «99-й перцентиль вырос втрое» ведут в разные места
Когда началось? С точностью до часа, если возможно Момент начала — самый сильный фильтр из всех
Что изменилось перед этим? Самый мощный вопрос отладки, ему ниже отдельный раздел
Воспроизводится ли? И при каких условиях Невоспроизводимое ищется иначе, чем воспроизводимое
У всех или у части? Каких именно Разделение на «все» и «некоторые» сразу отсекает половину гипотез
Работало ли когда-нибудь? «Никогда не работало» и «перестало работать» — разные расследования

Эти шесть ответов стоят пять минут и меняют весь дальнейший поиск. В частности, они превращают запрос из «почему сервис отдаёт 500» в «после деплоя такого-то часть запросов к одному эндпоинту падает с таким-то кодом только для пользователей с определённым признаком» — а это уже почти диагноз.

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

Порядок действий

Воронка отладочного поиска: сначала внутренние источники, потом внешние

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

«Что изменилось» — самый сильный вопрос

Если система работала, а потом перестала, что-то изменилось. Даже если «мы ничего не деплоили».

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

  • истёк сертификат (TLS, подпись клиента, корневой в образе);
  • истёк или ротировался токен, ключ доступа, пароль;
  • сработал TTL кэша, и нагрузка ушла на источник;
  • закончился ретеншн, и данные, на которые все рассчитывали, удалились;
  • наступила календарная граница: конец месяца, конец квартала, обнуление квоты;
  • сработал cron, о котором все забыли;
  • сменился часовой пояс или произошёл переход на летнее время;
  • достигнут порог: закончилось место на диске, номера в последовательности, идентификаторы, файловые дескрипторы.

Практический приём поиска «что изменилось»:

# что деплоилось и когда — по истории репозитория
git log --since='2 days ago' --oneline --all
git log --format='%ci %h %s' -20

# что изменилось в зависимостях: дифф lock-файла информативнее кода
git diff HEAD~5 -- package-lock.json go.sum poetry.lock Cargo.lock | rg '^[-+].*[0-9]+\.[0-9]+'

# что изменилось в конфигурации инфраструктуры
git log -p --since='1 week ago' -- deploy/ helm/ terraform/ | rg '^[-+]' | head -50

# какие образы реально запущены и когда собраны
docker inspect --format '{{.Created}} {{index .RepoTags 0}}' $(docker ps -q)
kubectl get pods -o custom-columns='NAME:.metadata.name,IMAGE:.spec.containers[*].image,START:.status.startTime'

Дифф lock-файла — недооценённый источник. Обновление транзитивной зависимости не видно в коде и не упоминается в описании изменений, но именно оно часто меняет поведение. Про управление зависимостями — глава в треке принципов.

Поиск внутри своей системы

До веба идёт поиск по тому, что у вас уже есть. Несколько приёмов, которые дают больше всего.

Найти первое вхождение. Не последнее, а самое раннее проявление симптома. Обычно оно отличается от остальных: там ещё нет каскада вторичных ошибок, и видно исходное событие.

# первая ошибка за окно, а не сотая
rg -n 'ERROR|panic|exception' app.log | head -5

# отфильтровать окно вокруг момента начала
rg -n '2026-07-16T1[0-2]:' app.log | rg -i 'timeout|refused|reset'

# структурные логи: считаем, что вообще происходит
jq -r 'select(.level=="error") | .msg' app.jsonl | sort | uniq -c | sort -rn | head -20

# корреляция по идентификатору трассировки
rg -n '"trace_id":"abc123"' *.jsonl | sort

Сравнить хороший период с плохим. Самый сильный приём анализа логов и метрик: не «что происходит сейчас», а «чем сейчас отличается от вчера в это же время». Разница обычно короткая и содержит ответ.

# что появилось в логах, чего не было раньше
jq -r '.msg' bad.jsonl  | sort -u > /tmp/bad.txt
jq -r '.msg' good.jsonl | sort -u > /tmp/good.txt
comm -23 /tmp/bad.txt /tmp/good.txt | head -30

Включить то, что выключено. У большинства библиотек есть debug-режим, у клиентов — подробное логирование, у СУБД — логирование медленных запросов. Пять минут на включение часто заменяют час гипотез. Про наблюдаемость — глава про мониторинг.

Когда идти во внешние источники и куда

Внешний поиск при отладке эффективен в четырёх случаях, и только в них.

Случай Куда Что ищете
Есть инвариантная строка ошибки поиск по коду, трекер место, где она печатается, и условие
Есть имя механизма документация, спецификация контракт и гарантии
Подозрение на баг зависимости трекер проекта, changelog, releases закрытые issue с вашим симптомом и версия с исправлением
Подозрение на проблему провайдера status page, официальные бюллетени подтверждение инцидента и его окно

Первым делом — status page провайдера. Тридцать секунд, и иногда расследование заканчивается: у них инцидент, вы ни при чём. Это правило кажется банальным, но проверяют его далеко не первым.

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

Проверка уязвимостей. Если симптом связан с безопасностью или с внезапным отказом после обновления, посмотрите бюллетени: OSV, GitHub Advisory. Они отвечают точно на вопрос «затронута ли моя версия».

Хронология одного расследования

Ключевой момент — шаг 6. Обнаружив, что изменений не было, инженер не пошёл искать в вебе «почему 5xx», а перешёл к списку «что меняется само по себе». Это переключение и есть навык.

Поиск во время инцидента: другие правила

Когда система лежит, приоритеты меняются: сначала митигация, потом причина. Отладочный поиск в этом режиме подчиняется дополнительным правилам.

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

Полный разбор процесса — Реагирование на инциденты и Постмортемы.

Что искать бесполезно

  • «Почему у нас падает X». У «нас» нет представительства в индексе.
  • Полный текст вашего стека вызовов. Он уникален; ищите одну инвариантную строку.
  • Симптом без версии. Найдёте чужую проблему с похожим проявлением и другой причиной.
  • Решение до диагноза. Запрос «как исправить ошибку N» приводит к набору чужих обходных путей; часть из них ухудшит ваше состояние.
  • Подтверждение уже выбранной гипотезы. Если вы ищете, чтобы убедиться, вы найдёте — и это ничего не значит.

Невоспроизводимая проблема: отдельный подрежим

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

Порядок действий другой:

  1. Сначала добиться наблюдаемости, а не причины. Пока событие не фиксируется, искать нечего. Добавьте логирование в подозрительный путь, включите сэмплирование трасс, поставьте счётчик.
  2. Собрать статистику проявлений. Когда именно? У кого? На каком узле? После чего? Часто уже эта таблица содержит ответ: все случаи оказываются на одной реплике, или все — в первые минуты после запуска, или все — у клиентов с определённой версией.
  3. Искать корреляцию, а не совпадение. Признак, встречающийся во всех случаях и отсутствующий в остальных, — это гипотеза. Признак, встречающийся во всех случаях и вообще везде, — нет.
  4. Проверить границы и редкие ветки. Невоспроизводимое почти всегда живёт в местах, где сходятся конкурентность, время, ошибки сети или необычные данные.
  5. Только потом внешний поиск — по имени механизма, который вы заподозрили, плюс слова race, flaky, intermittent, under load.

Отдельно про флаки-тесты: они тоже относятся к этому режиму, и у них есть своя литература и свои приёмы фиксации (повторные прогоны с записью, детерминированные сиды, изоляция состояния). Про устройство тестов в конвейере — Тесты в CI.

Ловушки отладочного поиска

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

Изменение симптома вместо устранения причины. Увеличенный таймаут убирает ошибку и оставляет проблему. Признак: вы не можете объяснить, почему помогло.

Каскад. Первая ошибка порождает сотню вторичных, и поиск идёт по вторичным. Отсюда правило «искать первое вхождение».

Туннельное зрение под давлением. Первая правдоподобная гипотеза захватывает внимание целиком. Противоядие простое и работает: вслух назвать три гипотезы, прежде чем проверять первую.

Разведка вместо наблюдения. Полчаса чтения там, где включение debug-лога дало бы ответ за две минуты. Про баланс — предыдущая глава.

Что оставить после расследования

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

  • Скрипт или тест, воспроизводящий проблему. Он же — доказательство того, что вы починили именно её.
  • Одна строка в коде рядом с исправлением: почему так, со ссылкой на issue или на источник.
  • Запись о причине с датировкой: какая версия, какое условие, что именно изменилось.
  • Тупики: где искали и не нашли. Следующий человек начнёт с тех же трёх мест.

Подробно про формы следа — следующая глава.

Типичные ошибки

  1. Открывать поисковик первым действием. Сначала шесть вопросов нулевого шага.
  2. Не спрашивать «что изменилось». Самый сильный вопрос, и он бесплатный.
  3. Забывать про ветку «время». Сертификаты, токены, TTL и календарные границы ломают системы без всяких изменений.
  4. Искать по последней ошибке вместо первой.
  5. Не смотреть status page провайдера. Тридцать секунд, иногда закрывает вопрос целиком.
  6. Искать без ограничения по версии.
  7. Менять несколько вещей одновременно.
  8. Не записывать хронологию. После инцидента её уже не восстановить.

Мини-итог

  • Отладочный поиск — причинный: ответа «вообще» не существует, главный источник — ваша система.
  • Нулевой шаг: что наблюдается точно, когда началось, что менялось, воспроизводимо ли, у кого, работало ли раньше.
  • «Что изменилось» — самый сильный вопрос; если ответ «ничего», работает ветка «время»: сертификаты, токены, TTL, календарь, пороги.
  • Внутренние источники идут до внешних: логи, метрики, трассировки, история изменений, дифф lock-файла.
  • Ищите первое вхождение, а не последнее, и сравнивайте плохой период с хорошим.
  • Внешний поиск эффективен в четырёх случаях: есть инвариантная строка, есть имя механизма, подозрение на баг зависимости, подозрение на инцидент провайдера.
  • Во время инцидента митигация идёт раньше причины, таймбокс жёсткий, изменения по одному, хронология пишется по ходу.
  • Похожее сообщение об ошибке не означает ту же причину; проверяйте условие.

Источники

  • Andreas Zeller. Why Programs Fail: A Guide to Systematic Debugging (2-е изд., 2009) — систематический подход к поиску причин, включая дельта-отладку.
  • David J. Agans. Debugging: The 9 Indispensable Rules for Finding Even the Most Elusive Software and Hardware Problems (2002).
  • Brendan Gregg. Systems Performance (2-е изд., 2020) — методики USE и другие подходы к локализации узкого места.
  • Betsy Beyer et al. (ред.). Site Reliability Engineering (Google, O’Reilly, 2016), глава «Effective Troubleshooting» — sre.google/sre-book/effective-troubleshooting.
  • OSV — база уязвимостей с точным указанием затронутых версий: osv.dev.

Что дальше

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

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

Нужен разбор именно вашей ситуации?

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

Доска запросов