Классическая ловушка при проектировании отказоустойчивости — разрыв между ожиданиями бизнеса и возможностями инфраструктуры. На бумаге в SLA может быть зафиксировано RTO в 4 часа, но если терабайтный бэкап PostgreSQL физически разворачивается 8 часов из-за лимитов дисковой подсистемы, такой SLA не выдержит первого серьезного инцидента.

На практике планы Disaster Recovery (DR) часто пишутся «для галочки» и в полном отрыве от реальной архитектуры. Под катом — техническая изнанка проектирования отказоустойчивости: как приземлить RTO и RPO на реальную инфраструктуру, связать их со стоимостью простоя и взять эти метрики под контроль с помощью правильных инженерных подходов. 

Также в статью включены практические инструменты: чек-лист для безопасного проведения DR-учений и перечень ключевых параметров, которые необходимо непрерывно мониторить для контроля рисков.

Что на самом деле измеряют RPO и RTO

Если отбросить сухую теорию, суть этих метрик сводится к двум вопросам:

  • сколько времени мы можем восстанавливаться;

  • сколько данных допустимо потерять.

RPO, Recovery Point Objective — это максимально допустимый объем потери данных, выраженный во времени. Если база бэкапится раз в сутки в 00:00, а сервер падает в 23:59, реальный RPO для такого сценария может составить почти 24 часа. Все изменения за день окажутся под угрозой.

RTO, Recovery Time Objective — это целевое время восстановления сервиса до состояния, когда он снова доступен пользователям или смежным системам.

Важно: RTO — это не только время восстановления из бэкапа. В честный RTO входят обнаружение аварии, реакция команды, подготовка инфраструктуры, восстановление данных, конфигурация сервисов, проверка целостности, переключение трафика и прогрев системы.

Упрощенно эту зависимость можно представить так:

Реальное RTO = 
    Время обнаружения аварии
  + Время принятия решения о восстановлении
  + Время подготовки инфраструктуры
  + Время восстановления данных и сервисов
  + Время настройки конфигураций
  + Время проверки работоспособности
  + Время переключения трафика
  + Время прогрева системы

Если дамп PostgreSQL разворачивается за 2 часа, это еще не значит, что RTO компании равно двум часам. В условиях реального инцидента к этому таймингу неизбежно добавляются:

  • 20 минут — на первичную диагностику и локализацию;

  • 40 минут — на подготовку целевого окружения;

  • 30 минут — на раскатку секретов и конфигураций;

  • 40 минут — на валидацию данных и проверку консистентности;

  • 10–20 минут — на переключение сетевого трафика.

Почему «у нас всё хорошо» — опасное заблуждение

Большинство проблем с DR возникают не из-за отсутствия бэкапов, а из-за неверных ожиданий.

  1. Путают RTO и время восстановления из бэкапа. Это главная ловушка. Если ваш дамп PostgreSQL весит 500 ГБ и разворачивается на тестовом контуре за 2 часа, это НЕ значит, что ваше RTO = 2 часа. Сюда нужно заложить время на обнаружение аварии, развертывание чистой ОС/железа, накатывание конфигов, переключение DNS, валидацию данных и прогрев кэшей. В реальности 2 часа легко превращаются в 8.

  2. Устанавливают одинаковые требования для всех систем. Требовать RTO < 15 минут для платежного шлюза и внутренней wiki — дорого и бессмысленно. Минимальный RTO требует другой архитектуры: репликации, standby-контуров, автоматизации failover, мониторинга и регулярных учений. Это стоит денег.

  3. Не тестируют восстановление. DR-план, который ни разу не проверялся, — это не план, а гипотеза. Его реальная эффективность станет понятна только во время аварии, то есть в худший возможный момент.

  4. Не учитывают зависимости. Сервис может быть восстановлен формально, но не работать из-за мертвой CRM, очереди, LDAP, DNS, Vault, object storage или внутреннего API. Поэтому DR нужно проектировать не для отдельных серверов, а для цепочек зависимостей.

Как мы получили 11 часов простоя вместо четырех

Несколько лет назад я участвовал в разборе крупного сбоя в корпоративной инфраструктуре. На бумаге всё выглядело хорошо: RTO — 4 часа, DR-план утвержден, бэкапы регулярно складываются в архив.

Но когда боевой кластер СУБД вышел из строя, штатный сценарий восстановления оказался нежизнеспособным. Вместо четырех часов система оставалась недоступной одиннадцать.

Проблем оказалось две.

Bus-фактор и монополия на доступы

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

Инфраструктура была технически готова к восстановлению, но организационно процесс остановился.

Неучтенные каскадные зависимости

Основную систему удалось поднять примерно за 3 часа. Формально мы укладывались в целевой RTO.

Но приложение при запуске обращалось во внутреннюю legacy-CRM для валидации профилей. При проектировании DR эту CRM посчитали второстепенной и не включили в приоритетный контур восстановления.

В результате core-сервис начал тонуть в таймаутах, ожидая ответа от смежного компонента. Пришлось на ходу восстанавливать legacy-окружение, менять конфигурацию и перепроверять цепочку вызовов. Именно эти зависимости и съели большую часть времени.

Вывод простой: если система не может работать без зависимости, эта зависимость тоже часть вашего DR-плана.

Как рассчитать RTO и RPO

Процесс не должен начинаться с фразы «бизнес хочет 15 минут». Сначала нужно понять, какие системы действительно критичны и сколько стоит их простой.

Рабочий алгоритм выглядит так:

  1. Инвентаризировать сервисы, базы данных, очереди, внешние API и инфраструктурные зависимости.

  2. Провести BIA, Business Impact Analysis: оценить потери от простоя каждого сервиса.

  3. Разделить системы по критичности.

  4. Назначить RTO/RPO с учетом стоимости простоя и стоимости реализации DR.

  5. Подобрать технологический подход: backup, PITR, репликация, standby, DRaaS.

  6. Проверить цифры через тестовое восстановление.

  7. Регулярно обновлять DR-план после изменений в архитектуре.

Пример матрицы:

Иллюстрация: Хайстекс
Иллюстрация: Хайстекс

Эта таблица не универсальна. Для одной компании CRM может быть вспомогательной системой, а для интернет-магазина — критическим элементом продаж. Поэтому матрица должна строиться от бизнес-процессов, а не от названий систем.

PostgreSQL: почему одного ночного бэкапа недостаточно

Если целевой RPO меньше 15 минут, а RTO меньше 1 часа, обычного pg_dump раз в сутки недостаточно.

Для PostgreSQL production-сценарий обычно строится вокруг нескольких уровней защиты:

  • потоковая репликация для быстрого failover;

  • base backup как стартовая точка восстановления;

  • WAL-архив для Point-in-Time Recovery;

  • регулярные restore-тесты;

  • мониторинг replication lag и состояния WAL-архивации.

Важно помнить: репликация не заменяет бэкап.

Репликация помогает при отказе узла. Но если приложение выполнит ошибочный DELETE, реплика быстро и честно повторит эту операцию. Для восстановления после логической ошибки нужен PITR: base backup плюс WAL-архив, позволяющий откатиться к моменту до инцидента.

Упрощенная схема:

[ Clients / API ]
        │
        ▼
[ HAProxy / PgBouncer / Router ]
        │
        ▼
[ PostgreSQL Primary ] ── WAL streaming ──► [ PostgreSQL Standby ]
        │                                           │
        ▼                                           ▼
[ WAL archive / Backup storage ]            [ Monitoring ]
        │
        ▼
[ PITR restore target ]

PgBouncer или балансировщик сам по себе не решает задачу failover. Он только направляет трафик. Выбор нового primary, защита от split-brain и управление переключением должны быть реализованы отдельным механизмом: Patroni, repmgr, Pacemaker/Corosync, managed-сервисом облака или DR-платформой.

Как мониторить риск нарушения RPO в PostgreSQL

Для асинхронной репликации replication lag — один из ключевых индикаторов риска нарушения RPO. Но важно понимать, какой именно тип задержки мы измеряем в конкретный момент.

На мастер-ноде (primary) для этого полезно анализировать системное представление pg_stat_replication:

SELECT
    application_name,
    client_addr,
    state,
    sync_state,
    pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn)   AS send_lag_bytes,
    pg_wal_lsn_diff(pg_current_wal_lsn(), write_lsn)  AS write_lag_bytes,
    pg_wal_lsn_diff(pg_current_wal_lsn(), flush_lsn)  AS flush_lag_bytes,
    pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS replay_lag_bytes,
    write_lag,
    flush_lag,
    replay_lag
FROM pg_stat_replication;

Эти значения помогают понять, где именно возникло отставание:

  • WAL еще не отправлен на standby;

  • WAL получен, но не записан;

  • WAL записан, но не сброшен на диск;

  • WAL сброшен, но еще не применен.

Для оценки готовности standby к переключению (promotion) особенно важен replay lag: если WAL-сегменты уже получены репликой, но еще не применены, резервный узел не сможет мгновенно взять на себя роль нового primary.

На самой реплике (standby) можно дополнительно оценивать разницу между полученным и примененным объемом WAL:

SELECT pg_wal_lsn_diff(
    pg_last_wal_receive_lsn(),
    pg_last_wal_replay_lsn()
);

Важно: этот запрос показывает только внутреннее отставание реплики между процессами получения (receive) и применения (replay). Для полноценного контроля отставания от мастера его одного недостаточно.

Пример простого Bash-скрипта для дежурной проверки replay lag со стороны мастера (primary):

#!/usr/bin/env bash

DB_USER="postgres"
DB_NAME="core_prod"
MAX_ALLOWED_REPLAY_LAG_BYTES=16777216 # 16 МБ (1 WAL-сегмент)

LAG_BYTES=$(psql -U "$DB_USER" -d "$DB_NAME" -t -A -c "
SELECT COALESCE(
    MAX(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)),
    0
)
FROM pg_stat_replication;
")

if [[ ! "$LAG_BYTES" =~ ^[0-9]+$ ]]; then
    echo "CRITICAL: failed to get PostgreSQL replication lag"
    exit 2
fi

echo "Current max replay lag: $LAG_BYTES bytes"

if [ "$LAG_BYTES" -gt "$MAX_ALLOWED_REPLAY_LAG_BYTES" ]; then
    echo "WARNING: replication lag exceeds RPO threshold"
    exit 1
fi

echo "OK: replication lag is within threshold"
exit 0

Конечно, в полноценном production-окружении подобные скрипты лучше заменить нативной интеграцией с Prometheus, Zabbix или другой системой мониторинга. Но сам принцип остается неизменным: RPO должно быть непрерывно наблюдаемой метрикой, а не просто декларативной строкой в документе.

Чем закрывать целевые RTO и RPO

Выбор технологии зависит от критичности системы, бюджета и допустимой потери данных.

  • Резервное копирование (Backup). Самый базовый уровень защиты. Подходит для стандартных и некритичных систем. RPO зависит от частоты копирования, RTO — от размера данных и скорости восстановления. Но backup без регулярного restore-теста не гарантирует восстановление. Это просто файл неизвестного качества.

  • Восстановление на момент времени (PITR). Для баз данных, особенно PostgreSQL, Point-in-Time Recovery часто является обязательным элементом. Он помогает восстановиться не только после падения сервера, но и после логической ошибки: неудачной миграции, ошибочного удаления данных, повреждения таблиц.

  • Репликация. Подходит для критичных систем, где нужно быстро переключиться на резервный узел. Синхронная репликация может приблизить RPO к нулю для подтвержденных транзакций, но не отменяет риски логических ошибок, неправильного failover, split-brain и каскадной порчи данных. Асинхронная репликация быстрее и проще, но допускает lag. Поэтому ее нужно мониторить и явно связывать с допустимым RPO.

  • Облачное аварийное восстановление (DRaaS). Когда систем много, зависимости сложные, а бизнес требует предсказуемого восстановления, ручные скрипты становятся рискованными. В таких случаях применяют DRaaS-подход: резервный контур, репликация машин или данных, заранее описанный порядок запуска и автоматизированный failover.

Например, в Хайстекс Акура используется подход с блочной репликацией машин. Вместо того чтобы адаптировать каждое приложение отдельно, в резервный контур непрерывно реплицируются диски, а сценарий восстановления описывается заранее: какие машины поднять, в каком порядке, с какими сетевыми настройками и проверками.

Такой подход особенно полезен там, где нужно восстанавливать не одну базу, а связанный набор сервисов.

Как проверить, что RTO/RPO достижимы

Единственный надежный способ — регулярные DR-тесты. Необязательно сразу отключать боевую площадку (production). Тестировать восстановление можно в изолированном контуре: поднять standby, восстановить базу из бэкапа и WAL-архива, проверить порядок запуска сервисов и замерить время переключения.

Я подготовил два базовых инструмента: пошаговый чек-лист для проведения самих учений и перечень критических параметров инфраструктуры, которые необходимо непрерывно контролировать в процессе восстановления.

  • Минимальный чек-лист для проведения DR-учений

  • Что обязательно мониторить

Правильно настроенный Disaster Recovery нужен не для красивого SLA, а для того, чтобы перевести ликвидацию аварии из режима хаоса в управляемый процесс. Не стоит пытаться защищать все системы одинаково. Нужно честно определить, какие сервисы критичны для бизнеса, просчитать стоимость их простоя, установить для них реалистичные RTO/RPO и проверить эти цифры на практике.

Бэкапы нужно не только создавать, но и восстанавливать. Репликацию — не только включать, но и мониторить. DR-планы — не только писать, но и регулярно прогонять в тестовом контуре.

И главное: если восстановление ни разу не проверялось, оно еще не существует.

Комментарии (2)


  1. RMastiyev
    30.06.2026 13:57

    Спасибо за разбор, жизненно! В формулу RTO я бы добавил еще один скрытый тайм-киллер — «время на совещание». На практике, если RTO равен 2 часам, первый час часто уходит на панику, сбор экстренной летучки и пинги руководства в духе: «А точно переключаем? А данные не потеряем?». Если у дежурного инженера нет жесткой инструкции и права нажать кнопку Failover без согласования с бизнесом, то все технические метрики летят в трубу.


  1. shut-down-now
    30.06.2026 13:57

    Хорошо расписано, но наоборот "не жизненно". В жизни встречаются интеграторы, которые и слов таких не знают SLA, RTO, RPO .