Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Chaos engineering: проверка отказоустойчивости на практике

Chaos engineering для команды продукта: эксперименты с отказами без героизма

Зачем ломать своё продакшен-систему осознанно: гипотезы и эксперименты chaos-инженерии, инструменты инъекции сбоев, безопасные границы и связь с SLO.

Прямой ответ

Chaos engineering — не «ломать прод на удачу», а проверка гипотез об отказоустойчивости управляемыми экспериментами: формулируется устойчивое состояние (SLO-метрики: p95, доля ошибок, глубина очередей), выдвигается гипотеза («смерть одного пода не нарушит SLO»), вводится контролируемый сбой (kill пода/задержка сети/отказ зависимости), измеряется поведение — гипотеза подтверждена или найдена дыра (обычно второе — в этом и ценность: дыры находятся в спокойный вторник, а не в инцидент в субботу). Зрелость по ступеням (не прыгать сразу в прод): (1) стейдж-эксперименты (свой стенд, любые сбои — первые опыты здесь), (2) прод с ограниченным радиусом (один инстанс из N, низконагруженные часы, мгновенный откат — «blast radius» контролируется), (3) регулярная практика (game days — командные учения по расписанию — incident-дисциплина); обязательные предохранители: эксперимент останавливается при выходе метрик за порог (abort-критерий заранее), наблюдаемость готова до эксперимента (вслепую ломать — вандалить), команда знает об эксперименте (или game day объявлен — «инцидент-сюрприз» без согласия — не chaos, а вредительство). Инструменты: toxiproxy (прокси-инъекции: задержка/обрыв/искажение трафика к конкретной зависимости — «БД тормозит 500 мс» — точечно и обратимо — главный инструмент прикладного уровня), LiteChaos/chaos-mesh/pumba (pod-kill/сетевые сбои в K8s — кластерные эксперименты), старая добрая рука (kill процесса, tc netem задержки, iptables-дроп — минимальный набор без новых зависимостей). И связь с паттернами: каждый найденный отказ проверяет конкретный механизм — ретраи/breaker (зависимость легла — деградация корректна?), graceful shutdown (под убит — соединения доработали?), failover (реплика поднялась?). Chaos без фикса найденного — театр; каждый эксперимент заканчивается тикетом или подтверждением «механизм работает как заявлен».

Методология: гипотеза, радиус, откат

Цикл эксперимента: устойчивое состояние — метрики «до» (p95/ошибки/очереди — baseline зафиксирован — процентили — «улучшилось/ухудшилось» меряется против него); гипотеза — конкретная и проверяемая («при недоступности платёжного API в течение 2 минут: заказы сохраняются в очередь, SLO не нарушен, после восстановления очередь разбирается без дублей» — не «проверим, что будет если…» — размытая гипотеза даёт размытый результат); инъекция — минимально достаточная (2 минуты отказа достаточны для проверки очереди — час не нужен — длительность эксперимента = длительность проверки гипотезы); наблюдение — дашборд + логи + трейсы (observability — эксперимент без наблюдаемости — лотерея); вывод и фикс — гипотеза подтверждена (механизм документирован как проверенный) или дыра (тикеты с приоритетом по критичности — найденное в experiment дешевле найденного в инциденте в разы). Радиус поражения — ключевая дисциплина: начинать с одного инстанса/пода (не «все реплики»), в низкий трафик (не «проверим в чёрную пятницу»), с abort-условием (SLO-метрика вышла за X — эксперимент сворачивается автоматически/дежурным — «наблюдали деградацию 20 минут потому что интересно» — провал методологии); откат — мгновенный и гарантированный (toxiproxy — удалить токсик одной командой; pod-kill — репликация восстановит; iptables — скрипт-откат написан до применения — «забыли правило в iptables» — инцидент после эксперимента — классика); документирование — отчёт эксперимента (гипотеза/результат/найденное — в базу знаний — следующая команда не повторит — документация решений). Психологический контур: blameless (incident-культура) — найденная дыра — не чья-то вина, а выигрыш команды; регулярность — эксперименты раз в спринт/месяц (разовый game day «для галочки» не строит мышление).

Инструменты и каталог экспериментов

toxiproxy — прикладной уровень (прокси между приложением и зависимостью: latency 500ms±200, timeout, connection refused, slow close, slice/искажения — сценарии «зависимость деградировала, а не умерла» — реалистичнее бинарного kill — именно деградации (медленно, но живо) ломают таймаут-дисциплину: без таймаута — воркеры висят, breaker не срабатывает на «живом тормозе» — латентные баги); tc netem — сетевой уровень (tc qdisc add dev eth0 root netem delay 300ms 50ms loss 5% — задержки/потери на интерфейсе — проверка ретрансмит-устойчивости и поведения клиентов — откат tc qdisc del); K8s-инструменты — chaos-mesh/LiteChaos (pod-kill/сетевой хаос/CPU-стресс как CRD — расписания/воркфлоу экспериментов — Helm-установка — для кластерных команд); стресс-ресурсы — stress-ng на CPU/память в контейнере (проверка лимитов/эвикшенов — ресурсы K8s — OOMKill-поведение под нагрузкой); ручные инъекции (kill -9 процесса, остановка контейнера зависимости, docker pause — пауза без убийства — «завис, не умер» — коварнейший сценарий; iptables DROP на порт — полная недоступность). Каталог «первых десяти» (покрывает большинство механизмов): смерть пода/процесса (репликация+graceful), зависание зависимости (таймауты), отказ зависимости (breaker+fallback), деградация латентности (таймауты/ретраи), потеря пакетов 5–10% (ретрансмиты/поведение клиента), полный узел (планирование/переезд подов), перезапуск БД (переподключение пулов — PgBouncer), исчерпание пула соединений (backpressure/ошибки), смерть брокера очередей (доставка — задачи пережили?), заполнение диска (логи/БД — поведение при ENOSPC — «диск кончился» — отдельный вид инцидентов — дисковая гигиена). Каждый эксперимент — про конкретный механизм с ожидаемым поведением — «просто всё поломаем» — не методология.

Практический сценарий: первый game day за полдня

Исходник: команда из 5 человек, сервис в K8s (3 реплики), зависимости: Postgres, Redis, платёжный API; за квартал — 2 инцидента с нештатным поведением (рестарт БД — приложение не переподключилось; Redis лёг — чекаут встал целиком вместо деградации). Подготовка game day: (1) площадка — стейдж-копия прода (данные обезличенные, топология та же — «стейдж не похож на прод» — отдельная проблема, здесь повезло); (2) наблюдаемость — дашборд SLO-панелей выведен на общий экран (p95/ошибки/очереди — метрики); (3) инструменты — toxiproxy вкомпонован перед БД/Redis/платёжкой (латентность/отказ по команде), pod-kill — kubectl; (4) agenda из 5 экспериментов с гипотезами (каждый 20–30 минут с разбором). Прогон: Э1 pod-kill — реплики пересобрались, SLO держится — подтверждено (graceful отработал — соединения доработали); Э2 рестарт Postgres — дыра: пул SQLAlchemy не переподключился (pre_ping не включён — 20 минут 500-х после восстановления БД) — тикет P1, фикс в тот же день (pool_pre_ping=True + ретраи на операциях); Э3 Redis down — дыра: чекаут падал вместо деградации (кеш без fallback — кеш-паттерны нарушены) — тикет P1 — fallback на БД с rate-лимитом; Э4 латентность платёжки 3s — breaker открылся корректно, заказы в очередь — подтверждено (сага отработала); Э5 — заполнение диска стейджа (учебно) — логи легли первыми, БД встала на записи WAL — вывод: алерт на диск 80% существовал, но не был в page-наборе — перенесён. Итоги полдня: 2 дыры P1 закрыты за неделю (обе стали бы инцидентами при первом же рестарте БД/Redis — цена game day — полдня команды против двух потенциальных инцидентов с разборами), 3 механизма подтверждены документально, привычка запущена (эксперимент в конце каждого спринта — 20 минут — «гипотеза спринта»). Через квартал: инцидентов с нештатным отказом зависимостей — ноль (не потому что отказов не было — БД рестартовали дважды планово — поведение было готовым и проверенным).

FAQ

Chaos engineering в маленькой команде — не роскошь ли? Полноценная программа (Netflix-стиль с автоматическими прод-экспериментами) — да, роскошь; базовая практика — наоборот, экономия: toxiproxy+kubectl+tc на стейдже раз в спринт — часы работы, находящие дыры до инцидентов; стоимость инцидента (простой+разбор+потеря доверия) почти всегда выше стоимости профилактики; начинать не с инструментов, а с вопросов («что будет, если БД перезагрузится прямо сейчас?» — если ответ «не знаем» — эксперимент уже оправдан).

Можно ли проводить эксперименты на проде без согласия пользователей? Этика и смысл: прод-эксперименты — с контролируемым радиусом и в рамках заявленной надёжности (SLO может качнуться в пределах error budget — бюджет на то и существует — эксперимент тратит бюджет осознанно); обязательны: abort-критерии, дежурный на откат, низкий трафик, уведомление команды поддержки (их пользователи звонят — «странные ошибки» без контекста пугают); «сюрприз для всех включая поддержку» — не chaos engineering, а розыгрыш с производственными последствиями; зрелые компании анонсируют maintenance-окна под эксперименты — честность дешевле репутационных потерь.

Чем chaos отличается от нагрузочного тестирования? Нагрузка (locust) проверяет «выдержит ли система объём» (производительность/пределы — ожидаемое поведение под давлением); chaos проверяет «как ведёт себя при поломках» (отказы/деградации — поведение при неожиданном); пересечение есть (нагрузка + отказ — самый реалистичный сценарий — experiment под трафиком показывает то, чего нет в покое — «breaker работает на 5 rps, но пул исчерпан на 500»); полноценная проверка — оба инструмента вместе: baseline-нагрузка + инъекция отказа.

Что делать с найденными дырами, если чинить некогда? Приоритизация по вероятности сбоя × ущербу (перезапуск БД случается планово — дыра P1; падение региона — реже — P2/P3 с планом); не починенное сразу — в реестр рисков с владельцем и сроком (техдолг-учёт — chaos-находки — его статья); временные компенсации — алерты на сценарий («БД рестартанула — дежурный вручную перезапустит приложение» — костыль, но осознанный — дешевле молчаливой дыры); и главное — найденное не теряется: отчёт эксперимента с тикетами — в базу знаний (runbook пополняется сценариями — следующий дежурный уже знает, что делать).

Источники: principlesofchaos.org, документация LitmusChaos, toxiproxy (Shopify) — ссылки в шапке.