Отказоустойчивость: резервирование, деградация, circuit breaker

Отказы неизбежны — вопрос не «если», а «когда»; задача инженера в том, чтобы система их пережила.

Отказоустойчивость (fault tolerance) — способность системы продолжать работу (возможно, с ухудшением) при отказе отдельных компонентов.

На масштабе тысяч серверов что-то ломается постоянно: диски, сеть, целые ЦОД. Нельзя сделать так, чтобы не падало; можно сделать так, чтобы падение одного узла не роняло систему.

Убрать единую точку отказа (SPOF)

Single Point of Failure — компонент, отказ которого роняет всю систему. Главный приём — резервирование (redundancy): дублировать критичные компоненты, чтобы при падении одного работу подхватил другой.

КомпонентКак убрать SPOF
Сервер приложениянесколько инстансов за балансировщиком
Балансировщикпара active-passive с плавающим IP
База данныхреплики + автоматический failover
Целый ЦОДмультирегиональное развёртывание

Graceful degradation

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

Таймауты и ретраи

Вызов внешнего сервиса без таймаута — мина: если он завис, ваш поток ждёт вечно, потоки кончаются, сервис встаёт. Всегда ставьте таймаут. Ретраи помогают пережить разовый сбой, но усиливают перегрузку, если сервис и так лежит. Поэтому ретраи делают с экспоненциальной задержкой и jitter (случайным разбросом), а не подряд.

Наивно: повтор сразу, ещё раз сразу… → добиваем упавший сервис
Правильно: ждать 1с, потом 2с, потом 4с (+случайный jitter), и предел попыток

Circuit breaker (предохранитель)

Circuit breaker — обёртка над вызовом сервиса, которая при серии ошибок «размыкает цепь» и перестаёт его дёргать, мгновенно отдавая отказ или запасной ответ.

Логика как у электрического предохранителя: если сервис стабильно падает, бессмысленно слать ему запросы и ждать таймаут на каждом. Breaker это замечает и временно «отрезает» вызовы, давая сервису восстановиться и не тратя ваши ресурсы на безнадёжные попытки.

СостояниеПоведение
Closed (замкнут)запросы идут как обычно; считаем ошибки
Open (разомкнут)порог ошибок превышен — запросы не шлём, сразу отказ/фолбэк
Half-openспустя время пробуем один запрос: ок → closed, нет → снова open

Circuit breaker предотвращает каскадные отказы — когда падение одного сервиса по цепочке тянет за собой все остальные, ждущие его ответа.

Итог

  • Отказы неизбежны: убирайте SPOF резервированием критичных компонентов.
  • Graceful degradation отдаёт урезанный ответ вместо ошибки; таймауты обязательны, ретраи — с экспоненциальной задержкой.
  • Circuit breaker отрезает падающий сервис и предотвращает каскадные отказы.
Проверьте себя
1. Что делает паттерн circuit breaker, когда сервис стабильно падает?
AШлёт ему запросы ещё чаще
BРазмыкает цепь и временно перестаёт его вызывать, отдавая отказ или фолбэк
CПерезапускает базу данных
DУвеличивает таймаут до бесконечности
2. Что такое graceful degradation?
AПолная остановка системы при сбое
BОтдача урезанного результата вместо ошибки, когда часть системы недоступна
CПостепенное замедление базы данных
DУдаление неисправного сервиса навсегда
3. Почему ретраи делают с экспоненциальной задержкой, а не подряд?
AТак быстрее восстановление
BПовторы подряд добивают уже перегруженный сервис; растущая задержка с jitter снижает давление
CЭто требование протокола HTTP
DЧтобы запутать злоумышленника
4. Зачем убирать единую точку отказа (SPOF)?
AЧтобы сэкономить серверы
BПотому что отказ такого компонента роняет всю систему; резервирование позволяет пережить его падение
CSPOF ускоряет систему
DЭто нужно только для базы данных
Поддержать проект