Автоматичний 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?

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

Захист — кворум через зовнішній арбітр. Для PostgreSQL використовуємо Patronі з 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
    1543
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1396
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1375
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    817
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1143