К содержанию
ActionPulse

Восстановление из резервной копии

Пошаговое восстановление on-prem ActionPulse — выбор снимка, порядок между хранилищами, версии схемы, проверка целостности, аварийный перенос на место и учебный прогон.

Кому
Операторам установки в аварийной ситуации
Проверено
На этой странице

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

Порядок восстановления

1. Зафиксируйте обстановку и выберите снимок

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

Прочитайте манифест до всего остального. Проверка подписи одновременно отвечает на вопрос «этот снимок вообще пригоден»: документ, у которого состояние не «полный», не пройдёт проверку.

SNAPSHOT=20260713T020000Z-0123abcd

aws s3 cp "s3://$BACKUP_S3_BUCKET/$BACKUP_S3_PREFIX/manifests/$SNAPSHOT.json" \
  manifest.signed.json

docker run --rm -i \
  -e BACKUP_MANIFEST_PUBLIC_KEYS \
  --entrypoint /opt/actionpulse-backup/apbackupctl \
  "$PP_BACKUP_IMAGE_REF" open -snapshot-id "$SNAPSHOT" \
  < manifest.signed.json > manifest.json

jq '{state, started_at, completed_at, schema_versions, consistency, storage}' manifest.json

В schema_versions лежат версии схем PostgreSQL и ClickHouse, в consistency — водяной знак согласованности. Обе величины понадобятся дальше.

2. Подготовьте целевые хранилища

  • PostgreSQL: создайте пустую базу. Роль pp_restore из postgres/roles.sql предназначена именно для этого: она может создавать базы и никогда не используется работающим сервисом.
  • ClickHouse: выберите новое имя базы. Целевой сервер должен видеть ту же именованную коллекцию, что и при копировании: восстановление выполняет сам ClickHouse, читая объекты из вашего хранилища.
  • Закройте доступ к тестовому контуру, остановите в нём отправителей и потребителей, отключите внешние уведомления и не используйте настоящих пользователей.

3. Соберите файл окружения восстановления

Отдельный файл, а не файл работающей установки. Значения — ваши; секретов на этой странице нет намеренно.

Переменная Назначение Обязательность
BACKUP_S3_BUCKET, BACKUP_S3_PREFIX где лежит снимок обязательны
BACKUP_S3_REGION, BACKUP_S3_ENDPOINT параметры доступа к хранилищу по обстоятельствам
BACKUP_S3_SSE_MODE, BACKUP_S3_KMS_KEY_ID ожидаемый режим шифрования; несовпадение с манифестом останавливает прогон обязательна при KMS
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY доступ на чтение объектов снимка обязательны
BACKUP_MANIFEST_PUBLIC_KEYS публичные ключи проверки подписи обязательна
BACKUP_INSTALLATION_ID проверка, что журнал удалений относится к этой инсталляции необязательна
RESTORE_PG_DSN адрес целевой пустой базы PostgreSQL обязательна
RESTORE_CH_HTTP_URL адрес целевого ClickHouse обязательна
RESTORE_CH_DATABASE имя целевой базы ClickHouse обязательна
CH_DATABASE имя базы-источника внутри снимка необязательна
CH_USER, CH_PASSWORD пользователь целевого ClickHouse — сгенерируйте свой пароль обязательны
CH_BACKUP_NAMED_COLLECTION именованная коллекция целевого ClickHouse необязательна
RESTORE_SNAPSHOT_ID идентификатор восстанавливаемого снимка обязательна
RESTORE_CONFIRM подтверждение вида restore-<идентификатор снимка> обязательна
RESTORE_SKIP_CONSISTENCY_RECONCILE отключает сверку по водяному знаку только осознанно
RESTORE_VERIFY_OBJECT_DIGESTS сверка контрольных сумм объектов в хранилище не отключайте

4. Запустите восстановление

docker run --rm \
  --network <сеть, из которой видны целевые PostgreSQL и ClickHouse> \
  --env-file restore.env \
  -e RESTORE_SNAPSHOT_ID="$SNAPSHOT" \
  -e RESTORE_CONFIRM="restore-$SNAPSHOT" \
  -v pp-restore-state:/var/lib/actionpulse-backup \
  --entrypoint /opt/actionpulse-backup/restore.sh \
  "$PP_BACKUP_IMAGE_REF"

Подтверждение RESTORE_CONFIRM должно совпадать с идентификатором снимка посимвольно — это защита от восстановления не того снимка по ошибке в переменной окружения. Контейнеру нужны и целевые базы, и хранилище копий: в поставляемой конфигурации сеть данных (actionpulse-onprem_data) внешнего маршрута не имеет, поэтому маршрут к хранилищу планируется так же, как для копирования.

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

5. Что происходит внутри прогона

Порядок важен: он и есть ответ на вопрос «в каком порядке восстанавливать хранилища».

Этап Что делается Разрушающий
Проверки подпись манифеста; соответствие снимку, бакету, префиксу и режиму шифрования; полная сверка перечня объектов в хранилище (пропавший, лишний, продублированный, обрезанный или подменённый объект — фатальны); журнал удалений тенантов; пустота целевых баз; загрузка дампа PostgreSQL, сверка SHA-256 и разбор его оглавления нет
PostgreSQL pg_restore в выбранную целевую базу да
PostgreSQL проигрывание записей журнала удалений тенантов да
ClickHouse серверное восстановление базы-источника под новым именем да
ClickHouse удаление событий новее водяного знака — обе базы приводятся к одной точке времени да
ClickHouse проигрывание записей журнала удалений, включая внутренние таблицы материализаций да
Redis только для восстановления «на месте»: полная очистка и проверка, что база пуста да
Итог сравнение фактического времени с вашей целью восстановления нет

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

Расхождение версий схемы

Манифест фиксирует версии схем PostgreSQL и ClickHouse, которыми на самом деле являются восстанавливаемые байты. Сверьте их с тем, что применено в той установке, куда вы восстанавливаете:

psql "$RESTORE_PG_DSN" -Atc \
  "SELECT max(version_id) FROM goose_db_version WHERE is_applied"
psql "$RESTORE_PG_DSN" -Atc \
  "SELECT count(*), max(version) FROM ch_schema_migrations"
  • Снимок старше развёрнутого выпуска. Обычный случай. После восстановления прогоните миграции (одноразовый контейнер мигратора) и только потом открывайте контур. Раскатка старого дампа под новым кодом — ваше решение, но оно должно быть осознанным: до миграций часть таблиц, которые ожидает приложение, ещё не существует.
  • Снимок новее развёрнутого выпуска. Не открывайте его. Обратных миграций в продукте нет: сначала разверните выпуск, соответствующий снимку, и лишь потом восстанавливайте.

Как проверить целостность после восстановления

Сценарий проверяет целостность транспорта и схемы: подпись, перечень объектов, контрольные суммы, завершение восстановления ClickHouse и наличие таблиц. Это не бизнес-проверка. До открытия контура сделайте следующее.

  1. Сверьте количества строк и контрольные суммы детерминированных критичных таблиц с вашими значениями до снятия копии. Для этого понадобится читающий доступ к восстановленным базам — у узкой роли копирования его нет.
  2. Прогоните миграции и проверку работоспособности, затем тестовый приём события и ограниченный по времени отчёт в том же часовом поясе и окне. Внешние уведомления должны остаться отключёнными.
  3. Проверьте лицензию и конфигурацию отдельно. Запись о лицензии приезжает с дампом PostgreSQL, но .env, секреты, TLS-материал и LICENSE_PUBKEY в снимок данных не входят. Если после снятия снимка ключ лицензии заменяли, установите текущий заново.
  4. Убедитесь, что сверка по водяному знаку выполнилась. Если вы отключали её осознанно, помните: хранилища тогда не находятся в одной точке времени.
  5. Зафиксируйте результат: фактические количества строк и контрольные суммы, время начала и конца, измеренные потерю данных и время восстановления.

Итог считается успешным, только если восстановлены обе базы и контрольные суммы совпали. Успешная загрузка объектов сама по себе успешным восстановлением не является.

Данные, пришедшие после снимка

Снимок — это точка в прошлом. Разберитесь с промежутком осознанно, а не «как получится».

  • Транспорт NATS. Поток событий хранит до 48 часов, поток записанных сессий — до 24 часов. Если авария уложилась в это окно, часть событий после снимка доедет повторной доставкой. Перед переключением проверьте отставание, после повторной доставки — дедупликацию.
  • Запросы на удаление данных. Старые снимки не переписываются. Возьмите из вашего защищённого реестра все запросы на удаление, поступившие после времени снимка, и повторите их до состояния completed. Иначе восстановление вернёт данные, которые вы обязаны были удалить. Записи журнала удалений тенантов раннер проигрывает сам, но удаление данных отдельного субъекта — нет.
  • Фрагменты записанных сессий. У них нет серверной отметки времени, поэтому за барьером согласованности может остаться до (конец копирования ClickHouse − водяной знак) таких данных. Окно ограничено и записано в манифесте.
  • Redis. При восстановлении «на месте» раннер очищает его синхронно и проверяет, что база пуста. Это обязательная часть переноса, а не уборка: старые ключи привязаны к числовым идентификаторам, которые восстановленный контроль-план может выдать другому тенанту. Частичная очистка по известным префиксам небезопасна.

Частичное восстановление

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

Что действительно возможно:

  • восстановить снимок целиком в изолированный контур и достать оттуда нужное запросами, а затем внести это в рабочую установку своими средствами;
  • восстановить в изолированный контур на конкретную дату, чтобы посмотреть состояние в прошлом;
  • пропустить сверку по водяному знаку, если вам осознанно нужно сырое содержимое ClickHouse.

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

Аварийный перенос на место

Восстановление «на месте» перезаписывает рабочие базы. Оно допустимо только после успешного учебного прогона и документированного решения о переносе.

Требования, которые проверяются и не обходятся:

  • полностью остановлены ingest-api, query-api, ch-writer, worker, а также копирование и проверочный прогон;
  • явно разрешено восстановление «на месте»;
  • задан адрес Redis и одноразовое подтверждение его очистки, тоже привязанное к идентификатору снимка;
  • база Redis принадлежит только ActionPulse. Для внешнего разделяемого Redis этот признак оставляют выключенным — и восстановление «на месте» будет заблокировано, вместо того чтобы очистить чужие данные;
  • пароль Redis передаётся только переменной окружения, чтобы не попасть в аргументы процесса; для TLS задаются признак TLS и файл корневого сертификата.

Учебное восстановление

Без учебного прогона плана восстановления не существует. До первого прогона неизвестно: сколько времени занимает восстановление, хватает ли прав на чтение объектов и расшифровку, доступен ли публичный ключ проверки манифеста, видит ли целевой ClickHouse именованную коллекцию, есть ли у пользователя права в целевой базе, и совпадают ли контрольные суммы.

Что уже делается за вас: сервис проверки в профиле копирования по умолчанию раз в сутки восстанавливает последний полный снимок в выбрасываемые базы и пишет метрики pp_backup_restore_*. Живые базы он не трогает — восстановление «на месте» ему запрещено.

Что нужно делать руками — не реже раза в квартал и обязательно перед опасным крупным обновлением:

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

Частые ошибки

Симптом Причина Что делать
Прогон останавливается на проверке подписи манифест неподписан, подписан неизвестным ключом или изменён не восстанавливайте этот снимок; проверьте список публичных ключей и целостность хранилища
«Целевая база не пуста» цель уже содержит объекты создайте новую цель, а не разрешайте запись в непустую
Отказ по совпадению адресов указан адрес базы-источника цель должна отличаться от источника; «на месте» — отдельная процедура с отдельным подтверждением
Манифеста для снимка нет снимок частичный он не пригоден для восстановления, возьмите предыдущий полный
Объекты ClickHouse не найдены адрес серверного копирования не совпадает с бакетом и префиксом раннера, либо у ClickHouse нет доступа сверьте адрес и права; не подставляйте учётные данные в SQL для проверки
Отказ в доступе на шаге сверки по водяному знаку у пользователя ClickHouse нет прав в целевой базе выдайте права на целевую базу; снимок при этом не повреждён
Прогон завершился, но события не сходятся с ожиданием сработала сверка по водяному знаку либо есть повторная доставка из транспорта сравните водяной знак из манифеста с ожидаемой точкой и проверьте отставание транспорта