Инфраструктура была покрыта кодом почти на сто процентов. Мониторинг покрыты все компоненты. В момент аварии все метрики базы данных были идеальными, соседние сервисы на том же сервере СУБД работали без единой ошибки, провайдер облака показывал зелёный статус.

При этом продакшн лежал двадцать минут, и первые пятнадцать никто не понимал, что происходит.

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

Дисклеймер про обезличивание

Разбор настоящий, авария была на проекте с миллионом с лишним пользователей в день, в период переезда инфраструктуры в новое облако.

Здесь нет названия проекта, отрасли, названий сервисов, СУБД, облачного провайдера и инструментов. Осталось ровно то, без чего механизм не понять: проект‑миллионник, идущая миграция, сервис в одной локации и его база в другой.

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

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

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

Симптом

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

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

Разгадка первой странности проста, и она же — главная ловушка этой аварии. У сервиса был кеш со временем жизни пять минут. Всё, что лежало в кеше, обслуживалось как обычно; всё, что требовало нового обращения в базу, падало. По мере истечения TTL доля отказов росла.

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

Что при этом выглядело спокойным

Всё. В этом и была суть.

Что смотрели

Что видели

Метрики СУБД

p99 времени ответа — единицы миллисекунд, соединений меньше половины лимита пула, процессор около десяти процентов, отставание репликации ноль

Медленные запросы

Ни одного

Соседи по СУБД

На том же сервере жили базы ещё нескольких сервисов — ни одной ошибки

Проблемный сервис

Процессы живы, память в норме, рестартов нет

Провайдер нового облака

Аварий нет, статус зелёный

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

Что мы делали и что не помогло

Первые минуты ушли на то, что кажется единственно правильным: проверить всё по очереди. Базу, сервис, ресурсы, провайдера. Каждая проверка давала «зелёный ответ», и каждый такой ответ уводил дальше от причины — потому что проверялись компоненты, а не связи между ними.

Второе, что не помогло, было хуже. У нас не было точного ответа на вопрос, что и где сейчас работает. Шла массовая миграция, и статус «какие сервисы в каких локациях обслуживают продакшн» существовал только в головах инженеров, это были первые дни, самое начало работ. Поэтому мысль «сервис живёт в другом дата‑центре, чем его база» пришла не первой, а примерно пятой.

Два измерения, которые снимают базу с подозрения

Первое: посмотреть на соседей. На том же сервере, на той же СУБД работали базы других сервисов, и у них всё было в порядке. Если бы проблема была в базе или в сервере, ошибки были бы у всех. Они были у одного.

Второе: прочитать текст ошибки, а не только её количество. Сервис получал не отказ соединения connection refused, а истечение времени ожидания то есть, connection timed out. Разница между этими двумя ошибками — это и есть диагноз.

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

После этого вопрос трансформировался с «что сломалось», на «что изменилось на сетевом пути между этим сервисом и его базой». У такого вопроса короткий список ответов.

Развилка, которую не прошёл никто

Инфраструктура была покрыта кодом почти полностью. Значит, любое изменение в ней — это коммит и запуск пайплайна.

И при этом за первые пятнадцать минут никто не открыл историю изменений и не посмотрел последние выполненные пайплайны. Все смотрели в мониторинг, потому что при аварии рефлекс — смотреть в мониторинг.

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

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

Корневая причина

Новые правила сетевого фильтра на стороне нового облака были настроены некорректно и отрезали трафик от сервиса в облаке к серверу базы данных в основном дата‑центре.

Проверка на то, что причина корневая: правила откатили — связность восстановилась, ошибки прекратились. Убрали причину — инцидент не воспроизводится.

Механизм целиком:

  1. Пайплайн применил новые правила фильтрации в новом облаке.

  2. Трафик от сервиса к базе в основном дата‑центре начал отбрасываться, новые соединения перестали устанавливаться.

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

  4. По мере истечения TTL доля ошибок росла.

  5. Метрики базы оставались идеальными: к ней перестали приходить запросы от одного из клиентов. База не отвечала медленно — её никто не спрашивал.

Провайдер облака был не виноват. Внешнюю причину искать приятнее, чем свою, и версия «у них что‑то с сетью» в первые минуты звучала правдоподобно. Сломали сами, своим же пайплайном.

Последствия

Простой около двадцати минут — оценка по памяти. Примерно пятнадцать из них ушло на диагностику и около пяти на откат и восстановление связности.

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

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

Что чинит класс проблем целиком

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

1. Тестовый контур для продовой инфраструктуры. Главное решение, принятое после этой аварии. Если инфраструктура описана кодом, у этого кода должно быть место, где его можно выполнить не на живых пользователях.

2. Проверка связности между локациями как отдельный сигнал. Не хватало ровно одного индикатора: жив ли сетевой путь между новым облаком и основным дата‑центром. Компонентные метрики этого не показывают в принципе.

3. Актуальная карта локаций во время миграции. Ответ на вопрос «какие сервисы в каких локациях обслуживают продакшн» должен быть документом. Во время переезда это «must have» информация и она должна быть под рукой у дежурного инженера.

4. «Что изменилось в git за последний час» — первым шагом, а не от безисходности. История изменений инфраструктуры и последние пайплайны проверяются до того, как открыт первый дашборд.

Четвёртый пункт стоит ноль рублей и именно он превратил бы двадцать минут в пять.

Чек‑лист: что смотреть в первые пять минут, когда всё зелёное

Если компоненты исправны, а продакшн не работает, сломалось между компонентами. Порядок проверок, который экономит время:

  1. Что изменилось за последний час. История изменений инфраструктуры, последние пайплайны, последние применённые конфигурации.

  2. Текст ошибки, а не её количество. Отказ соединения и истечение времени ожидания указывают на разные слои. Одно слово в логе экономит десятки минут.

  3. Соседи по общему ресурсу. Если у одного клиента общей базы, очереди или кеша плохо, а у остальных хорошо — общий ресурс здесь ни при чём.

  4. Обе стороны вызова. Сравните, сколько отвечала зависимость по её собственным метрикам и сколько ждал вызывающий. Расхождение на порядки означает, что проблема между ними.

  5. Топология: кто где живёт. Особенно во время миграции. Сервис и его база могут оказаться в разных локациях.

Первый пункт — самый недооценённый. Мониторинг отвечает на вопрос «что сейчас», а история изменений — на вопрос «что изменилось», и во время миграции второй вопрос точнее.

Вопрос, ради которого стоило вспомнить этот инцидент

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

Если бы этого человека в тот день не оказалось, авария длилась бы не двадцать минут, а столько, сколько потребовалось бы, чтобы кто‑нибудь догадался.

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


Я DevOps/SRE‑инженер, девятнадцать лет в эксплуатации: cian.ru, aliexpress.ru, mos.ru — в каждом больше миллиона пользователей в день. Пишу про то, как доходить до причины по симптому и как передавать этот способ думать команде: t.me/bukatchuk.

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

Комментарии (0)