# Методы, способы и средства обеспечения отказоустойчивости автоматизированных систем # Что такое отказоустойчивость и стабильность? Под **отказоустойчивостью** будем понимать свойство системы, которое позволяет максимально сохранять работоспособность при отказе отдельных конкретных компонентов системы либо связанных систем и восстанавливать работоспособность системы при восстановлении отказавших компонентов или связанных систем. Давайте рассмотрим подробнее эти 2 момента: - Деградация работоспособности системы должна быть прямо пропорциональна "величине" отказа. То есть, если упал сервис, отвечающий за некую некритичную функциональность — вся система не должна при этом падать. Да, небольшой кусочек не работает, но это не влияет на стабильность остальной части функционала. - **Стабильность** системы предполагает самостоятельного восстановления работоспособности после сбоя как компонентов системы, так и всей системы в целом. К примеру, если пропадала сеть на некоторое время — то у стабильных систем после восстановления подключения все компоненты продолжат работать и данные вернутся в консистентное состояние без ручного вмешательства со стороны команды эксплуатации. ## Наглядное сравнение ![](eroshko1.png) Если в стабильной системе из нормального состояния равновесия шарик в центре чуть-чуть подтолкнём в сторону — он, конечно же, ненадолго отклонится от равновесия (т.е. система перейдёт в некоторое неидеальное состояние), но после этого шарик быстро вернётся в нормальное состояние. В случае же плохо спроектированных и построенных систем — даже лёгкого воздействия на шарик достаточно, чтобы система начала деградировать с нарастающей скоростью. При этом сам по себе шарик не вернётся в нормальное состояние в таких системах. ## Как измерить отказоустойчивость и стабильность? Но как же определить является ли наша система отказоустойчивой и стабильной? И на сколько? Как в идеале замерить эти свойства, чтобы двигаться к цели согласно некой метрике, а не наощупь? Единственный способ спроектировать систему, которая будет устойчива к сбоям — проводить **стресс-тесты** (resilience testing / chaos engineering), по результатам тестов делать выводы, менять архитектуру и подходы к написанию кода, снова запускать тест... и так до бесконечности :) **Количество пройденных тестов** и будет метрикой отказоустойчивости отдельных компонентов и системы в целом. Только на основе метрики делаем вывод о повышении или понижении стабильности системы. Создание таких тестов — уже непростая инженерная задача. Для начала необходимо описать и автоматизировать сценарии отказа (легла сеть, закончилось место на диске, внешний сервис отвечает ошибками, сеть тормозит или доставляет только 50% пакетов, выключилось электричество на конкретном физическом хосте или во всё дата-центре и т.д.) — а потом запускать их в произвольном порядке, да и ещё и в случайных комбинациях друг с другом ??. Тесты позволят нам и получить измеримую метрику (прошли 10 тестов из 50), и понять какие отказы наиболее критичны, т.к. сразу же приводят к краху всей системы. ## Принципы построения отказоустойчивых систем ### Отсутствие единой точки отказа (No SPoF - Single Point of Failure) Принцип применим ко всем уровням эксплуатации — от точки деплоя (любой Nginx или микросервис в системе) до уровня дата центров. Рассмотрим этот принцип на примерах репликации и балансировки небольших компонентов системы: ![](eroshko2.png) Для его реализации сервисы должны быть готовы к запуску в нескольких экземплярах — как минимум не должны хранить состояния (быть stateless-сервисами). Давайте рассмотрим обратный пример, когда у нас сервис хранит состояние и неготов к горизонтальному масштабированию. Пусть в нашей схеме сессия пользоавтеля хранится на самом бэкендовском сервисе: ![](eroshko3.png) ### Проектирование с учётом отказов (Design for Failure) В любой системе происходят отказы и падения, поэтому важно уже на этапе проектирования архитектуры держать в уме, моделировать и закладывать обработку нештатных ситуаций. Рассмотрим основные базовые идеи концепции: **Постепенная деградация (Graceful degradation)** — это возможность частично деградировать функционала системы в случае отсутствия/неработоспособности её компонентов. Рассмотрим на схеме вариант построения системы с последовательной связанностью и полной деградацией при отказе: ![](eroshko4.png) Другой вариант частичной деградации — потеря или отложенное предоставление некритичных данных. Например, мы можем показать позже срок доставки товара (или не показывать вовсе) в случае проблем с компонентом расчета доставки, при этом вся остальная информация и возможность купить будут доступны. В худшем варианте, если некий BFF или API Gateway дожидается синхронного ответа от каждого компонента и только потом отдаёт результирующий html — страница отобразится пользователю только после отрабатывания самого медленного компонента (или суммы времени всех, если запросы строятся ещё и последовательно, а не параллельно). При падении одного из компонентов (например, не самого важного раздела с похожими товарами) в нетолерантном к отказам варианте проектирования пользователь бы в принципе ничего не увидел кроме страницы с ошибкой. Помимо отложенной доставки или потери данных, в случае их критичности — можем деградировать в их актуальности взамен полного отсутствия при помощи кэширования. К примеру, если источник актуальных данных недоступен — берём предсохранённые данные из кэша: в зависимости от сценария, тут может быть как частичная деградация (актуальные данные лучше старых, но старые лучше их отсутствия) так и отсутствие деградации вовсе (пусть в 99% случаев закэшированные данные соответствуют актуальным). ## Выводы На основе рассмотренных принципов и подходов можно сформулировать следующие ключевые выводы: ### Основные положения - **Отказоустойчивость** и **стабильность** — взаимосвязанные, но различные свойства системы, требующие целенаправленного проектирования и тестирования - Отказоустойчивость обеспечивает постепенную деградацию функциональности при отказах компонентов - Стабильность гарантирует самостоятельное восстановление системы после сбоев ### Методология оценки - Единственный эффективный способ оценки — **стресс-тестирование** и **chaos engineering** - Количество пройденных тестов служит объективной метрикой отказоустойчивости - Автоматизированные сценарии отказа позволяют выявить наиболее критические точки системы ### Архитектурные принципы 1. **Отсутствие единой точки отказа** — фундаментальный принцип, требующий: - Stateless-архитектуры сервисов - Готовности к горизонтальному масштабированию - Репликации критических компонентов 2. **Проектирование с учётом отказов** — включает: - Реализацию постепенной деградации функциональности - Стратегии обработки частичных отказов (кэширование, отложенные данные) - Параллельную обработку запросов вместо последовательной ### Практические рекомендации - Критически важные данные должны быть доступны через кэширование при недоступности источников - Некритичный функционал может временно деградировать без влияния на основную систему - Архитектура должна допускать частичные отказы без полного прекращения работы ### Непрерывный процесс Создание отказоустойчивой системы — **итерационный процесс**, включающий: - Регулярное тестирование на устойчивость к сбоям - Постоянное совершенствование архитектуры - Анализ метрик и адаптацию к новым угрозам Только комплексный подход, сочетающий продуманную архитектуру и регулярное тестирование, позволяет создать действительно стабильную и отказоустойчивую систему. Источник: habr.com