Проведение экспериментов в IT-инфраструктуре стало важной практикой для повышения надежности и устойчивости систем. Пользователи ожидают мгновенного отклика и безотказной работы приложений, и даже небольшие перебои могут привести к потере репутации и значительным финансовым убыткам.
Я Александр Волков — QA Lead в Сloud.ru. В статье на примере демосервиса онлайн-магазина покажу, как мы применили практики хаос-инжиниринга, проверили поведение нашей системы при сбоях, оценили ее отказоустойчивость и в итоге выработали стратегии для улучшения архитектуры.
Перед проведением эксперимента и внедрением хаоса в нашу систему, нужно было четко определить цели и ожидаемые результаты. В этой статье я расскажу только про основные этапы. Подробнее о том, как мы проводили тесты отказоустойчивости, и обо всех шагах и нюансах на пути, расскажет моя коллега Екатерина Ильина во второй части статьи — не пропустите.
Что и зачем мы решили сделать
Итак, основное, для чего мы решили внедрить хаос — это тестирование поведения системы при отказе одного из критических сервисов или сразу нескольких, а также для последующего уменьшения влияния этих отказов на ключевые пользовательские сценарии.
Первый эксперимент решили провести на демосервисе онлайн-магазина. Взять один из ключевых компонентов, работа которого влияет на значимые пользовательские сценарии — сервис Корзины (Cart), чтобы посмотреть, как ее отказ повлияет на работу системы и как это отразится на других компонентах.
Наш инструментарий
Прежде чем внедрять у себя на проектах практики хаос-инжиниринга, мы обратились к опыту коллег как внутри компании, так и за ее пределами. На Хабре уже есть несколько статей про эту дисциплину, как и обзор различных инструментов хаос-инжиниринга, например: статья 1, статья 2, статья 3.
После изучения существующих инструментов появилось желание попробовать для своих сервисов Chaos Mesh — свой непредвзятый выбор мы остановили на нем.
В Chaos Mesh можно выделить три ключевых компонента:
Chaos Dashboard
Chaos Controller Manager
Chaos Daemon
Интереснее всего для нас было попробовать Chaos Controller Manager — он позволяет управлять инъекциями и контролировать их выполнение, а также отвечает за:
запуск и остановку экспериментов;
оркестрацию выполнения инъекций;
определение области воздействия: Kubernetes API Server, Chaos Daemon или внешние ChaosD-агенты.
Эксперимент первый: сбой Корзины
Основная цель эксперимента — проверить, как наш онлайн-магазин справится с недоступностью ключевого сервиса — Корзины. Корзина — важная часть покупательского опыта, и ее сбой может существенно повлиять на общую работоспособность системы. Наша гипотеза заключалась в том, что при недоступности Корзины остальные сервисы нашего онлайн-магазина останутся доступны.
Мы создали манифест, который включает все необходимые параметры: селекторы, временные рамки выполнения и описание воздействия. Манифест выполняет подмену образа сервиса корзины на специальный тестовый образ, который имитирует недоступность сервиса в течение заданного времени.
После подготовки манифеста мы запустили эксперименты через Chaos Controller Manager. На первом этапе контроллер проверил параметры и область воздействия, а затем инициировал инъекцию. Инъекция попала в Kubernetes API Server благодаря патч-реквестам для модификации образа подов сервиса Корзины. Выглядит это вот так:
Результаты и наблюдения
В ходе эксперимента мы прошли путь пользователя и увидели, что:
страницы с товарами загружаются,
можно переходить в карточки товара, но при попытке добавить их в Корзину возникает ошибка 500.
Количество ошибок нарастает, что постепенно приводит к полной недоступности функционала Корзины, а затем и всего приложения. Вот такая картина была в UI демосервиса:
Мы провели анализ в режиме реального времени через систему мониторинга и вот что заметили:
Небольшие отклонения в системных метриках, что говорит о начальном воздействии на ресурсы кластера:
Резкий рост пользовательских ошибок, который мы зафиксировали с помощью мониторинга. Мы обнаружили, что сбой в работе корзины повлиял и на доступность всего онлайн-магазина:
Таким образом наша гипотеза о том, что остальная часть приложения останется функциональной при сбое Корзины, не подтвердилась. Магазин оказался полностью недоступным, что выявило слабое место в архитектуре системы и ее деградации.
Уроки и дальнейшие шаги
Мы не стали расстраиваться, что эксперимент не удался — напротив, теперь понимали, какие конкретно аспекты требуют доработки. В итоге выделили три направления:
Оптимизация архитектуры — решили разбить сервис Корзины на несколько независимых нод и разместить их в различных зонах доступности для повышения отказоустойчивости.
Обработка ошибок на уровне кода — вместо каскадного сбоя решили информировать пользователей о временной недоступности Корзины и предлагать им продолжать просмотр товаров, выдавая небольшое уведомление и не ограничивая дальнейшее взаимодействие с самим магазином:
А вот так это выглядело на уровне кода:
Таким образом, первый эксперимент привел к инсайтам, которые затем помогли нам улучшить устойчивость системы.
Эксперимент второй: нарушение связности между сервисами рекомендаций и каталога
Итак, мы решили провести второй тест и сосредоточили внимание на сетевых взаимодействиях между разными компонентами системы. Объектом исследования стали сервисы Рекомендаций (recommendation) и Продуктового каталога (product catalog), которые тесно связаны между собой.
Мы хотели выяснить, как отсутствие сетевой связи между сервисами Рекомендаций и Продуктового каталога повлияет на общую работоспособность онлайн-магазина. Мы предположили, что сбой рекомендаций не должен полностью нарушить работу магазина и что покупатель сможет взаимодействовать с каталогом товаров.
Для эксперимента использовали манифест, который описывал тип инъекции как Network Chaos. Определили ключевые параметры:
Селекторы для обоих сервисов — для определения подов, участвующих в эксперименте.
Тип сбоя — разрыв сетевой связи между сервисом рекомендаций и продуктовым каталогом.
Длительность — временные рамки эксперимента, чтобы ограничить его влияние и минимизировать последствия для системы. Мы выбрали 10 минут, чтобы быстро проверить гипотезу и отследить изменения в сервисе по данным мониторинга.
Мы отправили манифест в Chaos Controller Manager и он запустил разрыв сетевой связи между сервисами. Инъекция была успешно выполнена, поэтому мы перешли к наблюдению за системой.
Результаты и наблюдения
В течение первых минут после запуска эксперимента на экранах синтетического мониторинга и системного анализа появлялись изменения:
Потери данных в блоке рекомендаций — он перестал отображаться, что было ожидаемо, поскольку сервис не мог получить необходимые данные из каталога.
Стабильная работа каталога — основная часть магазина продолжала функционировать, пользователи могли просматривать и добавлять товары в корзину.
Метрики производительности — изменения, свидетельствующие об увеличении времени ответа (Response Time) со стороны продуктового каталога при недоступном сервисе рекомендаций.
Неожиданностью для нас стало то, что сбой повлиял на смежные подсистемы. Некоторые дополнительные сервисы, такие как Реклама, оказались зависимы от рекомендаций, что привело к ухудшению их производительности:
Выводы и рекомендации по итогам экспериментов
Эксперименты помогли лучше понять слабые места и уязвимости нашей системы. Сначала мы столкнулись с полной деградацией сервиса при сбое Корзины, что, честно говоря, было неожиданностью. Мы предполагали, что сбой в одном компоненте не повлияет на всё приложение, однако результаты показали обратное. Второй эксперимент подтвердил, насколько важна сетевая связность между сервисами Рекомендаций и Каталога, и продемонстрировал, что сбои в коммуникации могут иметь более обширные последствия, чем можно ожидать.
Основные выводы:
Мы недооценивали взаимосвязь между сервисами: оба эксперимента подчеркнули, что текущая архитектура онлайн-магазина имеет высокую степень взаимосвязанности между компонентами, что делает систему уязвимой к каскадным сбоям.
Важно локализовывать сбои: чтобы избежать полной деградации сервиса, необходимо добавить механизмы, которые позволят отдельным компонентам продолжать работать в условиях частичных отказов.
Стоит обновить стратегию алертинга: как показал второй эксперимент, мониторинг сетевых взаимодействий должен быть более подробным, чтобы заранее фиксировать потенциальные точки отказа и реагировать на них до того, как пользователи столкнутся с проблемами.
В результате мы разработали следующие рекомендации для улучшения системы:
Оптимизировать архитектуру:
Разделить критические компоненты и создание резервных копий.
Обеспечить избыточность для сервисов в разных доступных зонах (availability zones).
Внести изменения на уровне кода:
Добавить логику обработки ошибок, чтобы вместо критических сбоев пользователь видел уведомления о недоступности конкретного функционала.
Настроить детализированный мониторинг и алертинг:
Разработать и внедрить дополнительные метрики, позволяющие отслеживать сетевые сбои и нагрузку.
Ввести автоматические уведомления при превышении допустимых значений ошибок или времени отклика.
Заключение
Эксперименты показали, насколько важно не только проектировать системы с учетом их функциональных требований, но и предусматривать их поведение в условиях сбоев. Практика хаос-инжиниринга помогает выявить скрытые зависимости и слабые места в архитектуре, о которых мы могли не догадываться. Такой подход позволяет не просто реагировать на инциденты, но и предупреждать их, закладывая фундамент для более надежной и устойчивой системы.
А как ваша команда подходит к вопросам отказоустойчивости? Применяете ли вы хаос-инжиниринг в своих проектах? Какие уроки извлекли из реальных инцидентов? Делитесь своим опытом в комментариях и давайте обсудим, как мы все можем сделать наши системы более надежными и устойчивыми.
Другие статьи в блоге: