- PVSM.RU - https://www.pvsm.ru -

Chaos Engineering: искусство умышленного разрушения. Часть 3

Прим. перев.: Это продолжение цикла статей от технологического евангелиста из AWS (Adrian Hornsby) про довольно новую ИТ-дисциплину — chaos engineering, — в рамках которой инженеры проводят эксперименты, призванные смягчить последствия сбоев в системах. Первый [1] материал этого цикла рассказывал про концепцию chaos engineering в целом, второй [2] — о том, как эта деятельность способствует позитивным культурным изменениям внутри организаций.

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 1

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

Прим. автора: Хочу выразить искреннюю признательность своему другу Ricardo Sueiras [3] за его вклад в подготовку этой публикации и за то, что он помог мне сдвинуться с мертвой точки. Рикардо, ты крут!

«Мы становимся тем, что лицезреем. Сначала мы формируем свои инструменты, а затем они формируют нас». — Маршалл Маклюэн [4] (канадский философ, прославившийся своими исследованиями в области коммуникаций; первое предложение этой цитаты, впрочем, заимствовано у британского поэта Уильяма Блейка — прим. перев.)

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

«Метод включает в себя внимательное наблюдение, применение строгого скептицизма к предмету наблюдения, учитывая, что сознательные предположения могут исказить интерпретацию наблюдений. Он включает в себя формулировку гипотез при помощи индукции, основанных на этих наблюдениях; экспериментальную и измеримую проверку выводов, следующих из гипотез; а также уточнение (или отказ от) гипотезы в зависимости от результатов экспериментов». — Wikipedia [5]

Хаос-инжиниринг начинается с понимания устойчивого состояния системы. За этим следует формулировка гипотезы и, наконец, проверка и анализ результатов экспериментов ради повышения отказоустойчивости системы.

image
Этапы хаос-инжиниринга

В первой части [1] данной серии статей я изложил концепцию хаос-инжиниринга и рассмотрел каждый шаг процесса, изображенного выше.

Во второй части [6] — рассказал о направлениях, с которых следует начинать разработку экспериментов, и о том, как выбрать правильную гипотезу.

В этой, третьей, части речь пойдет о самих экспериментах. Будет представлена коллекция инструментов и методов, покрывающих широкий спектр возможностей по «внесению неисправностей [7]» (fault injection или failure injection), необходимый для проведения экспериментов хаос-инжиниринга.

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

Внесение неисправностей: что это и зачем?

Внедрение неисправностей в систему позволяет понять и проверить, соответствует ли спецификациям её реакция на стрессовые условия. Впервые эта методика использовалась для провоцирования неисправностей на аппаратном уровне [8] — в частности, на уровне контактов — путём изменения электрических сигналов на устройствах.

В разработке программного обеспечения внесение неисправностей помогает повысить отказоустойчивость системы и устранить потенциально слабые места. Этот процесс получил название «устранение неисправностей» (fault removal). Также он помогает прикинуть потенциальные последствия сбоя — то есть его радиус поражения — ещё до того, как нечто подобное случится в production. Это называется «прогнозированием неисправностей» (failure forecasting).

У внесения неисправностей есть несколько важных плюсов. Оно помогает:

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

Категории неисправностей

Внедрение неисправностей подразделяется на пять категорий:

  1. сбои на уровне ресурсов;
  2. на уровне сети и зависимостей;
  3. на уровне приложений, процессов и сервисов;
  4. на уровне инфраструктуры;
  5. на уровне персонала*.

Далее я рассмотрю каждую категорию и приведу пример внесения неисправности для каждой из них. Кроме того, расскажу о некоторых комплексных инструментах для внесения сбоев и управления ими.

* Примечание: в этой статье не будет рассматриваться внесение неисправностей на уровне персонала. Эту тему затрону в отдельной публикации.

1. Сбои на уровне ресурсов или «исчерпание ресурсов»

Хотя облачные услуги приучили нас к тому, что ресурсы практически безграничны, вынужден вас разочаровать: это не так. Экземпляр, контейнер, функция и т.д. — независимо от уровня абстракции, ресурсы рано или поздно закончатся. Проверкой устойчивости системы, поставленной в условия жесткой нехватки ресурсов, и занимается подход с названием «исчерпание ресурсов» (resource exhaustion [9]).

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 3 [10]

Исчерпание ресурсов обычно выглядит как DoS-атака [11] (правда, не совсем привычная), стремящаяся помешать работе целевого хоста. Это довольно популярный способ внесения неисправностей — возможно, по той причине, что его легко реализовать.

Исчерпание ресурсов CPU, памяти и ввода/вывода

Один из моих любимых инструментов — stress-ng [12], реинкарнация оригинальной утилиты [13], которую разработал Amos Waterland.

С помощью stress-ng можно внедрить неисправности в различные физические подсистемы компьютера, а также в интерфейсы ядра ОС, используя «стрессоры» (stressors). Они доступны для: CPU, кэша CPU, устройств, ввода/вывода, прерываний, файловой системы, памяти, сети, операционной системы, конвейеров, планировщиков, виртуальных машин. Страницы руководства [12] включают полное описание всех доступных стресс-тестов, коих насчитывается целых 220 штук!

Вот несколько полезных примером применения stress-ng:

  • Стресс-тест CPUmatrixprod — предлагает отличное сочетание операций с памятью, кэшем и с плавающей запятой. Пожалуй, является лучшим способом «поджарить» CPU.
    ❯ stress-ng —-cpu 0 --cpu-method matrixprod -t 60s
  • Стресс-тест iomix-bytes пишет N байтов для каждого процесса-worker'а iomix. Значение N по умолчанию равно 1 Гб и идеально подходит для стресс-теста ввода/вывода. В этом примере я указываю 80 % свободного пространства в файловой системе:
    ❯ stress-ng --iomix 1 --iomix-bytes 80% -t 60s
  • vm-bytes идеально подходит для проведения стресс-тестов памяти. В данном примере stress-ng запускает 9 стрессоров виртуальной памяти. Вместе они «съедают» 90 % доступной памяти на один час (каждый стрессор использует 10 % доступной памяти):
    ❯ stress-ng --vm 9 --vm-bytes 90% -t 60s

Исчерпание места на жестких дисках

dd — это утилита для командной строки, созданная для преобразования и копирования файлов. При этом dd может читать (или писать) из специальных файлов устройств, таких как /dev/zero и /dev/random, для задач вроде резервного копирования загрузочного сектора жёсткого диска или получения определенного количества случайной информации. Таким образом, её также можно использовать для внесения неисправности в хост и имитации заполнения диска. Помните, как ваши логи съели всё свободное пространство на сервере и привели к падению приложения? Эта утилита способна помочь, но также и навредить.

Используйте dd чрезвычайно осторожно! Ошибка в команде может стереть, уничтожить или перезаписать данные на жёстком диске!

❯ dd if=/dev/urandom of=/burn bs=1M count=65536 iflag=fullblock &

Исчерпание ресурсов API приложения

Производительность, отказоустойчивость и масштабируемость API имеют большое значение. В самом деле, API позволяют компаниям совершенствовать свои приложения и развивать бизнес.

Нагрузочное тестирование (load testing [14]) — отличная возможность испытать приложение, прежде чем оно попадёт в production. Также это превосходный метод стресс-тестирования, позволяющий выявить проблемы и ограничения, которые в противном случае могли бы проявиться только при реальной нагрузке.

wrk [15] — инструмент для бенчмаркинга HTTP, способный генерировать значительную нагрузку на системы. Мне очень нравится нагружать API для health-check'ов — особенно, если это глубокие проверки [16], поскольку они позволяют многое узнать об архитектурных решениях в проекте: как настроен кэш? Как работает ограничение по частоте? Уделяет ли система приоритетное внимание health-check'ам от балансировщиков нагрузки?

Вот отличная отправная точка:

❯ wrk -t12 -c400 -d20s http://127.0.0.1/api/health

Эта команда запускает 12 потоков и держит открытыми 400 HTTP-подключений в течение 20 секунд.

2. Внедрение неисправностей на уровне сети и зависимостей

Eight Fallacies of Distributed Computing [17] от Peter'а Deutsch'а — это набор из предположений, которыми руководствуются разработчики при проектировании распределённых систем. Однако они часто оборачиваются против них, вызывая перебои в работе системы и заставляя менять её архитектуру. Вот эти предположения:

  • Сеть надёжна.
  • Задержка равна нулю.
  • Пропускная способность безгранична.
  • Сеть безопасна.
  • Топология не меняется.
  • Есть только один администратор.
  • Транспортировка всегда происходит без проблем.
  • Сеть гомогенна.

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

Внедрение задержек, потерь и повреждений сети

tc (traffic control) [18] — это инструмент командной строки для конфигурации планировщика пакетов ядра Linux. Он определяет, как пакеты попадают в очередь для передачи и приёма по сетевому интерфейсу. Возможности включают постановку в очередь, применение политик, классификацию, планирование, шейпинг и отбрасывание.

tc можно использовать для имитации задержки и потери пакетов для UDP- или TCP-приложений, а также для ограничения пропускной способности сети для конкретного сервиса с целью имитировать реальное перемещение трафика в интернете.

— Внедряем задержку в 100 мс:

# Запуск
❯ tc qdisc add dev eth0 root netem delay 100ms

# Остановка
❯ tc qdisc del dev eth0 root netem delay 100ms

— Внедряем задержку в 100 мс с дельтой в 50 мс:

# Запуск
❯ tc qdisc add dev eth0 root netem delay 100ms 50ms

# Остановка
❯ tc qdisc del dev eth0 root netem delay 100ms 50ms

— Имитируем повреждение 5 % сетевых пакетов:

# Запуск
❯ tc qdisc add dev eth0 root netem corrupt 5%

# Остановка
❯ tc qdisc del dev eth0 root netem corrupt 5%

— Имитируем потерю 7 % пакетов с корреляцией в 25 %:

# Запуск
❯ tc qdisc add dev eth0 root netem loss 7% 25%

# Остановка
❯ tc qdisc del dev eth0 root netem loss 7% 25%

Примечание: 7 % позволяют сохранить работоспособность TCP.

Манипуляции с /etc/hosts

/etc/hosts — это простой текстовый файл, сопоставляющий IP-адреса с доменными именами (одна строка на адрес). Для каждого хоста должна быть своя строка со следующей информацией:

IP_адрес каноническое_доменное_имя [алиасы...]

Файл hosts — один из нескольких способов, с помощью которых компьютер сопоставляет сетевые узлы в компьютерной сети и переводит понятные для человека домены в IP-адреса [19]. Как вы уже догадались, он отлично подходит и для запутывания компьютеров. Вот несколько примеров:

— Блокируем доступ к API DynamoDB из экземпляра EC2:

# Запуск
# Копируем /etc/hosts в /etc/host.back
❯ cp /etc/hosts /etc/hosts.back
❯ echo "127.0.0.1 dynamodb.us-east-1.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 dynamodb.us-east-2.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 dynamodb.us-west-1.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 dynamodb.us-west-2.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 dynamodb.eu-west-1.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 dynamodb.eu-north-1.amazonaws.com" >> /etc/hosts
# Остановка
# Возвращаем изначальную версию /etc/hosts
❯ cp /etc/hosts.back /etc/hosts

— Блокируем доступ экземпляра EC2 к API EC2:

# Запуск
# Копируем /etc/hosts в /etc/host.back
❯ cp /etc/hosts /etc/hosts.back
❯ echo "127.0.0.1 ec2.us-east-1.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 ec2.us-east-2.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 ec2.us-west-1.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 ec2.us-west-2.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 ec2.eu-west-1.amazonaws.com" >> /etc/hosts
❯ echo "127.0.0.1 ec2.eu-north-1.amazonaws.com" >> /etc/hosts

# Остановка
# Возвращаем /etc/hosts
❯ cp /etc/hosts.back /etc/hosts

Вот пример работы с этим файлом. Изначально API EC2 доступен, и команда ec2 describe-instances завершается успешно:

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 4

Но как только я добавляю строку 127.0.0.1 ec2.eu-west-1.amazonaws.com в /etc/hosts, вызовы перестают доходить до API EC2:

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 5

Конечно, этот метод работает для всех endpoint'ов AWS.

Я мог бы рассказать анекдот про DNS...

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 6
Идёт обновление кэша DNS…

… только вам потребуется 24 часа, чтобы его понять.

21 октября 2016 году DDoS-атака на Dyn [20] привела к тому, что значительное число интернет-платформ и сервисов оказались недоступны в Европе и Северной Америке. Согласно отчёту ThousandEyes Global DNS Performance [21] за 2018 год, 60 % компаний и SaaS-провайдеров по-прежнему полагаются на один источник DNS и, следовательно, уязвимы перед сбоями DNS. Поскольку без DNS нет и интернета, разумно имитировать падение этой службы, чтобы проверить устойчивость системы к возможному отказу DNS.

Традиционно для борьбы с DDoS-атаками [22] используется така называемый blackholing — метод, в котором «плохой» сетевой трафик отправляется прямиком в «чёрную дыру» и выбрасывается в пустоту (этакая сетевая версия /dev/null). Можно воспользоваться им для имитации потери сетевого трафика или отказа протокола, например, службы DNS [23].

С этой работой прекрасно справится iptables [24]. Эта утилита используется для настройки, обслуживания и анализа таблиц с правилами фильтрации IP-пакетов в ядре Linux.

Чтобы отправить DNS-трафик в «чёрную дыру», попробуйте сделать следующее:

# Запуск
❯ iptables -A INPUT -p tcp -m tcp --dport 53 -j DROP
❯ iptables -A INPUT -p udp -m udp --dport 53 -j DROP

# Остановка
❯ iptables -D INPUT -p tcp -m tcp --dport 53 -j DROP
❯ iptables -D INPUT -p udp -m udp --dport 53 -j DROP

Внесение неисправностей с помощью Toxiproxy

Один из главных недостатков инструментов под Linux, таких как tc и iptables, состоит в том, что они требуют root-привилегий для своей работы, что может быть проблематично для некоторых организаций и ситуаций. В этом случае на выручку придет Toxiproxy!

Toxiproxy [25] — это TCP-прокси с открытым исходным кодом, разработанный инженерной командой Shopify [26]. Он помогает имитировать хаотические сетевые и системные условия из реальной жизни. Для этого достаточно поместить Toxiproxy между компонентами инфраструктуры, как показано на иллюстрации ниже:

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 7
Слайд из выступления [27] Simon'а Eskildsen'а, главы команды production-разработки, Shopify

Этот инструмент специально разработан для окружений с тестами, CI и разработкой, он поддерживает детерминированный или рандомизированный хаос, а также кастомизацию. Toxiproxy манипулирует соединением между клиентом и upstream'ом с помощью так называемых «токсиков» (toxics [28]) и поддерживает настройку через HTTP API [29]. Кроме того, инструмент поставляется с набором предустановленных токсиков.

В примере ниже показывается, как Toxiproxy с помощью downstream-токсика увеличивает задержку на 1000 мс между клиентом Redis, redis-cli и самой Redis:

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 8

Начиная с октября 2014 года Toxiproxy с успехом используется во всех development- и test-средах в Shopify. Подробности о Toxiproxy можно узнать из этой записи в блоге [30].

3. Внедрение сбоев на уровне приложения, процесса и сервиса

Программы падают. Это общеизвестный факт. Что делать, если произошел сбой? Следует ли зайти на сервер по SSH и перезапустить упавший процесс? Системы контроля процессов позволяют следить за состоянием процесса или изменять его с помощью таких директив, как start, stop, restart. Эти системы обычно реализуются для постоянного контроля за процессом. Одним из таких инструментов является systemd [31]. Он обеспечивает базовый набор методов для управления процессами в Linux. Supervisord [32] предлагает аналогичный функционал для UNIX-подобных операционных систем.

Эти инструменты следует использовать при деплое приложений. Конечно, прежде всего надо изучить последствия от падений критических процессов. Убедитесь, что получаете соответствующие уведомления, а процессы перезапускаются в автоматическом режиме:

— «Убийство» Java-процессов:

❯ pkill -KILL -f java
# Альтернативный способ
❯ pkill -f 'java -jar'

— «Убийство» процессов Python:

❯ pkill -KILL -f python

Конечно, с помощью pkill можно убить практически любой процесс в системе.

Внесение сбоев в базы данных

Если и есть сбои, жалобы на которые терпеть не может поддержка, так это те, которые имеют отношение к базам данных. Данные ценятся на вес золота, и всякий раз, когда происходит сбой в БД, возрастает риск потери данных клиентов.

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 9

В некоторых случаях способность как можно быстрее восстановить данные и вернуть систему в работоспособное состояние может определить судьбу компании. К сожалению, подготовиться ко всему разнообразию сбоев баз данных непросто, и многие из них проявляются только в production.

Впрочем, если вы используете Amazon Aurora [33], то можете проверить отказоустойчивость кластера баз данных Amazon Aurora путем специальных запросов с внедрением ошибок [34].

Внедрение сбоев в Amazon Aurora

Запросы со сбоями в виде SQL-команд направляются экземпляру Amazon Aurora и позволяют запланировать «возникновение» одного из следующих событий:

  • падение читающего (reader) или пишущего (writer) экземпляра БД;
  • сбой реплики Aurora;
  • выход диска из строя;
  • сбой диска с пометкой случайных сегментов как переполненных (congested).

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

— Падение экземпляра Amazon Aurora:

ALTER SYSTEM CRASH [ INSTANCE | DISPATCHER | NODE ];

— Имитация отказа реплики Aurora:

ALTER SYSTEM SIMULATE percentage PERCENT READ REPLICA FAILURE
[ TO ALL | TO "replica name" ]
FOR INTERVAL quantity { YEAR | QUARTER | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND };

— Имитация выхода из строя диска в кластере с БД Aurora:

ALTER SYSTEM SIMULATE percentage PERCENT DISK FAILURE
[ IN DISK index | NODE index ]
FOR INTERVAL quantity { YEAR | QUARTER | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND };

— Имитация повышенной загрузки диска в кластере с БД Aurora:

ALTER SYSTEM SIMULATE percentage PERCENT DISK CONGESTION
BETWEEN minimum AND maximum MILLISECONDS
[ IN DISK index | NODE index ]
FOR INTERVAL quantity { YEAR | QUARTER | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND };

Сбои в serverless-мире

Внедрять сбои может быть непросто, если вы используете serverless-компоненты, поскольку управляемые serverless-сервисы вроде AWS Lambda изначально не поддерживают внесение неисправностей.

Внедряем сбои в функции Lambda

Чтобы решить эту проблему, я написал небольшую библиотеку на Python [35] и лямбда-слой [36] для внедрения сбоев в AWS Lambda [37]. Оба в настоящее время поддерживают задержки, ошибки, исключения и внедрение кодов ошибок HTTP.

Само внесение неисправностей осуществляется путём задания следующих параметров в AWS SSM Parameter Store [38]:

{
   "isEnabled": true,
   "delay": 400,
   "error_code": 404,
   "exception_msg": "I really failed seriously",
   "rate": 1
}

Можно добавить декоратор Python в функцию-обработчик для внедрения неисправности.

— Вызываем исключение:

@inject_exception
def handler_with_exception(event, context):
    return {
        'statusCode': 200,
        'body': 'Hello from Lambda!'
    }
>>> handler_with_exception('foo', 'bar')
Injecting exception_type <class "Exception"> with message I really failed seriously a rate of 1
corrupting now
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/.../chaos_lambda.py", line 316, in wrapper
       raise _exception_type(_exception_msg)
Exception: I really failed seriously

— Внедряем неправильный код ошибки HTTP:

@inject_statuscode
def handler_with_statuscode(event, context):
    return {
        'statusCode': 200,
        'body': 'Hello from Lambda!'
    }
>>> handler_with_statuscode('foo', 'bar')
Injecting Error 404 at a rate of 1
corrupting now
{'statusCode': 404, 'body': 'Hello from Lambda!'}

— Внедряем задержку:

@inject_delay
def handler_with_delay(event, context):
    return {
        'statusCode': 200,
        'body': 'Hello from Lambda!'
    }>>> handler_with_delay('foo', 'bar')
Injecting 400 of delay with a rate of 1
Added 402.20ms to handler_with_delay
{'statusCode': 200, 'body': 'Hello from Lambda!'}

Чтобы узнать больше об этой Python-библиотеке, перейдите по ссылке [35].

Вмешиваемся в работу Lambda, устанавливая лимит concurrency

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

❯ aws lambda put-function-concurrency --function-name <value> --reserved-concurrent-executions 0

Эта команда установит concurrency на нуль, вынуждая запросы завершаться с ошибкой 429 («слишком много запросов»).

Thundra — отслеживаем serverless-транзакции

Этот инструмент для наблюдения за serverless-архитектурой обладает встроенной возможностью внедрять неисправности в serverless-приложения. Thundra [39] использует так называемые span listeners [40] для внедрения сбоев, таких как отсутствие обработчика ошибок для DynamoDB, отсутствие резервного источника данных или отсутствие таймаута для исходящих HTTP-запросов. Я сам не пользовался этим инструментом, однако эта публикация [41] от Yan Cui [42] и это замечательное видео [43] от Marcia Villalba [44] прекрасно описывают процесс работы. Исходя из них, Thundra выглядит многообещающе.

Подводя черту под serverless-разделом, хочу порекомендовать всем отличную статью [45] о сложностях хаос-инжиниринга в serverless-приложениях, которую написал уже упомянутый Yan Cui.

4. Внесение неисправностей на уровне инфраструктуры

Хаос-инжиниринг начинался в инъекции сбоев на уровне инфраструктуры — как в случае Amazon, так и в случае Netflix [1]. Пожалуй, инфраструктурные сбои: от отключения целого ЦОД и до случайной остановки экземпляров — реализовать проще всего.

И, естественно, первым на ум приходит пример с chaos monkey [46].

Случайная остановка экземпляра EC2 в зоне доступности

На заре своего существования Netflix озаботился разработкой и внедрением правильного подхода к архитектурным решениям. Chaos monkey стала одним из первых приложений, развернутых в AWS, которое следило на состоянием автомасштабируемых stateless-микросервисов. Другими словами, любой экземпляр мог быть остановлен и автоматически заменен без потери состояния. Chaos monkey следила за тем, чтобы никто не нарушал это правило.

Следующий скрипт — по аналогии с хаос-обезьянкой — случайным образом выбирает и останавливает экземпляр в определенной зоне доступности внутри региона:

❯ stop_random_instance(az="eu-west-1a", tag_name="chaos", tag_value="chaos-ready", region="eu-west-1")

stop-random-instance.py

import boto3
import random

REGION = 'eu-west-1'


def stop_random_instance(az, tag_name, tag_value, region=REGION):
    '''
    >>> stop_random_instance(az="eu-west-1a", tag_name='chaos', tag_value="chaos-ready", region='eu-west-1')
    ['i-0ddce3c81bc836560']
    '''
    ec2 = boto3.client("ec2", region_name=region)
    paginator = ec2.get_paginator('describe_instances')
    pages = paginator.paginate(
        Filters=[
            {
                "Name": "availability-zone",
                "Values": [
                    az
                ]
            },
            {
                "Name": "tag:" + tag_name,
                "Values": [
                    tag_value
                ]
            }
        ]
    )
    instance_list = []
    for page in pages:
        for reservation in page['Reservations']:
            for instance in reservation['Instances']:
                instance_list.append(instance['InstanceId'])
    print("Going to stop any of these instances", instance_list)
    selected_instance = random.choice(instance_list)
    print("Randomly selected", selected_instance)
    response = ec2.stop_instances(InstanceIds=[selected_instance])
    return response

(gist для stop-random-instance.py [47])

Обратите внимание на tag_name и tag_value. Подобные маленькие хитрости помогают предотвратить отключение «не того» экземпляра. #lessonlearned

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 10
— «Да, было бы классно, если бы вы перезапустили базу…» — Упс, не тот экземпляр...

5. Комплексные инструменты для оркестрации и внесения неисправностей

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

Chaos Toolkit

Chaos Toolkit [48] — один из моих любимейших инструментов подобного рода. Это целая Open Source-платформа для хаос-инжиниринга, поддерживаемая (на коммерческой основе) прекрасной командой ChaosIQ, [49] включающей в числе прочих Russ Miles [50], Sylvain Hellegouarch [51] и Marc Perrien [52].

Chaos Toolkit предлагает декларативный и расширяемый открытый API для экспериментов по организации хаоса. Он включает в себя драйверы для AWS, Google Cloud Engine, Microsoft Azure, Cloud Foundry, Humio, Prometheus и Gremlin.

Расширения — это набор тестов и последовательностей действий для организации различных экспериментов — например, для случайной остановки экземпляров в определенной зоне доступности, если значение tag-key равно chaos-ready.

stop-random-instance-exp.json

{
    "version": "1.0.0",
    "title": "What is the impact of randomly terminating an instance in an AZ",
    "description": "terminating EC2 instance at random should not impact my app from running",
    "tags": ["ec2"],
    "configuration": {
        "aws_region": "eu-west-1"
    },
    "steady-state-hypothesis": {
        "title": "more than 0 instance in region",
        "probes": [
            {
              "provider": {
                "module": "chaosaws.ec2.probes",
                "type": "python",
                "func": "count_instances",
                "arguments": {
                  "filters": [
                    {
                        "Name": "availability-zone",
                        "Values": ["eu-west-1c"]
                    }
                  ]
                }
              },
              "type": "probe",
              "name": "count-instances",
              "tolerance": [0, 1]
            }
        ]
    },
    "method": [
        {
            "type": "action",
            "name": "stop-random-instance",
            "provider": {
                "type": "python",
                "module": "chaosaws.ec2.actions",
                "func": "stop_instance",
                "arguments": {
                    "az": "eu-west-1c"
                },
               "filters": [
                    {
                        "Name": "tag-key",
                        "Values": ["chaos-ready"]
                    }
                ]
            },
            "pauses": {
               "after": 60
             }
        }
    ],
    "rollbacks": [
        {
            "type": "action",
            "name": "start-all-instances",
            "provider": {
                "type": "python",
                "module": "chaosaws.ec2.actions",
                "func": "start_instances",
                "arguments": {
                "az": "eu-west-1c"
                 },
               "filters": [
                    {
                        "Name": "tag-key",
                        "Values": ["chaos-ready"]
                    }
                ]
            }
        }
    ]
}

(gist для stop-random-instance-exp.json [53])

Запустить этот эксперимент просто:

❯ chaos run experiment_aws_random_instance.json

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 11

Преимущество Chaos Toolkit, во-первых, в открытых исходниках (поэтому его легко приспособить для конкретных потребностей). Во-вторых, он прекрасно интегрируется в CI/CD-пайплайн и поддерживает непрерывное хаос-тестирование.

Недостатком Chaos Toolkit'а является его сложность: чтобы начать работать, необходимо разобраться в его особенностях и принципах. Более того, в Toolkit'е нет готовых экспериментов: придётся написать свои собственные. Впрочем, команда ChaosIQ активно работает над устранением этого недостатка.

Gremlin

Другой мой любимый инструмент — Gremlin — включает в себя полный набор режимов внесения неисправностей в простой и удобной для использования форме с интуитивно понятным пользовательским интерфейсом — этакий вариант Chaos-as-a-Service.

Gremlin обеспечивает внедрение ошибок в ресурсы [54], состояния [55], сеть [56] и запросы [57], позволяя экспериментировать с различными частями системы. Он поддерживает bare metal, различных поставщиков облачных услуг, контейнерные среды (включая Kubernetes*), приложения и (в некоторой степени) serverless-вычисления.

* Прим. перев.: Подробнее об использовании Gremlin в контексте Kubernetes (и не только) можно прочитать, например, в этой статье [58].

Бонусом идет отличный контент в блоге проекта [59]. Кроме того, ребята из Gremlin по-настоящему круты и всегда готовы прийти на выручку! Прежде всего это Matthew [60], Kolton [61], Tammy [62], Rich [63], Ana [64] и HML [65].

Работать с Gremlin'ом весьма просто.

Войдите в приложение и выберите Create Attack:

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 12

Выберите целевой экземпляр:

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 13

Выберите тип неисправности, которую хотите внедрить, и выпустите (unleash) маленького гремлина на свободу!

Chaos Engineering: искусство умышленного разрушения. Часть 3 - 14

Должен признать, что всегда любил Gremlin, поскольку он делает хаос-экспериментирование простым и понятным.

Недостатком, на мой взгляд, является ценообразование [66]. Оно не слишком подходит новичкам или для эпизодического (on-demand) использования из-за своей лицензии. Впрочем, недавно появилась бесплатная версия. Другим минусом Gremlin'а является необходимость устанавливать клиента и демона в экземпляры, которые станут целями атаки, что по душе далеко не всем.

Run Command в AWS System Manager

Сервис EC2 Run Command [67], представленный в 2015 году, был создан для безопасного и простого администрирования экземпляров EC2. Сегодня он позволяет удаленно и безопасно управлять конфигурацией экземпляров не только типа EC2, но и из гибридных окружений [68]. К ним относятся on-premises-серверы, виртуальные машины и даже ВМ в других облачных окружениях, используемых с Systems Manager.

Run Command позволяет автоматизировать DevOps-задачи или проводить обновления конфигурации независимо от размера вашего парка.

Run Command преимущественно используется для таких задач, как установка и bootstrapping приложений, захват логов или присоединение экземпляров к домену Windows, однако он также хорошо подходит для проведения хаос-экспериментов.

У меня есть запись в блоге [69], посвященная внедрению хаоса с помощью AWS System Manager, а также готовые исходники [70] для экспериментов. Попробуйте — уверен, вам понравится!

Закругляюсь!

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

  1. Смысл хаос-инжиниринга не в том, чтобы ломать что-то в production. Это целое путешествие. Путешествие к знанию, получаемому путем проведения экспериментов в контролируемой среде — любой среде, будь то локальное окружение для разработки, beta, staging или production. Это путешествие может начаться где угодно! Об этом прекрасно сказала Olga Hall [71]:

    «Цените хаос независимо от обстоятельств. Найдите для него место в своём путешествии». — Olga Hall, старший менеджер команды Resilience Engineering в Amazon Prime Video.

  2. Прежде чем внести неисправность, помните, что необходимо иметь наготове соответствующие мониторинг и алерты. Без них вы не сможете оценить влияние экспериментов с хаосом или измерить радиус поражения — два критически важных компонента в практике хаос-инжиниринга.
  3. Некоторые из описанных методов могут нанести серьёзный урон, поэтому соблюдайте осторожность и проводите начальные испытания на тестовых экземплярах, от падения которых не пострадают реальные клиенты.
  4. Наконец, тестируйте, пробуйте, испытывайте, а затем повторяйте всё снова. Помните, что цель хаос-инжиниринга — выработать уверенность в способности вашего приложения (и инструментов) пережить турбулентные условия эксплуатации.

На этом всё. Спасибо, что дочитали до конца! Надеюсь, вам понравилась третья часть. Жду от вас мнений, комментариев и, конечно, хлопков в ладоши (на Medium [72] — прим. перев.)!

P.S. от переводчика

Читайте также в нашем блоге:

Автор: Андрей Сидоров

Источник [74]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/testirovanie-it-sistem/340545

Ссылки в тексте:

[1] Первый: https://habr.com/ru/company/flant/blog/460367/

[2] второй: https://habr.com/ru/company/flant/blog/465107/

[3] Ricardo Sueiras: https://medium.com/@094459

[4] Маршалл Маклюэн: https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%BA%D0%BB%D1%8E%D1%8D%D0%BD,_%D0%9C%D0%B0%D1%80%D1%88%D0%B0%D0%BB%D0%BB

[5] Wikipedia: https://en.wikipedia.org/wiki/Scientific_method

[6] второй части: https://habr.com/en/company/flant/blog/465107/

[7] внесению неисправностей: https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D1%81%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B5%D0%B8%D1%81%D0%BF%D1%80%D0%B0%D0%B2%D0%BD%D0%BE%D1%81%D1%82%D0%B5%D0%B9

[8] провоцирования неисправностей на аппаратном уровне: https://ieeexplore.ieee.org/document/780999/

[9] resource exhaustion: https://en.wikipedia.org/wiki/Resource_exhaustion_attack

[10] Image: https://xkcd.ru/676/

[11] DoS-атака: https://ru.wikipedia.org/wiki/DoS-%D0%B0%D1%82%D0%B0%D0%BA%D0%B0

[12] stress-ng: https://www.mankier.com/1/stress-ng

[13] оригинальной утилиты: https://directory.fsf.org/wiki/Stress

[14] load testing: https://ru.wikipedia.org/wiki/%D0%9D%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BE%D1%87%D0%BD%D0%BE%D0%B5_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5

[15] wrk: https://github.com/wg/wrk

[16] глубокие проверки: https://medium.com/@adhorn/patterns-for-resilient-architecture-part-3-16e8601c488e

[17] Eight Fallacies of Distributed Computing: https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing

[18] tc (traffic control): http://tldp.org/HOWTO/Traffic-Control-HOWTO/intro.html

[19] IP-адреса: https://ru.wikipedia.org/wiki/IP-%D0%B0%D0%B4%D1%80%D0%B5%D1%81

[20] DDoS-атака на Dyn: https://en.wikipedia.org/wiki/2016_Dyn_cyberattack

[21] отчёту ThousandEyes Global DNS Performance: https://www.thousandeyes.com/resources/2018-global-dns-performance-benchmark-report

[22] DDoS-атаками: https://en.wikipedia.org/wiki/Denial-of-service_attack

[23] службы DNS: https://ru.wikipedia.org/wiki/DNS

[24] iptables: https://linux.die.net/man/8/iptables

[25] Toxiproxy: https://github.com/shopify/toxiproxy

[26] инженерной командой Shopify: https://engineering.shopify.com/

[27] выступления: https://atscaleconference.com/videos/resiliency-testing-with-toxiproxy/

[28] toxics: https://github.com/shopify/toxiproxy#toxics

[29] HTTP API: https://github.com/shopify/toxiproxy#http-api

[30] этой записи в блоге: https://shopifyengineering.myshopify.com/blogs/engineering/building-and-testing-resilient-ruby-on-rails-applications

[31] systemd: https://en.wikipedia.org/wiki/Systemd

[32] Supervisord: http://supervisord.org/introduction.html#overview

[33] Amazon Aurora: https://aws.amazon.com/rds/aurora/

[34] специальных запросов с внедрением ошибок: https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Managing.FaultInjectionQueries.html

[35] библиотеку на Python: https://github.com/adhorn/aws-lambda-chaos-injection

[36] лямбда-слой: https://github.com/adhorn/aws-lambda-layer-chaos-injection

[37] AWS Lambda: https://aws.amazon.com/lambda/

[38] AWS SSM Parameter Store: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html

[39] Thundra: https://www.thundra.io/

[40] span listeners: https://docs.thundra.io/docs/python-span-listeners

[41] эта публикация: https://blog.thundra.io/chaos-test-your-lambda-functions-with-thundra

[42] Yan Cui: https://twitter.com/theburningmonk

[43] это замечательное видео: https://www.youtube.com/watch?v=TpoN1wm2bok

[44] Marcia Villalba: https://twitter.com/mavi888uy

[45] отличную статью: https://hackernoon.com/how-can-we-apply-the-principles-of-chaos-engineering-to-aws-lambda-80f87e3237e2

[46] chaos monkey: https://github.com/Netflix/chaosmonkey

[47] gist для stop-random-instance.py: https://gist.github.com/adhorn/dbb0350dcd2cbf6301538a977e3910f6#file-stop-random-instance-py

[48] Chaos Toolkit: https://github.com/chaostoolkit

[49] ChaosIQ,: https://chaosiq.io/

[50] Russ Miles: https://twitter.com/russmiles

[51] Sylvain Hellegouarch: https://twitter.com/lawouach

[52] Marc Perrien: https://twitter.com/mperrien

[53] gist для stop-random-instance-exp.json: https://gist.github.com/adhorn/b13d3a80d0a9deeffb925c1dc7f5204e#file-stop-random-instance-exp-json

[54] ресурсы: https://www.gremlin.com/docs/infrastructure-layer/attacks/#resource-gremlins

[55] состояния: https://www.gremlin.com/docs/infrastructure-layer/attacks/#state-gremlins

[56] сеть: https://www.gremlin.com/docs/infrastructure-layer/attacks/#network-gremlins

[57] запросы: https://www.gremlin.com/docs/application-layer/attacks

[58] этой статье: https://medium.com/better-practices/chaos-d3ef238ec328

[59] блоге проекта: https://www.gremlin.com/blog/

[60] Matthew: https://twitter.com/callmeforni

[61] Kolton: https://twitter.com/KoltonAndrus

[62] Tammy: https://twitter.com/tammybutow

[63] Rich: https://twitter.com/richburroughs

[64] Ana: https://twitter.com/Ana_M_Medina

[65] HML: https://twitter.com/HoReaL

[66] ценообразование: https://www.gremlin.com/pricing/

[67] EC2 Run Command: https://aws.amazon.com/blogs/aws/new-ec2-run-command-remote-instance-management-at-scale/

[68] гибридных окружений: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-managedinstances.html

[69] запись в блоге: https://medium.com/@adhorn/injecting-chaos-to-amazon-ec2-using-amazon-system-manager-ca95ee7878f5

[70] готовые исходники: https://github.com/adhorn/chaos-ssm-documents

[71] Olga Hall: https://twitter.com/ovhall

[72] Medium: https://medium.com/@adhorn/chaos-engineering-part-3-61579e41edd8

[73] Мониторинг и Kubernetes (обзор и видео доклада): https://habr.com/ru/company/flant/blog/412901/

[74] Источник: https://habr.com/ru/post/477994/?utm_source=habrahabr&utm_medium=rss&utm_campaign=477994