Автоматический failover: настройка, тестирование, защита от split-brain

Когда production-база падает в 3:15 ночи, а дежурный не может быстро подключиться, каждый час простоя обходится бизнесу в круглую сумму. Мы настраиваем автоматический failover, который переключает трафик на резервный узел за секунды, без участия человека. Наша команда реализует проект под ключ — с защитой от split-brain, тестированием и последующей поддержкой, чтобы система работала надёжно и не подводила в критический момент.
Часто задаваемые вопросы

На прошлой неделе у клиента production-база упала в 3:15 AM. Дежурный проснулся, но Wi-Fi глючил. Через 20 минут после логина скрипт восстановления не сработал из-за ошибки в конфигурации. Downtime составил 45 минут — час простоя обошелся компании в среднем $10,000, так что потеряли $7,500 только на этом инциденте. Автоматический failover мог бы сократить это до 30 секунд — в 30-60 раз быстрее ручного переключения. Но только если он настроен правильно. Мы сталкивались с кейсами, когда автоматика делала только хуже: split-brain, расхождение данных, ручное восстановление на 4 часа. Поэтому к настройке failover нужно подходить с пониманием подводных камней.

Мы разрабатываем и внедряем автоматический failover — систему, которая обнаруживает отказ основного сайта и переключает трафик на резервный без участия человека. Задача нетривиальная: нужна защита от split-brain, ложных срабатываний, корректный порядок остановки и запуска сервисов. Ошибка здесь опаснее ручного переключения.

Как работает защита от split-brain?

Split-brain возникает, когда оба сайта считают себя активными и одновременно принимают записи. Результат — расхождение данных, которое потом сложно reconcile. Классический случай: сеть между регионами оборвалась на 30 секунд. DR-сайт promote-нул реплику, а primary остался жив и продолжал принимать транзакции. После восстановления получили двух мастеров с разными данными.

Защита — кворум через внешний арбитр. Для PostgreSQL используем Patroni с etcd, Consul или ZooKeeper. Для кластеров — witness node или STONITH (Shoot The Other Node In The Head) — гарантированное выключение ноды перед promote.

# patroni.yml — конфигурация автоматического failover
scope: pg-production
bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    # Максимальный лаг реплики, при котором она может стать мастером
    maximum_lag_on_failover: 1048576  # 1 MB
    # Синхронный режим: хотя бы одна реплика должна подтвердить запись
    synchronous_mode: true
    synchronous_mode_strict: false  # false = не блокировать запись если нет реплик
postgresql:
  use_pg_rewind: true  # позволяет вернуть старый мастер как реплику
  # Скрипт вызывается при смене роли
  post_failover:
    - name: notify_ops
      command: /usr/local/bin/notify-failover.sh

Почему DNS failover не всегда спасает?

DNS failover через Route53 Health Check или Cloudflare Load Balancing — популярное решение, но с серьёзным недостатком: TTL кэширование. Даже при TTL=60 клиенты могут держать старый IP несколько минут. Для критичных приложений используем Anycast (Cloudflare Argo, AWS Global Accelerator) — переключение на сетевом уровне, минуя DNS-кэш. Anycast даёт время переключения менее 10 секунд против 60-300 секунд у DNS.

# terraform/route53-failover.tf
resource "aws_route53_health_check" "primary" {
  fqdn = "app-primary.company.internal"
  port = 443
  type = "HTTPS"
  resource_path = "/health"
  failure_threshold = 3
  request_interval = 10
  tags = {
    Name = "primary-health-check"
  }
}

resource "aws_route53_record" "app_primary" {
  zone_id = aws_route53_zone.main.zone_id
  name = "app.company.com"
  type = "A"
  failover_routing_policy {
    type = "PRIMARY"
  }
  health_check_id = aws_route53_health_check.primary.id
  set_identifier = "primary"
  ttl = 60
  records = [var.primary_ip]
}

resource "aws_route53_record" "app_dr" {
  zone_id = aws_route53_zone.main.zone_id
  name = "app.company.com"
  type = "A"
  failover_routing_policy {
    type = "SECONDARY"
  }
  set_identifier = "dr"
  ttl = 60
  records = [var.dr_ip]
}

Как автоматизировать failover с помощью AWS Lambda?

Для сложных сценариев оркестрируем failover через Lambda, вызываемую EventBridge по CloudWatch алерту. Скрипт promote-ит Read Replica, обновляет конфиг в SSM, перезапускает ECS сервисы и переключает Route53. Время выполнения — около 2 минут. Подробнее в документации AWS Lambda.

# lambda/failover-orchestrator.py
import boto3
import json

def lambda_handler(event, context):
    """ Вызывается EventBridge при алерте CloudWatch: DatabaseDown severity=critical duration=5m """
    rds = boto3.client('rds', region_name='eu-central-1')
    r53 = boto3.client('route53')

    # Шаг 1: Promote RDS Read Replica в DR-регионе
    response = rds.promote_read_replica(
        DBInstanceIdentifier='prod-dr-replica',
        BackupRetentionPeriod=7,
        PreferredBackupWindow='03:00-04:00'
    )

    # Ждём, пока реплика станет standalone
    waiter = rds.get_waiter('db_instance_available')
    waiter.wait(DBInstanceIdentifier='prod-dr-replica')

    # Шаг 2: Обновить application config через SSM Parameter Store
    ssm = boto3.client('ssm', region_name='eu-west-1')
    dr_endpoint = rds.describe_db_instances(
        DBInstanceIdentifier='prod-dr-replica'
    )['DBInstances'][0]['Endpoint']['Address']
    ssm.put_parameter(
        Name='/app/database/host',
        Value=dr_endpoint,
        Type='String',
        Overwrite=True
    )

    # Шаг 3: Перезапустить ECS сервисы в DR-регионе с новым конфигом
    ecs = boto3.client('ecs', region_name='eu-west-1')
    ecs.update_service(
        cluster='prod-dr',
        service='app',
        forceNewDeployment=True
    )

    # Шаг 4: Переключить Route53
    # (вызов update_health_check или change_resource_record_sets)
    return {'status': 'failover_initiated', 'dr_db': dr_endpoint}

Как протестировать failover без риска?

Периодически проверяем, что автоматика работает. Процесс тестирования состоит из шагов:

  1. Отключаем health check endpoint для primary-ресурса.
  2. Убеждаемся, что трафик переключился на DR-сайт (проверяем логи и метрики).
  3. Включаем health check обратно.
  4. Возвращаем primary в строй и выполняем switchback через patronictl switchover.

Для Patroni используем patronictl failover --master current-master --candidate replica-dr --force. После каждого тестового failover обязательно проверяем возврат в primary mode. Рекомендуем проводить тесты не реже раза в квартал, а для критичных систем — ежемесячно. Экономия от внедрения failover может превышать $100,000 в год за счёт предотвращения простоев.

Сравнение методов failover

Метод Время переключения Сложность Риск split-brain
DNS failover (TTL=60) 60-300 сек Низкая Нет
Anycast (Global Accelerator) <10 сек Средняя Нет
BGP anycast <1 сек Высокая Да (требует настройки)
Patroni + etcd <30 сек Средняя Нет (кворум)

Что входит в нашу работу

  • Аудит текущей инфраструктуры и выявление single points of failure
  • Проектирование архитектуры failover (DNS/Anycast, БД, приложения)
  • Настройка Patroni, Route53, Lambda, Ansible
  • Разработка runbook и процедуры отката
  • Тестирование сценариев: отказ primary, отказ реплики, отказ сети
  • Документация и передача знаний вашей команде

Ориентировочные сроки

Сложность Компоненты Срок
Базовый DNS failover (Route53/Cloudflare) + 1 БД 3–5 дней
Средний Patroni + DNS + app layer, 2–3 сервиса 1–2 недели
Сложный Полная оркестрация (Lambda/Ansible), 10+ сервисов, тестирование 4–8 недель

Стоимость проекта обсуждается после аудита. Получите консультацию по настройке failover — свяжитесь с нами для оценки вашего проекта. Опыт наших инженеров — более 10 лет в продакшен-инфраструктуре. Закажите аудит вашей инфраструктуры уже сегодня.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    816
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1141