Высокая доступность и отказоустойчивость инфраструктуры
↑ Этап 8 · Senior: надёжность, безопасность, платформа
Зачем это на собесе
Senior-вопрос: как спроектировать систему, переживающую отказы узлов, зон и регионов, и как посчитать доступность.
Понятия
- Доступность =
Uptime / (Uptime + Downtime); отказоустойчивость (fault tolerance) — работа при отказе компонентов; устойчивость (resilience) — способность восстанавливаться; HA (High Availability) — минимизация простоя за счёт избыточности и автоматического переключения; DR — восстановление после катастрофы. - SPOF (Single Point of Failure) — компонент, отказ которого выводит систему из строя; задача архитектора — найти и устранить SPOF (каждый уровень: DNS, LB, приложение, кэш, БД, сеть, электропитание, зона, провайдер, люди, процессы, зависимости третьих сторон).
Расчёт доступности
| Схема | Формула | Пример (по 99.9%) |
|---|---|---|
| Последовательные зависимости (все нужны) | A = A₁ × A₂ × … | 99.9% × 99.9% × 99.9% = 99.7% |
| Параллельные (резерв, достаточно одного) | A = 1 − (1 − A₁)(1 − A₂) | два по 99.9% → 99.9999% (при независимости и мгновенном переключении) |
| k из n | биномиальное распределение | кластер из 3, достаточно 2 |
Следствия: цепочка из многих зависимостей снижает итоговую доступность → минимизировать число критичных зависимостей, делать некритичные опциональными (graceful degradation), избегать общих причин отказов (correlated failures: одна зона, один релиз, один провайдер, одна конфигурация).
Уровни избыточности
| Уровень | Приёмы |
|---|---|
| Железо/ВМ | несколько узлов, RAID, резервные блоки питания, ECC, автозамена ВМ |
| Сеть | дублирование линков (bonding/LACP), несколько провайдеров, BGP, anycast, резервные маршрутизаторы (VRRP/keepalived) |
| Приложения | минимум 2–3 реплики, stateless, балансировщик + health checks, rolling-обновления, PDB |
| Балансировщики | пара LB (keepalived+VIP), облачные мультизональные LB, DNS/GSLB |
| Данные | репликация (sync/async), кворум, бэкапы, шардирование, multi-AZ БД |
| Зона доступности (AZ) | распределение по ≥ 2–3 зонам, отказ зоны не приводит к отказу сервиса |
| Регион | active-passive/active-active, DR-регион, глобальный балансировщик |
| Провайдер | мультиоблако (дорого; для критичных систем и регуляторики) |
Active-Active и Active-Passive
| Active-Passive | Active-Active | |
|---|---|---|
| Идея | основной обслуживает, резервный ждёт (hot/warm/cold standby) | все узлы обслуживают трафик |
| Переключение | failover (минуты/секунды) | нет переключения, перераспределение |
| Использование ресурсов | резерв простаивает | эффективное |
| Сложность | ниже | выше: согласованность данных, конфликты, sticky/состояние |
| Данные | репликация в standby | многомастерная репликация/шардирование/CRDT, глобальные БД (Spanner, Cosmos, DynamoDB Global Tables) |
Состояние и данные
- stateless приложения (сессии/файлы/кэш вынесены) — масштабируются и заменяются легко;
- БД — самое сложное: репликация (Patroni, Galera, managed multi-AZ), кворум (нечётное число: 3/5), синхронная репликация в зоне + асинхронная между регионами, RPO/RTO; сплит-брейн (fencing, STONITH, DCS с кворумом);
- кэш: кластер/Sentinel, приложение должно переживать потерю кэша (cache aside + защита БД);
- очереди: кластеры (Kafka RF=3,
min.insync.replicas=2, RabbitMQ quorum queues); - файлы: объектное хранилище с репликацией;
- согласованность: CAP/PACELC — осознанный выбор между консистентностью и доступностью при разделении сети.
Паттерны устойчивости приложений
- Таймауты на всех исходящих вызовах (без них зависание исчерпает потоки);
- Retry с экспоненциальным backoff + jitter, только для идемпотентных операций, retry budget (ограничение доли повторов) — иначе «шторм повторов»;
- Circuit breaker: после серии ошибок быстро отказывать, давая зависимости восстановиться (Polly, Resilience4j, Envoy);
- Bulkhead (переборки): изоляция пулов ресурсов по зависимостям; один медленный сервис не съедает все потоки;
- Rate limiting / load shedding: отбрасывание избыточной нагрузки (503 + Retry-After) вместо коллапса;
- Backpressure: очереди ограничены, сигнал «замедлитесь»;
- Graceful degradation: отключить второстепенное (рекомендации, аналитика), основная функция работает;
- Fallback/кэш «stale-if-error»: отдать устаревшее при недоступности источника;
- Идемпотентность и дедупликация (ключи идемпотентности) для безопасных повторов;
- Health checks (liveness/readiness), graceful shutdown, connection draining;
- Очереди и асинхронность развязывают сервисы во времени (outbox, саги);
- Feature flags для быстрого отключения проблем;
- Canary и прогрессивные релизы, автоматический откат.
Географическое распределение
- Multi-AZ — базовый уровень для продакшна (задержка между зонами ~1–2 мс, синхронная репликация возможна);
- Multi-Region — защита от потери региона, близость к пользователям; задержки 50–200 мс → асинхронная репликация, конфликты, регион данных (152-ФЗ/GDPR);
- DNS/GSLB (Route 53 latency/failover, Cloudflare LB, anycast): health-check, TTL, перенаправление; Global Accelerator;
- Cell-based architecture (ячейки): независимые полные копии (на подмножество клиентов) ограничивают «радиус поражения»;
- Shuffle sharding: каждый клиент привязан к случайному подмножеству узлов.
Kubernetes и HA
- control plane в 3 зонах, etcd 3/5 узлов, пулы нод в нескольких AZ;
- Deployment: ≥ 3 реплики,
topologySpreadConstraintsпо зонам,podAntiAffinity, PDB, readiness/liveness,maxUnavailable: 0; - HPA + Cluster Autoscaler/Karpenter, запас ёмкости (overprovisioning) для потери зоны (N+1/N+2: при потере зоны оставшиеся выдерживают нагрузку);
- StatefulSet/операторы БД с репликами в разных зонах; PV привязаны к зоне (учёт при failover);
- Ingress с несколькими репликами, externalTrafficPolicy, multi-cluster/федерация (Cluster API, Submariner, Cilium ClusterMesh), GitOps для идентичных кластеров;
- приоритеты подов (PriorityClass), квоты, лимиты.
Ёмкость и запас
N+1, N+2: запас на отказ узлов/зон + плановые работы; нагрузка на оставшиеся при потере зоны: при 3 зонах каждая нагружена ≤ 66%; при 2 зонах ≤ 50%. Тестировать потерю зоны (game day).
Проверка отказоустойчивости
- Chaos engineering (Chaos Mesh, Litmus, Gremlin, AWS FIS): убить под/ноду/зону, задержки/потери сети, отказ БД;
- Game days, DR-учения (переключение региона), failover-тесты БД/LB;
- нагрузочные тесты с отказами;
- Мониторинг: SLO/error budget, алерты на деградацию HA (реплика отстаёт, потеряна избыточность) — «система жива, но без запаса».
Типичные ловушки
- скрытые SPOF: один DNS-провайдер, один NAT Gateway, общий реестр образов, единственный Vault, один CI-раннер, единственный админ («bus factor»);
- корреляция отказов: общий релиз/конфигурация/сертификат ломает все реплики сразу;
- каскадные отказы: ретраи, перегрузка оставшихся узлов, thundering herd после восстановления (нужен jitter, плавный ввод в строй);
- избыточность без автоматического переключения и без проверок: «резерв» не работает, когда нужен;
- «split brain» из-за неверной кворумной схемы;
- недостаточный запас ёмкости при потере зоны;
- зависимость от внешних сервисов без таймаутов/деградации;
- бэкапы ≠ HA; HA ≠ DR; репликация не защищает от логических ошибок.
Практика собеседования
Проектирование: «как сделать сервис доступным на 99.95%?» — рассчитать бюджет (≈21 мин/мес), найти SPOF, multi-AZ (приложение ≥ 3 реплик, БД с синхронной репликацией и автоматическим failover, LB мультизональный), выделить критичные зависимости, добавить таймауты/ретраи/circuit breaker, мониторинг по SLO, runbook и учения, план DR, стоимость.
Вопросы с ответами
Как рассчитывается доступность цепочки зависимостей?
Для последовательных компонентов доступности перемножаются (три по 99.9% дают около 99.7%), для параллельных резервов:
1 − (1 − A₁)(1 − A₂). Поэтому нужно сокращать критичные зависимости и добавлять избыточность.
Чем Active-Active отличается от Active-Passive?
В active-active все узлы обрабатывают трафик (эффективнее, но сложнее с согласованностью данных); в active-passive резерв ждёт failover (проще, но ресурсы простаивают и есть время переключения).
Что такое каскадный отказ и как его предотвратить?
Сбой распространяется на другие части (из-за повторов, перегрузки оставшихся узлов). Предотвращают таймауты, circuit breaker, bulkhead, retry budget с jitter, load shedding и запас ёмкости.