Перейти к содержанию
Learning Platform
Продвинутый
30 минут
aurora-failover heartbeat replication-slots high-availability

Aurora Failover и Replication Slots

Критическая проблема: Slots не синхронизируются

Amazon Aurora PostgreSQL обеспечивает высокую доступность через автоматический failover. Когда Writer Instance выходит из строя, один из Reader Instances автоматически становится новым Writer.

Однако в PostgreSQL версий до 17 есть критическая особенность: replication slots не синхронизируются между Writer и Reader инстансами.

Warning: При failover Aurora PostgreSQL (версии до 17) все логические replication slots теряются. Это может привести к потере CDC-событий для транзакций, произошедших между последним подтвержденным событием и моментом failover.

Механика Aurora Failover

App
Writer
Reader
Slot
Debezium
Kafka
INSERT id=100Write LSNRead changesEvent id=100INSERT id=101PromotionReconnectSlot not foundCREATE SLOT
Потеря данных в Failover Window
id=101— ПОТЕРЯН. Был записан в WAL до crash, но Debezium не успел прочитать.
Новый slot начинает с текущей позиции (после recovery). Все транзакции в failover window невидимы для CDC.

Временная шкала потери данных

ВремяСобытиеДанные
T0Debezium подтверждает LSN=100id=100 в Kafka
T1Writer записывает id=101LSN=101 в WAL
T2Writer падаетid=101 не подтвержден Debezium
T3Reader становится WriterСлот потерян
T4Debezium пересоздает слотНачинает с LSN=102
T5+Нормальная работаid=101 потерян навсегда
Проверка знаний
Почему при Aurora failover теряются логические replication slots, хотя сами данные сохраняются?
Ответ
Aurora реплицирует данные на уровне storage layer, но логические replication slots — это метаданные в памяти и каталоге конкретного PostgreSQL-инстанса. При failover бывший Reader становится Writer, но не имеет информации о слотах старого Writer. Это архитектурное ограничение, решаемое в PostgreSQL 17 с failover slots.

Heartbeat: детектирование пропусков

Heartbeat не предотвращает потерю данных, но позволяет обнаружить её. Debezium может периодически обновлять специальную таблицу, создавая “маркеры времени” в потоке событий.

Debezium Connector
Heartbeat Generator
heartbeat.interval.ms = 10000
PostgreSQL
heartbeat table
id=1, ts=NOW(), writer_id
Kafka Topics
inventory.public.orders
__debezium-heartbeat.*
Monitoring & Alerting
Alert: gap > 30s
Heartbeat обнаруживает, но НЕ предотвращает потерю данных
UPDATE heartbeat
CDC событие
Kafka topics
Monitor
Alert

Создание heartbeat таблицы

-- Создание таблицы для heartbeat
CREATE TABLE public.heartbeat (
    id INTEGER PRIMARY KEY,
    ts TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    writer_instance VARCHAR(100)
);

-- Вставка начальной записи
INSERT INTO public.heartbeat (id, ts, writer_instance)
VALUES (1, NOW(), current_setting('aurora.server_id'));

-- Права для пользователя Debezium
GRANT SELECT, UPDATE ON public.heartbeat TO debezium_user;

Конфигурация коннектора с heartbeat

{
  "name": "inventory-connector",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "aurora-cluster.xxxxx.region.rds.amazonaws.com",
    "database.port": "5432",
    "database.user": "debezium_user",
    "database.password": "${file:/secrets/db-password.txt}",
    "database.dbname": "inventory",
    "topic.prefix": "inventory",
    "table.include.list": "public.orders,public.customers",
    "plugin.name": "pgoutput",

    "heartbeat.interval.ms": "10000",
    "heartbeat.action.query": "UPDATE public.heartbeat SET ts = NOW(), writer_instance = current_setting('aurora.server_id') WHERE id = 1"
  }
}

Параметры heartbeat

ПараметрЗначениеОписание
heartbeat.interval.ms10000Интервал между heartbeat (10 сек рекомендуется)
heartbeat.action.querySQL UPDATEЗапрос для обновления heartbeat таблицы
heartbeat.topics.prefix__debezium-heartbeatПрефикс Kafka topic для heartbeat
Проверка знаний
Heartbeat предотвращает потерю данных при Aurora failover?
Ответ
Нет. Heartbeat только обнаруживает пропуски в CDC-потоке, но не может их предотвратить. Его ценность — в раннем оповещении: когда разрыв heartbeat превышает настроенный интервал, это сигнал о произошедшем инциденте (failover), и можно запустить процедуры восстановления, например incremental snapshot.

Мониторинг heartbeat

SQL запрос для проверки последнего heartbeat

-- Проверка времени последнего heartbeat
SELECT
    ts AS last_heartbeat,
    writer_instance,
    EXTRACT(EPOCH FROM (NOW() - ts))::INTEGER AS seconds_ago,
    CASE
        WHEN EXTRACT(EPOCH FROM (NOW() - ts)) > 30 THEN 'ALERT: Gap detected!'
        WHEN EXTRACT(EPOCH FROM (NOW() - ts)) > 15 THEN 'WARNING: Delayed'
        ELSE 'OK'
    END AS status
FROM public.heartbeat
WHERE id = 1;

Детектирование failover через writer_instance

-- История изменений writer_instance показывает failover
-- (требует включение heartbeat в table.include.list или отдельный мониторинг)

-- Если writer_instance изменился - был failover
SELECT
    ts,
    writer_instance,
    LAG(writer_instance) OVER (ORDER BY ts) AS previous_writer
FROM public.heartbeat_history  -- таблица с историей, если ведется
WHERE writer_instance != LAG(writer_instance) OVER (ORDER BY ts);

Стратегии митигации потери данных

Стратегия 1: Принять риск (для некритичных данных)

Для аналитических систем или данных, где единичная потеря события допустима:

  • Настроить heartbeat для детектирования
  • Документировать возможные пропуски
  • Периодически сверять с исходной БД
-- Пример сверки: найти расхождения за последний час
SELECT o.id, o.created_at
FROM orders o
LEFT JOIN kafka_orders_sink k ON o.id = k.order_id
WHERE o.created_at > NOW() - INTERVAL '1 hour'
  AND k.order_id IS NULL;

Стратегия 2: Incremental Snapshot после failover

После обнаружения failover запустить incremental snapshot для “пропущенного” временного окна:

-- Таблица сигналов для запуска snapshot
CREATE TABLE IF NOT EXISTS public.debezium_signal (
    id VARCHAR(100) PRIMARY KEY,
    type VARCHAR(50) NOT NULL,
    data TEXT NOT NULL
);

-- После детектирования failover - запустить snapshot
INSERT INTO public.debezium_signal (id, type, data)
VALUES (
    'failover-recovery-' || NOW()::TEXT,
    'execute-snapshot',
    '{
        "data-collections": ["public.orders"],
        "type": "incremental",
        "additional-conditions": [{
            "data-collection": "public.orders",
            "filter": "updated_at > (NOW() - INTERVAL ''1 hour'')"
        }]
    }'
);

Стратегия 3: Aurora Global Database

Для критически важных данных используйте Aurora Global Database с отдельными CDC-потоками:

Primary Region (us-east-1)Recommended
Writer Instance
Debezium #1
Kafka Cluster #1
Aurora Replication
< 1 sec lag
Secondary Region (eu-west-1)
Writer Instance
Debezium #2
Kafka Cluster #2
Consumer Service (Multi-Region Merge)
Kafka #1
Consumer Service
Kafka #2
Требуется дедупликация по event ID при merge потоков
Преимущества
  • + CDC в двух регионах
  • + При failover в primary — secondary продолжает
  • + Можно мержить потоки с дедупликацией
Недостатки
  • - Увеличенная стоимость (2x инфраструктура)
  • - Сложность инфраструктуры
  • - Необходима дедупликация при merge

Преимущества:

  • CDC в двух регионах
  • При failover в primary регионе - secondary продолжает работать
  • Можно мержить потоки с дедупликацией

Недостатки:

  • Увеличенная стоимость
  • Сложность инфраструктуры
  • Необходима дедупликация при merge

Стратегия 4: Dual-write с outbox pattern

Вместо CDC использовать outbox pattern с гарантированной доставкой:

-- Outbox таблица
CREATE TABLE public.outbox (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    aggregate_type VARCHAR(100) NOT NULL,
    aggregate_id VARCHAR(100) NOT NULL,
    event_type VARCHAR(100) NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Приложение пишет в outbox в той же транзакции
BEGIN;
    INSERT INTO orders (id, customer_id, total) VALUES (101, 'cust-1', 99.99);
    INSERT INTO outbox (aggregate_type, aggregate_id, event_type, payload)
    VALUES ('Order', '101', 'OrderCreated', '{"id": 101, "total": 99.99}');
COMMIT;

Debezium читает outbox таблицу - события гарантированно в базе.

PostgreSQL 17: Failover Slots

PostgreSQL 17 (выпущен сентябрь 2024) добавляет функцию failover slots - автоматическую синхронизацию логических replication slots между primary и standby.

-- PostgreSQL 17+: создание failover slot
SELECT pg_create_logical_replication_slot(
    'debezium_slot',
    'pgoutput',
    false,  -- temporary
    true    -- failover = TRUE (новый параметр PG17)
);

Ожидаемое поведение в Aurora PostgreSQL 17

Когда Aurora PostgreSQL 17 станет доступен:

  1. Создание слота с failover = true
  2. Слот автоматически реплицируется на read replicas
  3. При failover новый writer имеет актуальный слот
  4. Потеря данных устранена

Note: На момент написания курса (февраль 2026) Aurora PostgreSQL 17 еще не доступен в general availability. AWS обычно отстает на 6-12 месяцев от community релизов PostgreSQL.

Мониторинг с Prometheus/Grafana

Метрики для отслеживания failover риска

# prometheus/rules/aurora-cdc.yml
groups:
  - name: aurora-cdc-alerts
    rules:
      - alert: HeartbeatGap
        expr: |
          time() - max(debezium_heartbeat_timestamp) > 30
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "Debezium heartbeat gap detected"
          description: "No heartbeat for {{ $value }} seconds"

      - alert: ReplicationSlotLag
        expr: |
          pg_replication_slot_lag_bytes > 1073741824
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Replication slot lag exceeds 1GB"
          description: "Slot {{ $labels.slot_name }} has {{ $value | humanize }}B lag"

Grafana dashboard queries

-- InfluxDB / TimescaleDB query для визуализации heartbeat
SELECT
    time_bucket('1 minute', ts) AS bucket,
    COUNT(*) AS heartbeats,
    MAX(EXTRACT(EPOCH FROM (ts - LAG(ts) OVER (ORDER BY ts)))) AS max_gap
FROM heartbeat_events
WHERE ts > NOW() - INTERVAL '1 hour'
GROUP BY bucket
ORDER BY bucket;

Чеклист для production Aurora CDC

Перед развертыванием

  • Heartbeat таблица создана и включена в мониторинг
  • heartbeat.interval.ms настроен (10-30 секунд)
  • Алерты на heartbeat gap настроены
  • Документирована процедура recovery после failover

При failover

  • Проверить heartbeat timestamp - определить время простоя
  • Проверить writer_instance - подтвердить смену инстанса
  • Запустить incremental snapshot если нужна полнота данных
  • Проверить consumer lag в Kafka

Долгосрочно

  • Отслеживать доступность Aurora PostgreSQL 17
  • Планировать миграцию на failover slots
  • Рассмотреть Aurora Global Database для критичных workloads

Ключевые выводы

  1. Replication slots не переживают failover в Aurora PostgreSQL версий до 17
  2. Heartbeat обнаруживает, но не предотвращает потерю данных
  3. Incremental snapshot - способ восстановления после failover
  4. PostgreSQL 17 failover slots решат проблему, когда появятся в Aurora
  5. Для критичных данных рассмотрите Aurora Global Database или outbox pattern

Главный инсайт: Aurora failover - это не баг, а архитектурное ограничение PostgreSQL версий до 17. Планируйте митигации заранее, а не после первого инцидента.

Что дальше?

Теперь вы понимаете production-особенности Aurora PostgreSQL для CDC. В следующих уроках мы рассмотрим стратегии snapshot’ов: когда использовать initial snapshot, а когда incremental, и как настроить signaling table для управления snapshot’ами по требованию.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Что происходит с логическими replication slots при failover Amazon Aurora PostgreSQL (версии до 17)?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс