Привет, Хабр!
В ночь на 11 октября остановился дата-центр Яндекса во Владимире. За неделю до этого отключились площадки в Сасово и Калуге. 11 октября Yandex Cloud объявил аварийный режим и посоветовал клиентам использовать «любые другие альтернативные планы по аварийному восстановлению».
У многих команд другого плана не было. Реплика жила в соседней зоне доступности, снапшоты в том же регионе, бэкапы в том же облаке. Такую схему советуют годами, и против отказа железа она в целом-то работает. Октябрь показал, что отказ целого региона в неё не входит.
В статье разберем, где именно ломается привычная схема «реплика плюс бэкап», сколько на самом деле занимает восстановление и что настроить, чтобы потеря региона не превратилась в потерю данных. Отдельно коротко: что делать в первые часы простоя, что проверить после восстановления и как зафиксировать убытки.
Что было в октябре
В Сасово площадка мощностью около 12 МВт получила повреждения и встала полностью. В Калуге часть модулей вышла из строя в самом крупном ДЦ Яндекса — 63 МВт и около 3800 стоек. Во Владимире остановилась вся площадка примерно на 40 МВт, вместе с ней замолчала зона ru-central1-a и суперкомпьютер «Галушкин». Несколько тысяч жителей города остались без света.
Потом сбои стали заметны уже без всяких отчётов. Ложились Яндекс Про и почта, Циан и Twinby, такси в трёх соседних странах. В Yandex Cloud заморозили квоты на создание новых ресурсов, поддержка отвечала с перебоями. К вечеру 11 октября Яндекс договорился с Selectel, VK Cloud и К2Cloud о приоритетном приёме клиентов по программе CloudBro, а позже добавил в соглашение новые пункты о форс-мажоре.
Прошло 3 недели. Зона ru-central1-b на странице статуса всё ещё недоступна.
Первые часы, когда всё лежит
Начинаем не с восстановления, а с того, что видно снаружи. На странице статуса Yandex Cloud смотрим, какие зоны и сервисы затронуты, и пишем в поддержку: какие данные недоступны, можно ли их восстановить и когда. Пока ответа нет, ничего не удаляем и не перезаписываем. Файл, который не открывается, ещё не потерян.
Дальше список того, что остановилось: приём заказов, клиентская база, отправка документов, выставление счетов. Первыми поднимаем то, от чего зависят выручка и обязательства перед клиентами. Остальное подождёт.
На время простоя процессы переводятся на запасные инструменты:
Что лежит |
Как работать временно |
|---|---|
CRM с заказами и контактами |
новые заказы в общей таблице для сотрудников |
Корпоративная почта |
запасной ящик или мессенджеры |
Интернет-магазин |
заказы по телефону и в мессенджерах |
Хранилище документов |
локальные копии файлов |
Выставление счетов |
счёт вручную в Excel или Word, отправка почтой |
Клиентов предупреждаем на сайте и в соцсетях. Что случилось, как заказать другим способом, куда писать по срочным вопросам. Если сроки восстановления неизвестны, дату не обещаем, просто регулярно публикуем обновления.
А еще есть реклама. Показы в Яндекс Директе во время сбоя продолжались, остановить кампании было невозможно, деньги списывались за клики и конверсии. Пока кабинет недоступен, остаётся обрабатывать заявки и сохранять данные о расходах. После восстановления сверяем статистику и списания, при расхождениях идём в поддержку.
Почему не спасли зоны доступности
Зона доступности в документации Yandex Cloud — это по сути инфраструктура внутри дата-центра, изолированная от аппаратных и программных сбоев других зон. Пожар в одном здании не гасит соседнее, отказ стойки не трогает соседнюю. Развёртывание в двух зонах закрывает отказ железа, питания и сети одной площадки.
Вопрос в том, что в этот список не входит. Зоны ru-central1 разнесены по Владимиру, Рязани и Калуге, но все принадлежат одному региону. Второй регион платформы находится в Казахстане, с отдельной консолью и отдельным биллингом, и мало кто держит там резерв про запас. Когда из строя выходят несколько площадок одновременно, расстояние между зданиями внутри региона уже ничего не решает.
Есть зависимость и похуже. Control plane, который создаёт виртуальные машины, выдаёт квоты и хранит образы, живёт в том же регионе, что и ваши ресурсы. В аварийном режиме поднять новую ВМ может не получиться даже в живой зоне. В вашем runbook первым пунктом написано «создать машину», а на практике этот пункт превращается в тикет в перегруженную поддержку. Управляемые базы устроены так же. Кластер Managed PostgreSQL с репликами в 3 зонах переживает отказ любой одной, но все 3 реплики остаются внутри региона.
Где на самом деле лежит ваш бэкап
Если ничего не настраивать специально, облако складывает копии рядом с данными. Снапшот диска остаётся в той же зоне, автоматические копии управляемой базы в том же регионе. Бакет Object Storage считается глобальным ресурсом, но глобальным внутри региона. Галочка резервного копирования включена с первого дня проекта, и вопрос выглядит закрытым. Иногда аж до 11 октября.
Ну и про снапшоты. Снапшот диска — это crash-consistent копия. Он выглядит так, будто у машины выдернули питание. PostgreSQL такое переживёт за счёт WAL, но только если весь WAL лежит на том же диске и успел сброситься. Если WAL на отдельном диске или в таблице шла большая транзакция, после подъёма из снапшота можно получить битые данные, и узнаете вы об этом уже при проверке. Для базы осмысленная копия — это pg_dump, физическая реплика или снапшот, снятый после чистой остановки.
Второе открытие ждёт тех, кто решил забрать данные наружу. Образ или снимок диска из Yandex Cloud штатно не скачивается. Путь один. Создаём вспомогательную ВМ, подключаем к ней диск из снапшота, конвертируем qemu-img в qcow2, грузим файл в бакет и уже оттуда скачиваем. Либо dd по ssh, про него ниже. В обычной ситуации через это проходят единицы, в основном при миграциях.
Сколько длится восстановление на самом деле
Про время восстановления обычно говорят «поднимем за час». Собрал базу, похожую на настоящую: PostgreSQL 15 на локальной машине с SSD, таблица заказов на 10 млн строк, 2,5 ГБ вместе с двумя индексами, текстовый payload по 160 символов в строке. И прогнал полный цикл с секундомером.
pg_dump -Fc 43 с файл 453 МБpg_restore -j1 85 с загрузка данных 40 с построение индексов 44 сpg_restore -j4 (3 ядра) 86 с
Восстановление заняло вдвое больше времени, чем копия. Половина этих 85 секунд ушла на индексы. В дампе от индекса лежит только одна DDL-строка, а время съедает построение B-tree по 10 млн ключей. Так что pg_restore почти никогда не равен pg_dump по длительности.
С флагом -j4 я ждал ускорения и не получил его. Параллельность в pg_restore работает по объектам. Одна таблица означает одну задачу COPY, толстая таблица на потоки не делится. На базе из десятка сопоставимых таблиц расклад будет другим, а сервис с одной жирной таблицей заказов восстанавливается фактически в один поток. Ускорить восстановление можно памятью. Поднимите maintenance_work_mem на время восстановления, чтобы построение индексов не пилило диск сортировками, и max_parallel_maintenance_workers, если ядер хватает. Потоки pg_restore делят работу между таблицами, а эти настройки ускоряют работу внутри одной.
Теперь перенесём пропорцию на объём из жизни. Терабайтная база при той же скорости диска даст дамп примерно за 5 часов и восстановление примерно за 10. Ночной бэкап такой базы означает RTO в полдня, и это при условии, что файл уже лежит на целевой машине, машина существует и СУБД установлена. В октябрьском сценарии перед этими 10 часами стоят ещё поиск мощностей при замороженных квотах, установка, накат WAL и проверка данных.
Заметьте, сам pg_restore в этой истории ещё не самое страшное. Полный RTO складывается из цепочки: найти мощности, получить доступы, поднять СУБД, скачать файл, восстановить, накатить WAL, проверить, переключить трафик. Каждое звено по отдельности выглядит мелочью. В день аварии они складываются в сутки.
А еще я сверил count и sum(amount) в оригинале и в копии и получил одинаковые числа: 10 000 000 строк и 250 013 654 577,58 рубля, до копейки. Такая сверка занимает минуту и остаётся единственным способом узнать, что копия рабочая. Если сверки нет в расписании, копия считается непроверенной.
Как увезти терабайт из деградировавшего региона
До pg_restore файл ещё нужно получить. В деградировавшем облаке трафик шёл по резервным каналам, и те, кто качал архивы в те дни, описывали скорость как магистраль, сжатую до переулка.
Дальше школьная арифметика. В терабайте 8 терабит. По каналу 100 Мбит/с это 80 000 секунд, то есть 22 часа без единого обрыва. Гигабитный канал сокращает передачу до 2 часов 15 минут. Обрыв на 90% без докачки означает начать сначала, поэтому rsync здесь заметно полезнее scp.
Штатная команда для снятия образа диска выглядит так:
ssh user@<ip-временной-ВМ> "sudo dd if=/dev/sdb status=progress | gzip -c" > disk.img.gz
На текстовых дампах gzip выигрывает раз в 5, и 22 часа превращаются в 4 с небольшим. dd снимает образ с блочного устройства, поэтому машину перед этим останавливают, иначе образ получится рассогласованным. В октябре добавился ещё один подвох. Чтобы забрать данные, нужно создать временную ВМ в том же регионе, а квоты заморожены.
Схема, которая переживает потерю региона
Всё ниже работает только если сделано до аварии. Пункты идут от дешёвого к дорогому, можно остановиться на любом, если понимаете, какой риск оставляете.
Первый уровень — дамп в чужое хранилище. pg_dump по расписанию, файл уезжает в Object Storage другого провайдера или на своё железо, контрольная сумма считается сразу:
pg_dump -Fc shop -f shop-$(date +%F).dumpsha256sum shop-$(date +%F).dumpaws s3 cp shop-$(date +%F).dump s3://dr-backups/ \ --endpoint-url https://s3.<другой-провайдер>
Стоит это egress-трафиком и вторым биллингом. Ключи от резервного хранилища нельзя держать в Lockbox того же региона, иначе в день аварии бэкап есть, а подойти к нему не с чем. Туда же, наружу, уезжают SSH-ключи, резервные коды 2FA и сам runbook. Включите версионирование бакета, если провайдер его даёт. Оно пригодится в другой популярной катастрофе, когда бэкап затирают сами.
Второй уровень — физическая реплика у второго провайдера. PostgreSQL на ВМ в другом облаке получает WAL с основной площадки, RPO падает до минут, а восстановление сводится к promote вместо десятичасового pg_restore. Платим постоянной второй инфраструктурой. По моей прикидке это 30–40% стоимости основной площадки в месяц без учёта трафика. За репликой нужно следить так же, как за продом: мониторить отставание (pg_last_wal_receive_lsn против pg_current_wal_lsn на мастере), обновлять версии, раз в квартал делать учебный promote.
Третий уровень — учебное восстановление. Раз в квартал бэкап поднимается в чистую базу, сверяются count и sum, время засекается:
createdb shop_restorepg_restore -j 4 -d shop_restore shop.dumppsql -d shop_restore -c "select count(*), sum(amount) from orders;"
Это единственный способ проверить, что дамп вообще читается, а не просто занимает место в бакете.
И мелочь — TTL у DNS. При 3600 секундах переключение на резервную площадку растянется минимум на час даже при идеальном подъёме. Значение 60–300 секунд выставляется заранее, до аварии.
Что проверить, когда сервисы поднялись
Первым делом заказы и платежи. Заявки из CRM, магазина, почты и запасной таблицы сводим в один список и смотрим, что потерялось, что задвоилось, совпадают ли статусы заказов с фактическими оплатами. Заявки, принятые вручную за время простоя, переносим в основные системы. Иначе дубли вылезут при следующей сверке.
Про чеки было разъяснение ФНС. После восстановления сервисов чеки должны сформироваться автоматически, в том числе у самозанятых, которые работают через продукты Яндекса.
Самозанятым советовали не формировать их вручную в «Моём налоге» до 1 ноября 2026 года, чтобы не задвоить. Если к этой дате чеки не пришли, доход нужно отразить самостоятельно не позднее 9 ноября 2026 года. У предпринимателей с онлайн-кассой проверяем, все ли чеки сформированы. ФНС допустила освобождение от штрафа за неприменение ККТ из-за сбоя, но решать будут по каждому случаю отдельно.
Дальше интеграции. Заявки снова попадают в CRM, письма уходят клиентам, учётная система обменивается данными с сервисами Яндекса. Операции, которые не выполнились за время простоя, запускаем повторно и проверяем результат. В Метрике и Директе смотрим, что статистика собирается, кампании запущены и бюджет расходуется как задумано.
Как посчитать убытки и дойти до претензии
Недоступность сервиса сама по себе компенсацию не гарантирует. Сначала собираем подтверждения.
Прямые расходы считаются проще всего: аренда серверов у другого провайдера, оборудование, работа специалистов, восстановление данных. Сохраняем договоры, счета и документы об оплате. Потерянную выручку оцениваем по заявкам, продажам и отменённым заказам, например сравниваем выручку за дни простоя со средней за такой же период. Но связь потерь именно со сбоем придётся доказывать. Упущенная выгода взыскивается тяжелее, а за нематериальные активы вроде разработок и файлов примерной оценки недостаточно.
Договор с провайдером читаем до претензии: ответственность за сбои, возврат денег за простой, форс-мажор. Новые пункты о форс-мажоре в соглашении Яндекса не освобождают его автоматически от любой ответственности, всё зависит от условий договора и обстоятельств сбоя. В претензию идут сообщения провайдера о сбое, переписка с поддержкой, список сорванных заказов и расчёт потерь с подтверждениями.
Что сделать на этой неделе
Минимальный план для команды, у которой сегодня «реплика в соседней зоне и бэкап в том же облаке»:
Выписать, где физически лежат все копии: снапшоты, управляемые бэкапы, бакеты, ключи, документация. Если весь список умещается в один регион, считать, что копии нет.
Настроить ежедневный дамп с отправкой в хранилище другого провайдера. Ключи и доступы к нему хранить вне основного облака.
Провести учебное восстановление и записать три числа: время подъёма мощностей, время восстановления, отставание данных. Это фактические RTO и RPO, а не те, что написаны в презентации.
Снизить TTL у DNS до 60–300 секунд и завести записи о резервной площадке заранее.
Для баз, где час простоя дороже второй ВМ, поднять физическую реплику у другого провайдера и поставить мониторинг отставания.
Написать runbook на одну страницу: кто поднимает мощности, где лежат доступы, в каком порядке поднимаются сервисы, кто предупреждает клиентов и кто принимает заказы вручную. Хранить его там, где он доступен без основного облака.
Ни зоны, ни снапшоты, ни managed-бэкапы в октябре не сломались. Каждый механизм сделал то, под что проектировался. Просто модель угроз у большинства команд осталась из эпохи, когда худшим сценарием для дата-центра был отказавший дизель. Когда поднимется ru-central1-b и что получат клиенты, чьи данные не выехали, на момент написания не знает никто.
А вы когда в последний раз поднимали бэкап в пустую базу? Сколько заняло на вашем объёме?

За схемой выше стоят люди, которые умеют её настроить и поддерживать. Если таких компетенций в команде не хватает, их проще вырастить заранее, чем искать в пожарном порядке. У OTUS есть корпоративные программы по Linux, Kubernetes, PostgreSQL и DevOps. Программу собирают под стек команды, занятия идут вечером, практика строится на задачах вашей инфраструктуры, а работодатель видит прогресс в личном кабинете. Подробности
Xelld
Использовать pg_dump для DR - сомнительное решение, тем более на базах объемом в несколько терабайт.
pgbackrest и подобные решают эту задачу лучше и быстрее.