Меня зовут Михаил Новиков, я архитектор в команде, которая развивает один из пользовательских сервисов. В статье расскажу, зачем мы за 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 и другие.