Концепция Chaos Engineering, или управления хаосом в инфраструктуре, начала набирать популярность в 2010-м. Нагрузка на проекты все росла, и в ответ на рост и усложнение вызовов усложнялась архитектура. Примерно в это время разработчики Netflix подумали, что было бы неплохо проверять, как инфраструктура реагирует на случайные, но запрограммированные ошибки на разных уровнях.

 
На тот момент Chaos Engineering был неизвестной территорией, на которой что-то делали только большие компании и некоторые энтузиасты. Сегодня, если мы строим решение в облаке, без Chaos Engineering создать реально избыточную и отказоустойчивую инфраструктуру становится все сложнее. Все чаще доносятся утверждения о том, что Chaos Engineering — это механизм, который предлагает значительную помощь в выявлении «известных неизвестностей» (вещей, о которых мы в курсе, но не всегда понимаем, как они работают) или «неизвестных неизвестностей» (самых опасных для инфраструктуры и приложения — вещей, о которых мы и не знаем и которые не понимаем).

Как следствие, появился достойный инструментарий, позволяющий быстро начать работать с концепцией Chaos Engineering буквально за 5 минут. 

В этой статье мы посмотрим, какие задачи стоят перед Chaos Engineering, а также запустим эксперимент, то есть ситуацию, в которой будет автоматически создаваться аварийная ситуация, на примере Managed Kubernetes в VK Cloud. Но перед этим порассуждаем, как создать из этого не разовую историю, а процесс, и где место этого процесса в современной компании.

Современная ИТ-система должна реагировать на внешние вызовы

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

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

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

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

Поскольку условия постоянно меняются, мы не можем подходить к ним с позиции классических решений и должны применять гибкие подходы и устраивать эксперименты. Облачные платформы помогают решать эти проблемы за счет эластичности (гибкого выделения ресурсов по запросу), надежности и модели оплаты по факту использования. Однако, когда мы мигрируем в облако либо проектируем наше приложение под использование всей мощи облачных инструментов (балансирования нагрузки, автомасштабирования и многих других) в рамках подхода Cloud Native, мы сталкиваемся с тем, что системы могут вести себя некорректно. 

Вроде бы каждый компонент замечательно протестирован и отлажен в работе с другими. Мы знаем, чего ожидать от каждого из микросервисов, платформ вроде Kubernetes или внешних сервисов, которые реализуют рутинные задачи, например Mail-сервера. Но в постоянно меняющихся внешних условиях, влияющих на нашу систему, не так просто понять, как будет вести себя один компонент при нестандартном поведении другого. Бывает и Dependency Hell, когда всего так много, что понять, что происходит и как это эффективно поддерживать, становится сложно и очень дорого. Причину сбоя в таких условиях найти сложно, а в продакшене — дорого.

Разработка современной ИТ-системы — это поиск компромиссов и оценка факторов влияния

Поиск золотой середины между количеством трудозатрат и потенциальными финансовыми потерями — часть концепции надежности сервиса (Service Reliability). Так как идеальных систем не существует, что-то все равно будет выходить из строя или тормозить. Однако мы должны четко понимать, что имеем в виду под выходом из строя и скоростью работы. В какой-то момент мы обязательно окажемся в ситуации, в которой «снижение» латентности внутри наших систем потребует выполнения такого количества задач или их сложности, которое будет слишком дорогим и долгим. 

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

Chaos Engineering как процесс

Сложно однозначно сказать, когда должен начинаться этот процесс. Кто-то думает, что его нужно интегрирован в DevOps. Кто-то — что практики управления хаосом следует внедрять в самом начале проектирования системы, чтобы сразу создать понимание и метрики для будущей работы с ошибками. По мере наращивания инструментария его все чаще включают в CI/CD-пайплайн. У процесса управления хаосом есть и научная, или исследовательская составляющая. Управление хаосом позволяет стать ближе к пониманию стабильного состояния системы, проверить гипотезы, выстроить связку с Service Level Objectives и SLA и включить эффективные проверенные способы восстановления после ошибок в регламенты и обучение сотрудников.

Дополнительную сложность в управление хаосом вносит интерпретация результатов. Если мы проводим эксперименты сразу на нескольких уровнях, например выбиваем поды в Kubernetes и добавляем «шум» на сетевом уровне, как правильно толковать то, что получилось? 

Здесь важно понимать особенности архитектуры и имплементации того, что мы тестируем. Например, API Server Kubernetes может начать троттлить запросы в ответ на большое их количество, что тоже можно назвать управлением хаосом. Почему он это делает? Потому что не справляется сам или не справляется, например, etcd? Сложно сказать, придет ли индустрия когда-то к универсальным практикам, которые будут в хоть какой-то мере покрывать сценарии управления хаосом в экосистемном подходе, а не в выпуклых случаях: выбили 10 подов из 11 — они восстановились за 1 минуту.

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

Облачные платформы позволяют получить стенд быстро, отработать эксперимент, посмотреть на реакцию системы, выключить стенд и прекратить платить, внести изменения, переразвернуть и повторить все заново. Гибкость облачных платформ позволяет разворачивать несколько стендов с разными версиями и проводить сравнительное тестирование.

Управляем хаосом в Managed Kubernetes в VK Cloud

На данный момент у нас есть богатый набор инструментов для Chaos Engineering, который отличается в основном доступным набором экспериментов, уровнем интеграции внутрь тестируемой платформы и субъективным опытом удобства использования.

Я покажу на примере Chaos-mesh.

Установим helm.

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
helm repo add chaos-mesh https://charts.chaos-mesh.org

Подготовим кластер. Я ставлю сам компонент в отдельный Namespace, это обычная практика, так удобнее. 

kubectl create ns chaos-testing

Ставим Chaos-mesh.

helm install chaos-mesh chaos-mesh/chaos-mesh -n=chaos-testing --version 2.3.1

Проверяем, что все работает.

kubectl get pods --namespace chaos-testing -l
app.kubernetes.io/instance=chaos-mesh

Мы готовы к выполнению эксперимента. Yaml-файл поможет нам в этом: 

apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
  name: pod-failure-example1
  namespace: default
spec:
  action: pod-failure
  mode: one
  duration: '10s'
  selector:
   labelSelectors:
    'run': 'redis-pod'

Chaos-mesh следует аккуратному и понятному формату описания эксперимента в разделе Spec. Каждые 10 секунд в рамках этого эксперимента он будет выбивать один под из Namespace Default с селектором Redis-pod.

Kubectl apply -f experiment.yaml

И уже через 10 секунд можно увидеть результат работы:

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

В Chaos-mesh доступно множество других экспериментов на самом разном уровне. В этом примере мы выбили поды. Другой эксперимент может выбивать под и в это же время устраивать хаос на уровне сети или IO. Все подробно и аккуратно описано в документации Chaos-mesh.

Если же Chaos-mesh по какой-то причине не подходит, то написаны уже десятки других хороших инструментов: Litmus, chaosblade, ChaosToolkit (использующий JSON), PowerfulSeal.

Заключение

В этой статье мы ступили одной ногой на неизвестную территорию, которую индустрия только начинает осваивать. Мы планируем описывать эту тему и дальше, так как верим, что осознанное изучение того, как реагируют компоненты нашей системы в ответ на разные условия и как быстро система приходит в равновесие с помощью инструментов и процессов, является важным шагом вперед в развитии любой современной ИТ-системы.