SRE и надёжность Проверка отказом: учения, chaos-эксперименты, game day
0%

Проверка отказом: учения, chaos-эксперименты, game day

Проверка отказом: учения, chaos-эксперименты, game day

В понедельник в 11:20 у платёжного сервиса умирает первичный узел базы. У команды есть горячая реплика, автоматическое переключение и документ, где написано «RTO 2 минуты». Через две минуты сервис всё ещё лежит. Через двадцать выясняется: реплика поднялась, но приложение продолжает ходить на старый адрес, потому что DNS-запись обновляется скриптом, у которого полгода назад отозвали права после наведения порядка в IAM. Скрипт падал молча — его выполнение никто не проверял, потому что оно случалось ноль раз.

Итог: 74 минуты простоя вместо заявленных двух. Резерв был. Документ был. Работающего переключения не было. Это не история про халатность. Это структурное свойство любого механизма, который срабатывает редко: пока вы не активировали его специально, у вас нет свойства «переживаем отказ X» — у вас есть гипотеза о том, что вы его переживаете. Разница между этими двумя вещами обнаруживается ровно в один момент — когда отказ случается сам, в неудобное время, без наблюдателя с секундомером и с настоящими пользователями в качестве испытательного стенда.

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

Три разные практики, которые постоянно путают

Под зонтиком «chaos engineering» в разговоре обычно смешивают три занятия с разными целями, разной ценой и разными участниками. Смешение вредно: команда говорит «мы не готовы к chaos в проде» и заодно отказывается от учений, которые стоят час и не трогают прод вообще.

Учение (drill) Chaos-эксперимент Game day
Что проверяет людей и процедуру свойство системы и то и другое разом, вместе с координацией
Главный вопрос «дежурный дойдёт до смягчения?» «гипотеза о поведении верна?» «мы как организация справимся?»
Где выполняется стенд или ролевая игра стенд, потом прод с узким радиусом стенд + прод, объявленное окно
Длительность 30–90 минут 5–30 минут на прогон полдня–день
Участники 1–3 человека 1–2 человека + автоматика 5–15 человек, включая продукт
Стоимость прогона часы доли процента бюджета ошибок человеко-дни
Что на выходе находки по рунбукам, доступам, связи подтверждённая или опровергнутая гипотеза список правок с владельцами
Можно начать сегодня после того, как есть наблюдаемость после двух-трёх успешных учений

Порядок внедрения именно такой, слева направо. Chaos-эксперимент в системе, которую вы не видите в метриках, — это не эксперимент, а способ устроить аварию с непонятной причиной. Game day без предварительных учений — это восемь человек, которые полдня смотрят, как двое разбираются с тем, что можно было найти за час. И терминологическая честность: «game day» как формат придумал не Netflix. Джесси Роббинс завёл его в Amazon в середине 2000-х, взяв идею напрямую из подготовки пожарных: Resilience Engineering: Learning to Embrace Failure, ACM Queue, 2012. Chaos Monkey появился позже и решал другую задачу — не тренировку людей, а принуждение разработчиков писать код, переживающий пропажу инстанса.

Арифметика латентного дефекта

Возьмём ту же пару «первичный узел + горячий резерв». Пусть первичный узел отказывает два раза в год; без резерва восстановление занимает 40 минут (поднять из бэкапа, прогреть, вернуть трафик), резерв обещает 2 минуты. Но переключение либо срабатывает, либо нет: обозначим долю удачных переключений c. Если переключение не сработало, простой оказывается длиннее, чем без резерва вообще — дежурный сначала ждёт автоматику, потом выясняет, почему её нет, потом разбирается, в каком состоянии остался резерв, и только потом идёт по ручному пути. Реалистичная оценка — 90 минут.

Ожидаемый простой на один отказ:

  E[T] = 2·c + 90·(1 − c) = 90 − 88·c

  c = 0,95  →  90 − 83,6 = 6,4 мин
  c = 0,80  →  90 − 70,4 = 19,6 мин
  c = 0,60  →  90 − 52,8 = 37,2 мин
  c = 0,30  →  90 − 26,4 = 63,6 мин

Точка безубыточности (когда резерв не даёт ничего):

  90 − 88·c = 40   →   c = 50/88 = 0,568

Резерв с вероятностью срабатывания ниже 0,57 хуже, чем его отсутствие. Вы платите за второй комплект железа, за репликацию, за поддержание симметрии сред — и получаете простой длиннее, чем если бы честно восстанавливались руками: при двух отказах в год это 127 минут против 80. Проблема в том, что c не наблюдаем. Компания, купившая резерв, автоматически считает c = 1 — в документе так и написано, «RTO 2 минуты». Единственное измерение c в природе — настоящая авария: одно наблюдение, в худший момент, с оплатой пользователями.

Уверенность деградирует, а не держится

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

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

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

Вероятность успешного переключения падает со временем; учения возвращают её обратно

Отсюда выводится расписание — не «раз в квартал, потому что так у всех», а из простого условия. Если вы хотите держать c не ниже 0,80 при деградации 7 п.п. за квартал, а после успешного учения c возвращается к ~0,97, то интервал между проверками — не больше двух кварталов, с запасом — один. Если ваш стек меняется быстрее (еженедельные изменения инфраструктуры, миграции схемы), интервал сокращается до месяца, и тогда ручное учение становится дорогим — приходится автоматизировать.

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

Сколько девяток вы вообще способны обслужить

Второй расчёт, без которого разговор про учения превращается в ритуал. Месяц — 43 200 минут.

99 %      → 0,01     × 43 200 = 432 мин   = 7 ч 12 мин
99,5 %    → 0,005    × 43 200 = 216 мин   = 3 ч 36 мин
99,9 %    → 0,001    × 43 200 = 43,2 мин
99,95 %   → 0,0005   × 43 200 = 21,6 мин
99,99 %   → 0,0001   × 43 200 = 4,32 мин  = 4 мин 19 с
99,999 %  → 0,00001  × 43 200 = 0,432 мин = 25,9 с

Теперь честный хронометраж восстановления с участием человека — цифры взяты из главы про дежурство и главы про реакцию на инцидент:

обнаружение (алерт по скорости сгорания)      2 мин
доставка пейджера, подъём, ноутбук            4 мин
вход, открытие дашборда, ориентация           3 мин
диагностика по рунбуку                        6 мин
действие и подтверждение эффекта              3 мин
                                       итого 18 мин

Один такой инцидент в месяц: 18 / 43 200 = 0,0417 %  → 99,958 %
Два инцидента в месяц:       36 / 43 200 = 0,0833 %  → 99,917 %

Первый вывод. 99,99 % несовместимы с человеком в контуре в принципе: 4,32 минуты — это меньше, чем доставка пейджера плюс подъём. Четвёртая девятка означает, что смягчение выполняет код: переключение, размыкатель, автоматический откат, отбрасывание нагрузки. Это код, который в бою выполняется единицы раз в год. Такой код по умолчанию сломан — ровно по той же причине, что скрипт с отозванными правами из вступления. Единственный способ проверить его — вызвать отказ специально.

Второй вывод. Прежде чем ставить целью четвёртую девятку, стоит посчитать её цену. Разница между 99,9 % и 99,99 % — 38,88 минуты в месяц.

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

  второй регион в активном режиме         +18 000 USD/мес
  межрегиональная репликация и трафик      +4 000 USD/мес
  разработка автоматического переключения   ~4 человеко-месяца
  постоянное поддержание симметрии сред     ~0,5 инженера
                                    итого  ~25 000 USD/мес + 0,5 FTE

Порог окупаемости: 25 000 / 38,88 = 643 USD за минуту простоя,
то есть около 38 600 USD в час.

Чтобы час полной остановки стоил 38 600 USD, годовая выручка
должна быть порядка 38 600 × 8 760 ≈ 338 млн USD.

Это грубая оценка, и у неё есть законные исключения: договорные штрафы в SLA, регуляторные требования, репутационные эффекты, неравномерность выручки по времени (для ритейла минута Чёрной пятницы стоит в тридцать раз дороже средней). Но порядок величины устойчив: если ваша выручка измеряется десятками миллионов, а не сотнями, четвёртая девятка обычно не окупается прямым счётом.

Про «пять девяток» — 25,9 секунды в месяц — говорить в терминах денег вообще бессмысленно. Один нештатный перезапуск пода с 30-секундным прогревом съедает месячный бюджет целиком. Плановая миграция с 20-секундным окном без обслуживания — 77 % бюджета. Пять девяток — это класс систем, где отказ измеряется не в деньгах: связь экстренных служб, ядро платёжной сети, медицинское оборудование. У них другая регуляторика, другая структура затрат и другая архитектура (см. главу про основы надёжности). И отдельно: «99,999 %» в SLA облачного провайдера — почти всегда обещание про узкий SLI (обычно про control plane или доступность API, а не про то, что ваши данные обслуживаются), подкреплённое компенсацией в размере скидки за месяц. Это не обещание доступности, а размер скидки; как выбирать SLI, чтобы такого не происходило у вас, — глава про SLI и SLO.

Chaos-эксперимент — это эксперимент, а не диверсия

Слово «хаос» в названии практики сыграло с ней злую шутку: оно наводит на мысль о случайности. На деле работающая практика устроена как обычный научный эксперимент, а не как рулетка. Principles of Chaos Engineering формулируют это в пяти пунктах; в переводе на язык повседневной работы:

  1. Стационарное состояние измеримо. Есть показатель, который в норме ведёт себя предсказуемо, и вы знаете его нормальный диапазон.
  2. Гипотеза записана до прогона. Не «посмотрим, что будет», а «показатель не выйдет за границу X».
  3. События реалистичны. Ломаем то, что ломается на самом деле, а не то, что легко сломать.
  4. Радиус ограничен и стоп-условие автоматическое.
  5. Прогон повторяем. Один раз — это анекдот; регулярный прогон — это регрессионный тест на устойчивость.

Шаблон, который стоит завести

Название:      Отказ реплики для чтения в зоне B
Владелец:      команда каталога
Стационарное:  доля успешных запросов /catalog ≥ 99,9 % за 5 мин,
               p99 latency ≤ 220 мс
Инъекция:      отбрасывание всех TCP-соединений к реплике зоны B
Радиус:        поды каталога в зоне B (7 из 21), это ~33 % трафика зоны,
               ~11 % общего
Длительность:  6 минут
Гипотеза:      доля успешных не опустится ниже 99,5 %,
               p99 не превысит 400 мс,
               алерт на скорость сгорания НЕ сработает
Стоп-условие:  доля успешных < 99 % в течение 30 с
               ИЛИ p99 > 600 мс
               ИЛИ любой пейджерный алерт
Откат:         снять правило firewall, время отката < 10 с
Стоимость:     максимум 0,8 % месячного бюджета ошибок
Окно:          вторник, 11:00–12:00, вне периода заморозки
Отменяем если: идёт инцидент любого уровня, выкатывается релиз,
               дежурный один

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

Радиус поражения считается в бюджете ошибок

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

Радиус поражения и его цена в месячном бюджете ошибок

Сервис: 1000 rps, SLO 99,9 % по доле успешных запросов.

Запросов в месяц:      1000 × 86 400 × 30 = 2 592 000 000
Бюджет ошибок (0,1 %):                       2 592 000 запросов

Прогон длиной 10 минут:  1000 × 600 = 600 000 запросов всего.
Худший случай — всё в радиусе провалилось:

  радиус 0,5 %  →   3 000 плохих →  0,12 % бюджета
  радиус 5 %    →  30 000        →  1,16 %
  радиус 33 %   → 198 000        →  7,64 %
  радиус 50 %   → 300 000        → 11,57 %
  радиус 100 %  → 600 000        → 23,15 %

Практическое правило: один прогон — не дороже 1–2 % месячного бюджета. Тогда программа из четырёх прогонов в месяц стоит около 5 % бюджета: заметно, но приемлемо, особенно если она предотвращает хотя бы одну аварию из тех, что съедают 20–30 % за раз. Механика самого бюджета — в главе про бюджет ошибок. Ещё один вывод из той же арифметики: ущерб линеен и по радиусу, и по длительности. Стоп-условие, срабатывающее за 30 секунд вместо десяти минут, делит ущерб на 20 — это дешевле и полезнее, чем сужать радиус до неинформативного. Поэтому первое требование к программе экспериментов — не «умейте ломать», а «умейте увидеть за 30 секунд». Если ваш мониторинг агрегирует с шагом в минуту и отстаёт на две, вы физически не сможете остановиться вовремя; сначала — разрешение метрик (глава про мониторинг), потом эксперименты.

Лестница зрелости одного сценария

Ключевой переход — второй сверху: «не выдержала» отправляет сценарий не в прод, а в бэклог. Соблазн «прогнать в проде, чтобы убедиться, что там тоже плохо» надо гасить: вы уже знаете ответ, а платить за него будут пользователи. Верхняя ступень — автоматический прогон — достижима и полезна далеко не всем. У Netflix ChAP автоматически подбирает эксперименты и гоняет их непрерывно (Automating chaos experiments in production, ICSE-SEIP 2019), но это работает поверх тысяч однотипных stateless-инстансов и зрелой платформы выкатки. В кластере из шести подов автоматический случайный убийца — не практика, а рулетка. Об этом подробнее ниже.

Что ломать: сценарии берутся из документов, а не из фантазии

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

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

Каталог инъекций по слоям

Слой Что вводим Чем вводим Что обычно находится
Процесс убить, заморозить (SIGSTOP), исчерпать файловые дескрипторы kill, stress-ng, chaos-агент нет graceful shutdown; соединения не закрываются; readiness врёт
Узел/под остановить, отобрать CPU, заполнить диск Chaos Mesh, LitmusChaos, AWS FIS PDB не настроен; всё реплики на одном узле; данные на локальном диске
Зона отрезать сеть зоны, остановить все узлы AWS FIS, правила безопасности кворум теряется при отказе одной зоны из трёх; квоты в других зонах не подняты
Сеть задержка, потери, дублирование, разрыв tc netem, toxiproxy, Pumba таймауты «из головы»; ретраи без джиттера; отсутствие дедлайнов
DNS NXDOMAIN, задержка резолва, залипший TTL подмена резолвера, toxiproxy закешированный адрес переживает переключение; резолв в горячем пути
Зависимость 500-е, медленные ответы, частичные ответы прокси-инъектор, feature flag фолбэк не включается; фолбэк медленнее основного пути
Хранилище отставание реплики, отказ первичного, read-only средства СУБД, firewall приложение не различает отставание и отказ; переключение не тестировано
Ресурсы исчерпать пул соединений, очередь, память нагрузочный генератор насыщение вместо деградации; нет отбрасывания нагрузки
Время сдвиг часов, истёкший сертификат подмена NTP, срок в тестовом CA всё построено на синхронности часов; нет алерта на срок сертификата
Люди ключевой инженер недоступен, нет доступа правило «этот человек молчит» знание в одной голове; доступ только у одного; рунбука нет

Две строки заслуживают отдельного упоминания. Истёкший сертификат — самая частая и самая дешёвая в проверке причина аварий, которую почти никто не проверяет специально: прогон занимает полчаса в стенде (выпустить сертификат с истекающим сроком в тестовом CA), а находит целый класс — отсутствие алерта за 30 дней, ручное обновление, клиенты с закешированной цепочкой, mTLS между сервисами, о котором забыли (глава про транспортную безопасность). И человеческие инъекции — самый дешёвый и самый недооценённый слой: «сегодня Пётр не отвечает» не требует никакой инструментовки и находит ровно то, что убивает команды, — единственный носитель знания, единственный владелец доступа, рунбук, понятный только автору.

Учение: проверяются люди, а не только система

Chaos-эксперимент отвечает на вопрос «что делает система». Учение отвечает на вопрос «что делает человек», а это чаще оказывается узким местом: система-то, может, и переживёт, а вот дежурный полчаса ищет дашборд.

Три детали устройства, без которых учение не работает.

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

Наблюдатель отдельно от ведущего. Ведущий занят инъекцией и подсказками, он не успевает вести таймлайн. Без таймлайна с отметками времени учение превращается в «ну вроде нормально прошло».

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

Самая дешёвая форма: разбор сценария без инъекции

Ролевая игра, известная как Wheel of Misfortune (описана в SRE-книге, гл. 28): ведущий берёт настоящий прошлый инцидент, участник «дежурит», ведущий отыгрывает систему — показывает графики, отвечает на команды словами. Никакой инструментовки, никакого стенда, час времени.

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

  • рунбуки, написанные автором для себя (никто другой по ним не проходит);
  • алерты без ссылок или со ссылками на переехавшие страницы;
  • дашборды, которые знает один человек, и отсутствие доступа к консоли у половины дежурных;
  • расхождение в понимании, кто имеет право откатывать релиз без согласования.

Ни одна из этих находок не требует ломать прод — и каждая стоит десятков минут в реальной аварии.

Правила безопасности учения

  • Настоящий инцидент побеждает учение. Всегда, немедленно, без обсуждения.
  • Стоп-слово известно всем и означает мгновенную остановку без объяснений. Тот, кто его сказал, никогда не оказывается неправ.
  • Учение помечено в календаре и в чате. Смежные команды должны знать, иначе вы получите второй инцидент — у соседей.
  • Учения — в рабочее время. Ночное учение «чтобы по-настоящему» выжигает людей быстрее реальных аварий и почти ничего не добавляет: работоспособность ночью проверяется другими средствами — контрольной доставкой пейджера и разбором ночных инцидентов. Цена ночных подъёмов посчитана в главе про дежурство.
  • Неанонсированные учения — только после того, как анонсированные проходят чисто, и только с ведома руководителя дежурства. Сюрприз в качестве стартовой практики — не эксперимент, а способ испортить отношения и потерять доверие к программе.

Game day: как выглядит день

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

  • Разбор идёт сразу после сценария, а не в конце дня. К 16:00 половина деталей забыта. Тридцать минут после каждого прогона дают в разы больше материала.
  • Прод — один сценарий и ближе к концу. К этому моменту команда разогрета, наблюдаемость проверена, а если что-то пойдёт не так, впереди ещё полтора рабочих часа и полный состав людей, а не вечер пятницы.
  • День заканчивается отчётом, а не намерением его написать. Отчёт, написанный на следующей неделе, не пишется никогда.

Роли на день — те же, что в реакции на инцидент, плюс две специфические:

Роль Кто Задача
Ведущий обычно тот, кто готовил сценарии инъекции, подсказки, тайминг, стоп
Наблюдатель человек вне сценария таймлайн с отметками времени, находки дословно
Командир по обычному расписанию, не ведущий координация участников, как в настоящем инциденте
Участники дежурные и разработчики работают так, как работали бы в бою
«Безопасник дня» старший инженер право остановить всё, следит за стоп-условиями
Представитель продукта опционально, но полезно видит цену деградации своими глазами

Последняя роль — самый недооценённый пункт: продукт-менеджер, который час наблюдал, как выглядит отказ рекомендаций для пользователя, потом совершенно иначе участвует в разговоре про приоритет правок и про SLO. Подготовка первого game day — примерно 2 человеко-недели: сценарии, стенд, инструментовка, согласование окна. Последующих — 2–3 человеко-дня, если сценарии переиспользуются.

Каскад — это усиливающая петля, и это меняет то, что вы измеряете

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

  1. Инъекция в одном месте, измерение — в другом. Интересна не реакция сломанного компонента, а передача возмущения. Если вы ломаете сервис цен и смотрите на метрики сервиса цен, вы измеряете инъекцию, а не систему.
  2. Малая инъекция может дать большой эффект — это и есть находка. Плюс 150 мс к одной зависимости не должны ронять продукт. Если роняют — вы нашли петлю усиления, а не «слишком сильную инъекцию».
  3. Эффект приходит с задержкой. Очередь растёт минуты, ретраи разгоняются десятками секунд, автоскейлер реагирует ещё позже. Шестиминутный прогон с наблюдением ровно шесть минут пропускает самое интересное: наблюдение должно продолжаться минимум вдвое дольше инъекции.
  4. Система может не вернуться после снятия инъекции. Это метастабильный отказ: причина устранена, а система остаётся в плохом состоянии, потому что петля питает сама себя. Именно поэтому в плане обязателен не только откат инъекции, но и процедура вывода системы из перегрузки — сброс очередей, временное отбрасывание нагрузки, поэтапный возврат трафика. Это же — важнейший аргумент в пользу узкого радиуса: эксперимент, который нельзя отменить простым снятием инъекции, обязан начинаться с долей процента трафика.

Цена

Время команды

Команда 8 инженеров, годовая ёмкость ≈ 8 × 1 800 = 14 400 ч

Программа:
  Wheel of Misfortune, 1 ч/мес на всю команду     8 × 12 =  96 ч/год
  Учение с инъекцией в стенде, 3 ч × 3 чел./квартал        36 ч/год
  Game day 2 раза в год: 6 чел. × 8 ч + 16 ч подготовки   128 ч/год
                                                   итого  260 ч/год

Доля годовой ёмкости: 260 / 14 400 = 1,8 %

Для сравнения: один средний инцидент — 90 минут по пять человек в остром режиме, 4 часа на постмортем, 2–3 дня на правки — обходится примерно в 40 человеко-часов. Годовая программа учений стоит как шесть-семь инцидентов. И тут надо быть честным: строго доказать окупаемость программы нельзя. Предотвращённые аварии не наблюдаются. Всё, что можно предъявить, — находки: если каждый прогон даёт три-пять пунктов класса «в реальном инциденте это стоило бы получаса», арифметика сходится по порядку величины. Обещать больше — значит продавать веру.

Инструменты

Инструмент Что даёт Что стоит
toxiproxy задержки, разрывы, потери на уровне TCP-прокси почти ничего; ставится рядом, без прав в кластере
tc netem, Pumba сетевые условия на узле/контейнере нужны привилегии на узле
Chaos Mesh, LitmusChaos инъекции в Kubernetes: поды, сеть, IO, время ещё один контроллер с широкими правами в кластере
AWS FIS, Azure Chaos Studio отказы на уровне облака, включая зоны привязка к провайдеру, поминутная оплата
Chaos Toolkit описание экспериментов в JSON/YAML, драйверы нужен свой каркас вокруг
Собственный фича-флаг «включить отказ» самый точный радиус, минимум прав код в проде, который умеет ломать прод

Скрытая цена инструментов посерьёзнее лицензий: chaos-агент с правами на убийство подов — это ещё один демон в проде, который может стать причиной аварии сам. Известный класс инцидентов — агент, оставшийся включённым после эксперимента, или агент, у которого сбился селектор. Отсюда практическое требование: рубильник должен находиться вне того, что вы ломаете. Если кнопка отмены живёт в том же кластере и вы уронили его control plane, отменять нечем. Про устройство самого кластера — глава про Kubernetes. И отдельная ветка, о которой стоит знать: для распределённых алгоритмов и хранилищ инъекция в живой системе — не самый эффективный способ. Детерминированное симуляционное тестирование (подход FoundationDB, описание) и проверка заявленных гарантий через Jepsen находят классы дефектов, которые chaos-эксперимент не наберёт статистикой никогда. Подробнее — в главе про тестирование распределённых систем.

Бюджет ошибок и люди

Бюджет. Эксперименты тратят его наравне с авариями и релизами. Если бюджет уже сожжён, эксперименты в проде останавливаются вместе с релизами — по тому же правилу. Это не бюрократия: сжигать остаток на добровольную поломку, когда пользователи и так пострадали, нельзя. Люди. Учения — это когнитивная нагрузка сверх обычной работы, и она ложится на тех же людей, что и дежурство. Отсюда правила: не совмещать учение с дежурной сменой того же человека; не проводить в неделю релиза крупной функциональности; не ставить два дня подряд. Программа, которая добавляет 1,8 % ёмкости в календарь и 15 % в утомляемость, работать не будет.

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

Где инженерное решение упирается в организационное

Прямым текстом: четыре вещи из этой главы инженер не может решить сам. Взгляд с другой стороны стола — в главе про дежурства и инциденты трека инженерного лидерства.

  1. Разрешение ломать прод. Это решение руководителя, и оформлять его надо как политику («эксперименты с радиусом до 5 % и автоматическим стоп-условием не требуют отдельного согласования»), а не выпрашивать каждый раз. Согласование на каждый прогон убивает регулярность, а без регулярности программа бессмысленна.
  2. Время в календаре. 260 часов в год не появляются из энтузиазма. Если они не выделены явно, учения проводятся первые два месяца, а потом отменяются в пользу срочного.
  3. Судьба находок. Game day, после которого находки не попали в бэклог с владельцем и сроком, — это два потраченных дня и минус доверие. Второй такой проводить не надо, пока не решён вопрос с приоритизацией.
  4. Компенсация за неурочное время. Если учение всё же приходится ставить в нерабочее время, это оплачиваемое время, а не проявление командного духа.

Что переносится из Netflix и Google, а что нет

Chaos Monkey работает у Netflix, потому что у Netflix тысячи взаимозаменяемых stateless-инстансов, автоматическая замена за минуты, трёхкратный запас ёмкости и платформа выкатки, умеющая откатывать сама (FIT: Failure Injection Testing). Ни одно из этих условий не выполняется в команде из восьми человек с шестью подами, один из которых — единственная реплика Redis. Google DiRT (Weathering the Unexpected, ACM Queue, 2012) — учения масштаба компании, с выделенной командой организаторов и правом останавливать целые датацентры. Полезно читать; воспроизводить целиком бессмысленно.

Переносится почти без изменений Не переносится
Гипотеза, записанная до прогона Непрерывный автоматический прогон в проде
Стоп-условие и измеренное время отката Случайное убийство инстансов
Радиус, посчитанный в бюджете ошибок Выделенная команда chaos-инженеров
Wheel of Misfortune раз в месяц Учения масштаба компании с остановкой ДЦ
Game day дважды в год Собственная платформа автоматизации экспериментов
Сценарии из постмортемов и таблицы критичности Расчёт на статистику по редким отказам
Проверка резерва раз в квартал «Мы ломаем всё и всегда» как культурная норма

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

С чего начинать команде из шести-десяти инженеров, в порядке отдачи на вложенный час:

  1. Wheel of Misfortune, час в месяц. Ноль инструментов. Первые три сессии дадут больше находок, чем следующий год чего угодно.
  2. Проверка одного резервного механизма в квартал. Того, на который вы реально рассчитываете: переключение БД, восстановление из бэкапа, второй канал доставки пейджера.
  3. Инъекция отказов зависимостей в стенде. Проверка заявленных фолбэков по таблице критичности. Toxiproxy или фича-флаг — этого достаточно.
  4. Восстановление из бэкапа целиком, с замером времени. Отдельный пункт, потому что «бэкапы делаются» и «из бэкапа можно восстановиться» — разные утверждения, и второе проверяли единицы.
  5. Первый прод-эксперимент с радиусом 0,5 % — только после того, как пункты 1–4 идут гладко.
  6. Game day — когда набралось хотя бы шесть-восемь сценариев и есть, что координировать.

Пункты 1–4 не требуют разрешения ломать прод, не тратят бюджет ошибок и закрывают, по опыту, большую часть разрыва между «написано» и «работает».

Как понять, что программа работает

Показатель Хороший знак Ловушка
Находок на прогон 3–5 в начале, снижение со временем ноль находок значит либо зрелость, либо повтор одного и того же сценария
Доля правок из постмортемов, проверенных отказом растёт к 60–80 % статус «проверено» без прогона
Доля пейджерных алертов с рунбуком, пройденным незнакомым человеком растёт «прошёл» ставит автор рунбука
Время до смягчения в учении сокращается тренируется один и тот же сценарий
Расхождение между учением и реальным инцидентом сокращается учения подгоняются под удобные условия
Число прогонов в квартал стабильно превращение в KPI даёт формальные прогоны

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

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

  • Начинать с прода. Первый прогон в проде до того, как сценарий отработан в стенде, — это не смелость, а незнание собственной наблюдаемости.
  • Эксперимент без записанной заранее гипотезы. Без неё любой результат объявляется ожидаемым, и прогон не даёт информации.
  • Стоп-условие «на глазок». Человек, ведущий эксперимент, всегда хочет «ещё минутку». Условие должно срабатывать автоматически.
  • Рубильник внутри радиуса поражения. Кнопка отмены в том же кластере, консоль за тем же балансировщиком, флаг в той же базе.
  • Инъекция и измерение в одной точке. Проверяется передача возмущения, а не реакция сломанного компонента.
  • Наблюдение ровно на длину инъекции и без плана вывода из перегрузки. Самое интересное — очереди, ретраи, автоскейлер, невозврат — происходит после снятия, а метастабильный отказ переживает устранение причины.
  • Драматизм вместо информации. Учение ночью «чтобы по-настоящему» и неанонсированный сюрприз как стартовая практика: дорого в людях, мало данных, минус доверие и второй инцидент у соседей.
  • Разбор в конце дня. Детали забываются за час; разбор нужен сразу после каждого сценария.
  • Находки без владельца, срока и выделенного времени на программу. Список наблюдений, который никуда не ведёт, отменяет смысл мероприятия; программа на энтузиазме живёт два месяца.
  • Оценка людей вместо сравнения с ожиданием. Мгновенно превращает учение в спектакль — механизм тот же, что при поиске виноватого в постмортеме.
  • Случайное убийство инстансов на маленьком масштабе. Без взаимозаменяемости и запаса ёмкости это лотерея, а не практика.
  • Chaos-агент оставили включённым. Классика: эксперимент закончился, правило firewall осталось, авария случилась через два дня.

Мини-итог

  • Механизм, срабатывающий редко, по умолчанию сломан. Резерв, фолбэк, скрипт отката и рунбук — гипотезы, пока их не активировали специально.
  • Резерв с вероятностью успешного переключения ниже 0,57 хуже, чем его отсутствие: E[T] = 90 − 88·c против 40 минут ручного восстановления. Величина c не наблюдаема без учений и падает примерно на 7 п.п. за квартал — отсюда и берётся периодичность проверок.
  • Арифметика девяток задаёт границу применимости человека: 18 минут на инцидент дают потолок около 99,96 % при одном инциденте в месяц. 99,99 % (4,32 мин/мес) означает автоматическое смягчение, а автоматическое смягчение проверяется только вызванным отказом.
  • Четвёртая девятка окупается прямым счётом примерно от 340 млн USD годовой выручки: 25 000 USD/мес дополнительных затрат против 38,88 сэкономленной минуты. Пять девяток — 25,9 секунды в месяц — исключают даже штатный перезапуск с прогревом.
  • Ущерб эксперимента линеен по радиусу и по длительности. При 1000 rps и SLO 99,9 % десятиминутный прогон на 5 % трафика стоит 1,16 % месячного бюджета, на всём трафике — 23,1 %; рабочая доза — 1–2 % за прогон. Стоп-условие за 30 секунд вместо 10 минут делит ущерб на 20, поэтому сначала разрешение метрик, потом эксперименты.
  • Сценарии берутся не из фантазии, а из документов: правки постмортемов со статусом «выкачена», заявленные фолбэки, рунбуки, план ёмкости, архитектурные допущения. Невозможность записать ожидание заранее — уже находка.
  • Учение проверяет людей: рунбуки, доступы, связь, эскалацию. Wheel of Misfortune — час в месяц, ноль инструментов, максимальная отдача. Подсказки выдаются, но записываются как находки.
  • Каскад и усиливающая петля — одно явление: ломать в одном месте, измерять на границе с пользователем, наблюдать вдвое дольше инъекции и иметь план вывода из перегрузки, а не только отката инъекции.
  • Программа стоит порядка 1,8 % годовой ёмкости команды; доказать её окупаемость строго нельзя, предъявлять можно только находки. Четыре вещи решает не инженер: разрешение ломать прод (как политика, а не разовое согласование), время в календаре, приоритет находок и оплата неурочного времени.
  • Из Netflix и Google переносятся гипотеза, радиус, стоп-условие и регулярность. Не переносятся непрерывный автоматический прогон, случайное убийство инстансов и расчёт на статистику по редким отказам — последнее как раз потому, что при малом масштабе редкие отказы сами по себе не происходят достаточно часто, чтобы чему-то научить.

Источники

Что дальше

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

Безопасные релизы: флаги, канареечные выкатки, откат

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

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

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

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