MAATRIX / Блог / Резервный сервер не включился, когда понадобился

Резервный сервер не включился, когда понадобился

MAATRIX

Основной сервер упал — и вы спокойно переключаетесь на резервный, который готовили именно для этого случая. А он не поднимается: данные не той версии, конфиг не совпадает с продом, скрипт переключения падает на шаге, о котором никто не вспомнил. План, который должен был спасти ситуацию за пять минут, превращается в аварийное восстановление с нуля — только теперь без времени на раздумья. Разберём, почему так происходит почти всегда, если резерв ни разу не проверяли по-настоящему, и что сделать, чтобы в следующий раз он действительно сработал.

Резервный план, который жил только на бумаге

Самая частая формулировка после провала: «у нас же был резервный сервер». Был. Его арендовали, настроили, даже показали на совещании как доказательство отказоустойчивости — и с этого момента он превратился в строчку в документации, которая исправно существовала месяцами, а иногда годами.

Ирония в том, что именно эта видимая готовность убивает бдительность. Резервный сервер числится в списке ресурсов, отвечает на пинг, иногда проходит формальную «проверку» — кто-то заходит по SSH, видит запущенные процессы и закрывает тикет. Но между «сервер жив» и «сервер реально примет продовую нагрузку прямо сейчас» — пропасть, которую заполняет только одно: попытка по-настоящему на него переключиться. Пока такой попытки не было, резервный план — это гипотеза, а не факт.

Это не история про конкретную компанию, а обобщённый разбор того, что типично идёт не так, когда резерв встречает реальную аварию впервые. Три причины ниже по отдельности звучат очевидно, но вместе образуют паттерн, который повторяется в большинстве несработавших disaster recovery планов.

Причина первая: резервные данные — это данные из прошлого

Самая частая техническая причина провала: на резервном сервере лежат не те данные. Не потому что про синхронизацию забыли в принципе — обычно её настраивали, и какое-то время она честно работала. Проблема в том, что синхронизация базы, файлового хранилища и состояния приложения — это не разовая задача, а процесс, который должен пережить обновления схемы БД, смену форматов хранения, миграции на новые версии сервисов. Он либо развивается вместе с продакшеном, либо тихо отстаёт.

Типичный сценарий: реплику базы данных настроили при запуске проекта. Потом добавили новую таблицу с очередями задач в отдельном движке (Redis, RabbitMQ) — её в план резервирования не включили, потому что «это же не основная база». Потом переехали с локального диска на объектное хранилище для файлов — а cron-задача, которая раз в сутки rsync'ила файлы на резерв, продолжает синхронизировать старую, уже не используемую директорию. Формально «бэкапы идут», по факту они синхронизируют пустоту.

Отдельная ловушка — путаница между бэкапом и живой репликацией. Бэкап, снятый месяц назад, и потоковая репликация с отставанием в секунды — это принципиально разные уровни готовности, но в документации оба варианта часто описаны одним словом «резервирование». Механика самой репликации и то, откуда берётся отставание, разобраны в статье как работает репликация и отставание реплики.

Практическая проверка, которую стоит сделать прямо сейчас, не дожидаясь аварии:

# на резервном сервере — когда реально последний раз обновлялись данные
stat -c '%y' /var/lib/postgresql/*/main/base/ 2>/dev/null | sort | tail -1

# для потоковой репликации PostgreSQL — текущее отставание в секундах
psql -U postgres -c "SELECT now() - pg_last_xact_replay_timestamp() AS replication_lag;"

# для файлового rsync — дата последнего успешного запуска
grep -a "rsync error\|total size" /var/log/rsync-backup.log | tail -20

Если эти команды показывают «последний раз обновлялось три месяца назад» или лог синхронизации молчит уже неделю — вы нашли будущую точку отказа заранее, а не в момент, когда основной сервер уже лежит.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Причина вторая: конфигурация, которая разошлась незаметно

Данные — это только половина проблемы. Вторая половина — конфигурация: версии пакетов, переменные окружения, правила файрвола, сертификаты, cron-задания, настройки веб-сервера. На старте резервный сервер обычно клонируют с продового максимально точно. А дальше жизнь идёт своим чередом: на проде правят nginx.conf под новый домен, добавляют лимит запросов, меняют версию PHP или Node.js, выпускают новый SSL-сертификат — и всё это делают только на основном сервере, потому что «сейчас некогда, продублирую потом».

«Потом» наступает редко. Через полгода конфигурации основного и резервного серверов расходятся десятками мелких деталей, ни одна из которых сама по себе не выглядит критичной. Но в сумме они дают ситуацию, когда резервный сервер поднимает сервис — а тот падает на первом же запросе, потому что ожидает переменную окружения, которую на проде добавили три месяца назад, а на резерве её попросту нет.

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

ПодходНадёжностьЧто нужно
Ручное копирование файлов конфигурацииНизкая — расходится за неделиДисциплина и чек-лист (не масштабируется)
Configuration management (Ansible, Salt)ВысокаяПлейбук, применяемый к обоим серверам из одного репозитория
Инфраструктура как код (Terraform + провижининг)ВысокаяОписание сервера в коде, резерв — тот же код с другим адресом
Docker/Compose с образами из реестраВысокая для приложенияОдин и тот же образ разворачивается и на проде, и на резерве

Практический ориентир: если конфигурацию резерва нельзя развернуть за один прогон плейбука или один docker compose up из того же репозитория, что и прод, — она неизбежно разойдётся, вопрос только времени.

Причина третья: переключение существовало только в чужой голове

Даже если данные свежие, а конфигурация идентична, остаётся третий и самый коварный источник провала — сама процедура переключения. В момент аварии нужно не просто «включить» резервный сервер, а перенаправить на него трафик: поменять A-запись в DNS, обновить конфигурацию балансировщика, переключить VIP-адрес, пересоздать правила проксирования, иногда — вручную промоутнуть реплику базы данных в мастер.

Проблема в том, что эту последовательность действий обычно знает один человек — тот, кто настраивал резерв изначально. Он держит в голове порядок шагов и пару неочевидных нюансов («сначала снизить TTL DNS-записи, подождать распространения, и только потом менять сам адрес»), которые не попали ни в один документ, потому что казались «само собой разумеющимися» в момент настройки.

Когда авария случается, а этот человек недоступен или не успевает отреагировать первым — переключение делает кто-то другой по обрывочным заметкам. Пропущенный шаг — например, не сброшенный заранее TTL DNS-записи, из-за которого клиенты ещё час обращаются по старому адресу, — превращает быстрое переключение в растянутый на часы инцидент. О похожей механике распространения изменений можно почитать в статье про гео-DNS и когда он вообще нужен: принцип «TTL решает, как быстро мир увидит изменение» работает и в обычном failover-сценарии.

Правильная процедура переключения — это не документ «на всякий случай», а рабочий runbook, который проверяли на практике хотя бы раз, желательно — несколько раз разными людьми:

Runbook: переключение на резервный сервер (пример структуры)
1. Подтвердить недоступность основного сервера (2 независимых проверки)
2. Промоутнуть резервную БД в мастер: `pg_ctl promote -D /var/lib/postgresql/data`
3. Обновить A-запись основного домена на IP резерва
4. Проверить, что TTL записи снижен заранее (см. пункт "за неделю до")
5. Перезапустить сервисы приложения на резервном сервере
6. Прогнать smoke-тест: главная страница, логин, ключевой API-эндпоинт
7. Уведомить команду и пользователей о переключении
8. Мониторить логи резерва первые 30 минут после переключения

Ключевая деталь — пункт «за неделю до»: TTL DNS-записи нельзя снизить в момент аварии, это нужно делать заранее и держать постоянно низким для критичных записей, иначе даже правильно выполненное переключение растянется на время старого TTL.

Главный вывод: резерв без учений — это иллюзия, а не защита

Все три причины выше объединяет один факт: план существовал только в теории. Данные считались синхронизированными — потому что задача синхронизации была один раз поставлена. Конфигурация считалась идентичной — потому что была идентичной в момент создания резерва. Процедура переключения считалась понятной — потому что была понятна тому, кто её придумал. Ни одно из этих предположений никогда не проверялось практикой.

Это системная, а не случайная ошибка: задача, отмеченная как «сделано» после разовой настройки, перестаёт получать внимание — ресурсы идут туда, где горит здесь и сейчас, а резерв не горит никогда, пока не понадобится по-настоящему.

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

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

Как проводить настоящий game day, а не имитацию

Разница между «тестом», который ничего не доказывает, и настоящим учением — в том, насколько условия приближены к реальной аварии. Проверка «зашёл по SSH, увидел, что процесс запущен» ничего не говорит о готовности резерва. Реальное учение выглядит иначе:

  • Полноценное переключение, а не имитация. На согласованное время (например, ночное окно с наименьшей нагрузкой) трафик реально направляется на резервный сервер по тому же runbook и теми же людьми, что будут делать это при настоящей аварии. Не «представим, что переключились», а буквально меняем DNS-запись или вес в балансировщике.
  • Ротация ответственных. Runbook выполняет не тот, кто его писал, а другой инженер по документации. Это моментально вскрывает пропущенные шаги и неявные предположения, которые автор процедуры считал очевидными.
  • Фиксированная периодичность. Разовое учение отвечает только на вопрос «сработает ли план сейчас», но не на вопрос «будет ли он работать через полгода», когда конфигурация снова успеет разойтись. Ориентир — раз в квартал для критичных сервисов, раз в полгода для остальных; точная частота зависит от того, как часто меняется инфраструктура именно у вас.
  • Разбор результатов без поиска виноватых. Цель учения — найти, что не в порядке, пока это не стоит реальных денег, а не доказать, что всё хорошо. Каждое расхождение — повод обновить процедуру, а не наказать исполнителя.
  • Обязательный откат обратно. Учение заканчивается не успешным переключением, а успешным возвратом на основной сервер по той же документированной процедуре — обратный путь репетируют ещё реже, поэтому именно там чаще всего прячутся сюрпризы.

Расписание регулярных учений стоит вести так же серьёзно, как расписание бэкапов — например, напоминать о них через простой cron-мониторинг вроде healthchecks.io для мониторинга cron-заданий, который просигналит, если очередное плановое учение не было отмечено как выполненное.

Автоматизация вместо ручной дисциплины

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

Для данных это переход от разовых ручных копирований к постоянной автоматической репликации с мониторингом отставания — потоковая репликация БД, а не ночной дамп «на всякий случай», плюс алерт, если lag превышает согласованный порог:

# пример простой проверки отставания репликации с алертом
LAG=$(psql -U postgres -tAc "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))")
if (( $(echo "$LAG > 300" | bc -l) )); then
    echo "ALERT: replication lag ${LAG}s" | mail -s "Repl lag warning" ops@example.com
fi

Для конфигурации — обязательное применение одного и того же плейбука или манифеста к обоим серверам, желательно как часть CI/CD-пайплайна: изменение конфигурации прода автоматически применяется и к резерву в рамках того же деплоя, а не отдельным ручным действием, про которое можно забыть.

Для самой процедуры переключения — минимизировать число ручных шагов через скрипты и оркестрацию (health-check → авто-промоушен реплики → обновление записи в балансировщике одной командой), оставляя человеку решение «переключаться или нет», а не набор команд, которые нужно вспомнить под давлением времени. Выбор между постоянно включённым «горячим» резервом и поднимаемым по необходимости «холодным» — с разными требованиями к автоматизации для каждого варианта — разобран в статье резервный сервер: горячий или холодный режим.

Итоговая формула простая: то, что делается руками и не проверяется регулярно, рано или поздно перестаёт работать именно тогда, когда это станет заметно дороже всего.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Как часто нужно проводить учения по переключению на резерв?

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

Можно ли ограничиться тестовым переключением без реального трафика?

Лучше, чем ничего, но это не проверяет главное — поведение под реальной нагрузкой и человеческий фактор при выполнении процедуры под давлением. Учение с реальным трафиком в контролируемом окне выявляет то, что тестовый прогон не покажет.

Что делать, если полноценные учения кажутся слишком рискованными?

Начните с некритичного по времени окна (ночь, выходной, минимум нагрузки) и с менее критичного сервиса, чтобы наработать уверенность перед учением на основном продакшене.

Достаточно ли настроить автоматическую репликацию БД, чтобы считать резерв готовым?

Нет — репликация закрывает только часть проблемы данных. Конфигурация приложения, сертификаты, cron-задачи и сама процедура переключения трафика требуют отдельной проверки.

Кто должен отвечать за проведение учений?

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

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →