Меня зовут Михаил Новиков, я архитектор в команде, которая развивает один из пользовательских сервисов. В статье расскажу, зачем мы за 5,5 недель внедрили х��ос-тесты, что учли при их настройке и почему ломаем прод Mindbox.
Мы решили искоренить дефекты на проде
В нашем сервисе используется кластер Redis. Однажды во время планового обслуживания сработал алерт: одно из приложений не могло подключиться к Redis, хотя он отвечал на запросы. Оказалось, что обращение направлено к реплике, которая находится на обслуживании. Пришлось вручную перезапускать поды в Kubernetes, чтобы приложение увидело рабочую реплику. Мы разбирались почти час, а 90% пользователей не могли подключиться к нашему сервису.
Вскоре случился новый дефект. Снова отказал весь функционал нашего сервиса, теперь из-за остановки одного из трех брокеров Kafka. В этот раз к сервису потеряли доступ 5% пользователей.
Каждый раз мы тратили время на решение инцидентов и нарушали обязательства перед клиентами. Нужно было найти способ выявлять подобные дефекты до того, как они проявятся. Такой способ — хаос-тестирование.
Хаос-тестирование: что это и зачем нужно
Хаос-тестирование — это способ проверить, насколько устойчива система. Во время тестов в неё преднамеренно вносят сбои или нештатные ситуации (например, отключают сервера, увеличивают нагрузку, ломают сети).
Цель — выявить слабые места, оценить отказоустойчивость и способность системы восстанавливаться после сбоев. Это помогает предотвратить потенциальные инциденты и убедиться, что система корректно работает в экстремальных условиях. Особенно полезно для сложных распределенных систем, где сбои могут наслаиваться один на другой.
Метод не новый, и в этой статье я не буду вдаваться в теорию. В конце статьи добавлю материалы, на которые мы опирались при внедрении хаос-тестов.
Как мы разворачивали хаос-тесты
Весь процесс внедрения от идеи до запуска первого теста на проде занял у нас чуть меньше полутора месяцев. Первые 1,5 недели собирали гипотезы и описывали стабильное состояние системы. Следующие 4 недели три разработчика писали тесты, вспомогательные уведомления и отображения прохождений для них. Написали тесты отказа брокера Kafka и ноды Cassandra, смены мастера Redis, перезапуска подов приложения, деградации Cassandra и общей проверки инфраструктуры.
Этап 1. Контрольная точка
В любом эксперименте сначала определяют стабильное состояние системы, чтобы было с чем сравнивать результат эксперимента. Перед тем, как запускать хаос-тесты, нужно зафиксировать правильное поведение системы: показатели метрик, приложений и вспомогательных ресурсов. Система должна вернуться к нему после того, как искусственный сбой закончится.
Наша система выполняет маркетинговые сценарии, составленные пользователем. Поэтому мы опередили стабильное состояние через алерты и Success Rate метрику.
Состояние | Как измеряем |
Все сценарии выполняются в обычном режиме | Нет алертов о работе сервиса и сбоев Heartbeat. Heartbeat — это сервис, который раз в 15 секунд запускает заранее подготовленные искусственные сце��арии. Если происходит сбой, присылает оповещение в течение минуты. |
Договор с клиентом (SLA) не нарушается | Не нарушена Success Rate метрика. Метрика рассчитывается как сумма успешно завершенных событий ко всем событиям, ушедшим в ошибку. Должен быть больше 0,9: это значит, что 90 из 100 событий обработаны успешно. |
Все метрики наблюдаем на отдельном борде Grafana:

Сервис Heartbeat подходит для проверок большинства сбоев, например сбоя Kafka. Если выключение брокера ломает систему, Heartbeat это поймает и покажет. Но скрипт не универсальный и на некоторых тестах не срабатывает. Например, мы тестировали разрыв связи между сервисами: один сервис переставал видеть другой, но продолжал нормально работать за счет долгоживущего кеша. Однажды связь не восстановилась после окончания теста, а наши графики стабильного состояния этого не показали. Время жизни данных в кеше завершилось, и система перестала корректно работать.
Чтобы оценить стабильное состояние системы, смотрите на основные процессы, с каким SLA они выполняются, какая у них статистическая норма. Важно настроить дашборд с этими состояниями и уведомления о нештатной работе. Во время тестирования надо убедиться, что в случае сбоя, вызванного тестом, стабильное состояние реально нарушается. И точно знать, что есть мониторинг и алерты на сбой.
Этап 2. Гипотезы для проверки хаос-тестами
Мы проводим для каждой гипотезы отдельный эксперимент. Считаем, что важно их не усложнять — например, проверять только один элемент системы: Redis или Cassandra, но не оба вместе.
Для нас первым источником гипотез стали инциденты с Redis и Kafka, описанные в начале статьи. Для ситуации, когда приложение обращалось к нерабочей реплике Redis, придумали такую формулировку: смена мастера кластера Redis не приводит к деградации сервиса.
Дефект с остановкой одного из трех брокеров Kafka дал нам такую тему для эксперимента: отказ одного брокера Kafka не влияет на выполнение сценариев.
Позднее к гипотезам о падении части инфраструктуры мы добавили другие, о деградации части системы, например: сетевые задержки до одной из нод Cassandra в 90 перцентилей не влияют на время выполнения запросов от приложения.
Можно строить сложные гипотезы на основе уже проверенных. Если участвуют несколько элементов системы, лучше сформулировать предположения по каждому элементу отдельно и проверить сначала их, и только после этого проверять первоначальную гипотезу с несколькими элементами.
Пример гипотезы из двух элементов: деплой приложения (перезапуск подов приложения) при отказе одного брокера Kafka не приводит к сбоям сервиса.
Упростить ее можно так:
отказ одного брокера Kafka не приводит к сбоям сервиса;
деплой приложения (перезапуск подов приложения) не приводит к сбоям сервиса.
Двойные гипотезы мы формулировали по следам ситуаций, когда сам по себе сбой Kafka не приводил к деградации, но при перезапуске мы не могли стартовать сервисы из-за неверных настроек приложения.
Гипотезы для тестов не обязательно строить на уже случившихся инцидентах. Можно предполагать любые ситуации:
1. Можно строить гипотезы об отказе других элементов кластера, которые ещё не приводили к дефектам. Например, реплика SQL базы данных, Cassandra.
2. От гипотез отказа можно перейти к гипотезам о деградации. В реальной жизни мы чаще сталкиваемся с ситуациями, когда какой-то элемент системы не полностью отказал, а стал отвечать с задержками или терять часть запросов. Пример — наша гипотеза, что сетевые задержки до одной из нод Cassandra не влияют на время выполнения запросов от приложения.
3. Можно подумать о гипотезах из нескольких частей, как в нашем двойном предположении, ��то деплой приложения (перезапуск подов приложения) при отказе одного брокера Kafka не приводит к сбоям сервиса. Или продумать ситуации более глобальных отказов, например, целой зоны в облаке или одного из датацентров.
Этап 3. Эксперимент
Чтобы провести эксперимент, мы выбрали среду и инструменты, подобрали и написали тесты, продумали, как их остановить, и убедились, что не сломаем ничего у соседей — определили радиус поражения. Дальше обо всем по порядку.
Среда для тестов
На нашем проде 60 миллионов конечных пользователей, тысяча компаний и до 2 миллионов RPM. Воспроизвести все это в тестовой среде мы не можем. Если проводить хаос-тесты только на модели без пользователей, обязательно что-то упустим. Поэтому мы приняли волевое решение и вносим хаос в настоящий прод раз в день с понедельника по четверг.
У нас в течение дня может быть десяток релизов, как это устроено, уже рассказывали в статье про наш релизный цикл. Большинство тестов запускается раз в день, их результаты помогают понять, что выкаченные изменения не привели к дефектам и деградации.
На проде все под контролем: мы знаем время запуска тестов, знаем стабильное состояние системы и можем восстановить работоспособность в любой момент даже без алерта.

Инструмент для тестов
Выбор инструмента зависит от параметров, которые нужно проверять, и от стека, который применяется в вашем продукте. Наши сервисы живут в Kubernetes. Вспомогательные штуки, вроде Kafka и Cassandra, — на облачных виртуалках. Redis используем готовый, его предоставляет провайдер. Нам интересны хаос-тесты, которые умеют дружить с Kubernetes и делать что-то на виртуалках, поэтому мы выбрали Chaos Mesh.
Chaos Mesh разворачивается в Kubernetes и из коробки умеет ломать сеть и убивать поды. В его состав входит утилита Chaosd, которую можно поставить на виртуальные машины, чтобы наводить хаос там — рестартовать процессы, нарушать работу сети и диска. Полный список есть в документации Chaos Mesh.
Из минусов разве что UI: он очень сырой и создавать из ��его эксперименты бывает сложно. Но это нам не мешает: в нашей инфраструктуре релизы управляются через Helm, а хаос-тесты создаются через yml-описания. Вот пример декларации простейшего эксперимента, который убивает (action: pod-kill) 50% подов с выбранной меткой (labelSelectors):
kind: PodChaos
apiVersion: chaos-mesh.org/v1alpha1
metadata:
namespace: my-namespace
name: kill-pods-0
spec:
selector:
namespaces:
- my-namespace
labelSelectors:
app: my-app-label
mode: fixed-percent
value: '50'
action: pod-kill
gracePeriod: 5Чтобы настроить регулярный запуск тестов, используем элемент Chaos Mesh — расписание (schedule). Chaos Mesh не умеет ограничивать параллельный запуск разных расписаний. Параметр concurrencyPolicy может только запретить новый запуск, если предыдущий еще не завершился. Чтобы ограничить одновременное выполнение разных расписаний, подб��раем их вручную.
Для описания шагов эксперимента используем элемент Workflow. Внутри Workflow идет последовательность действий по созданию хаоса. Chaos Mesh поддерживает последовательные шаги templateType: Serial и параллельные templateType: Parallel.
В примере kind: Schedule определяет, что это расписание, а внутри type: Workflow говорит, что по расписанию будем запускать последовательность шагов.
apiVersion: chaos-mesh.org/v1alpha1
kind: Schedule
metadata:
name: cassandra-node-fault-workflow
namespace: my-namespace
spec:
schedule: 30 18 * * 1-4
startingDeadlineSeconds: 1800
concurrencyPolicy: Forbid
historyLimit: 1
type: Workflow
workflow:
entry: cassandra-node-fault-entry
templates:
- name: cassandra-node-fault-entry
templateType: Serial
deadline: 10m
children:
- notify-test-started
- stop-cassandra-node
- name: stop-cassandra-node
templateType: PhysicalMachineChaos
deadline: 3m
physicalmachineChaos:
action: process
address:
- http://cassandra-a-1-v2:31767
- http://cassandra-b-1-v2:31767
- http://cassandra-d-1-v2:31767
mode: one
process:
process: java
recoverCmd: systemctl restart cassandra
signal: 9
- name: notify-test-started
templateType: Task
task:
container:
args:
- -c
- "notify command here"
command:
- /bin/sh
image: curlimages/curl:7.78.0
name: notify-chaos-test-startedРадиус поражения
При подготовке к эксперименту важно понять, просчитать и минимизировать потенциальный радиус поражения от экспериментального сбоя. Что пострадает, кроме основной цели теста, какие еще сервисы могут работать нештатно или ломаться от привнесенного хаоса — это необходимо учесть до запуска тестов. Если не понимаете радиус поражения, то ломать прод нельзя — последствия становятся непредсказуемыми.
В своем сервисе мы знаем все функ��ии, которые могут сломаться, и все способы повлиять на другие части системы. Они ограничены и контролируемы. И мы не стали делать хаос-тесты Redis там, где на одном кластере работают десятки микросервисов разных команд — радиус поражения был бы слишком велик.
Рекомендую четко высчитывать радиус поражения и не запускать хаос-тестирование, если точно не знаете, что может сломаться. Подсчеты должны опираться на важность сервиса, на его уровень критичности. Если у вас еще нет градации уровней критичности — ее нужно ввести. Прежде чем попытаться все сломать, вы должны знать, как быстро сможете восстановить нормальную работу, если тест пойдёт не по плану.
Кнопка аварийной остановки
Чтобы хаос не вырвался из-под контроля, обязательно должен быть способ вручную остановить тест и вернуть систему в стабильное состояние.
В Chaos Mesh можно руками поставить эксперимент на паузу или настроить, чтобы он останавливался автоматически в определённых состояниях системы.

Мы еще не сделали вариант с автоматической остановкой, но при старте хаос-теста в командный канал приходит сообщение со ссылками на эксперимент и инструкцию по ручной остановке.
Каких-то встроенных интеграций с мессенджерами у Chaos Mesh нет, но работает механизм Webhook, примерно так:
type: 'Workflow'
workflow:
entry: notify-test-started
templates:
- name: notify-test-started
templateType: Task
task:
container:
name: notify-chaos-test-started
image: cr.yandex/crpetiko0nqk7f4hqfl3/docker.io/curlimages/curl:7.78.0
command:
- sh
- -c
- >-
curl -s -X POST -d '{
"channel": "#maintenance-notifications-chaos",
"text": "{{ .Values.somevalue }} chaos testing is carried out.",
...
}' -H 'Content-Type: application/json' https://mindbox.messanger.ru
Тесты собственной разработки
В Chaos Mash есть готовые тесты и сценарии экспериментов для часто встречающихся конфигураций, они подробно описаны в документации. Нам они не подошли, потому что мы используем управляемый Redis, который находится в облаке. Стандартных экспериментов для такой ситуации нет, но в Chaos Mesh есть эксперимент с типом Task, который позволяет выполнять произвольный код. Вот пример, где мы инициируем смену мастера Redis, через такой вызов:
apiVersion: chaos-mesh.org/v1alpha1
kind: Workflow
metadata:
namespace: my-namespace
name: redis-failover-chaostest-staging-workflow-7zdgp
labels:
managed-by: redis-failover-chaostest-staging-workflow
spec:
entry: redis-failover-chaostest
templates:
- name: redis-failover-chaostest-scenarios-common-staging
templateType: Task
task:
container:
name: redis-chaostest
image: cr.yandex/crpo9tj76o3c7pi8i72n/redis-maintenance:1.0.7
args:
- failover
- '-r'
- '-c'
- c9q89rfji5uhvfl95hlv
- '-k'
- $(CHAOS_TEST_REDIS_API_SECRET_KEY)
envFrom:
- secretRef:
name: chaos-test-credentials-staging
resources: {}
# other steps here...Сообщения о сбоях во время тестов
У нас есть два типа сообщений о сбоях — алертов:
Система не работает → клиенты страдают, мы теряем деньги.
Система работает, но что-то деградировало → клиент не страдает, система может восстановиться сама. Если не восстановилась за заданное время, то мы получим алерт, потому что в долгосрочной перспективе ситуация опасна.
Мы не отключаем алерты, когда проводим хаос-тесты, по двум причинам:
тестируем на проде и все еще должны следить за его состоянием;
укладываемся с тестами в рамки времени срабатывания штатных алертов.
Продолжительность тестов настраиваем так, чтобы тестовые события заканчивались раньше, чем сработают алерты второго типа — о деградации. Если система выйдет из стабильного состояния от тестового события, мы получим алерт, если не выйдет — тест пройдет незаметно, а гипотеза подтвердится.
Например, если один из брокеров Kafka действительно отключится и не вернется в работу, мы получим алерт второго типа примерно через полчаса. Поэтому для теста отключения брокера подбираем промежуток времени короче получаса. Если система не сломается, то срабатываний не будет.
Но возможен и другой подход — остановить некоторые алерты на время тестов. Как поступать, зависит от особенностей конкретной системы, универсального рецепта нет.
Этап 4. Анализ результатов и улучшение сервиса
После того, как тесты выполнены, нужно проанализировать результаты и сравнить их с исходной гипотезой эксперимента. Например, мы выловили и исправили до возникновения инцидентов такие ситуаци:
Гипотеза: отказ одного брокера Kafka не влияет на выполнение сценариев.
Реальность: из-за отказа брокера Kafka не обрабатывался перезапуск подов. Min In Sync Replicas был настроен некорректно, из-за этого не создавались топики для пода на старте.
Улучшение: поменяли настройки Min In Sync Replicas.Гипотеза: сетевые задержки до одной из нод Cassandra не влияют на время запросов от приложения.
Реальность: влияют, запрос всегда шел к одной ноде.
Улучшение: настроили механизм Speculative Query Execution.
Внедрение хаос-тестов заняло полтора месяца. В результате мы избавились от нарушений обязательств перед клиентами (SLA) в тех приложениях, которые покрыли тестами. Несколько раз по результатам тестов исправляли дефекты до того, как они повлияли на пользователей.
Кратко повторю, что мы сделали, чтобы внедрить хаос-тесты:
Провели подготовку к внедрению, которая заняла 1,5 недели. За это время определили стабильное состояния системы и подобрали метрики, по которым его отслеживать. Сформулировали гипотезы для экспериментов.
За следующие 4 недели написали тесты, проанализировали результаты и внесли в систему улучшения. Профит!
Полезности по теме
Доклад Дмитрия Баскакова о внедрении хаос-тестов в Mindbox на Yandex Scale 2024.
Подборка видео, репозиториев, статей и материалов по хаос-тестированию из доклада.
Обзор инструментов для хаос-тестирования в двух частях:
Часть 1: kube-monkey, chaoskube, Chaos Mesh.
Часть 2: Litmus Chaos, Chaos Toolkit, KubeInvaders и другие.
