Восстановление из резервной копии
Пошаговое восстановление on-prem ActionPulse — выбор снимка, порядок между хранилищами, версии схемы, проверка целостности, аварийный перенос на место и учебный прогон.
На этой странице
- Порядок восстановления
- 1. Зафиксируйте обстановку и выберите снимок
- 2. Подготовьте целевые хранилища
- 3. Соберите файл окружения восстановления
- 4. Запустите восстановление
- 5. Что происходит внутри прогона
- Расхождение версий схемы
- Как проверить целостность после восстановления
- Данные, пришедшие после снимка
- Частичное восстановление
- Аварийный перенос на место
- Учебное восстановление
- Частые ошибки
Восстановление — это разрушающая операция. Сценарий восстановления устроен 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 и наличие таблиц. Это не бизнес-проверка. До открытия контура сделайте следующее.
- Сверьте количества строк и контрольные суммы детерминированных критичных таблиц с вашими значениями до снятия копии. Для этого понадобится читающий доступ к восстановленным базам — у узкой роли копирования его нет.
- Прогоните миграции и проверку работоспособности, затем тестовый приём события и ограниченный по времени отчёт в том же часовом поясе и окне. Внешние уведомления должны остаться отключёнными.
- Проверьте лицензию и конфигурацию отдельно. Запись о лицензии приезжает с
дампом PostgreSQL, но
.env, секреты, TLS-материал иLICENSE_PUBKEYв снимок данных не входят. Если после снятия снимка ключ лицензии заменяли, установите текущий заново. - Убедитесь, что сверка по водяному знаку выполнилась. Если вы отключали её осознанно, помните: хранилища тогда не находятся в одной точке времени.
- Зафиксируйте результат: фактические количества строк и контрольные суммы, время начала и конца, измеренные потерю данных и время восстановления.
Итог считается успешным, только если восстановлены обе базы и контрольные суммы совпали. Успешная загрузка объектов сама по себе успешным восстановлением не является.
Данные, пришедшие после снимка
Снимок — это точка в прошлом. Разберитесь с промежутком осознанно, а не «как получится».
- Транспорт 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_*. Живые базы он не трогает — восстановление «на
месте» ему запрещено.
Что нужно делать руками — не реже раза в квартал и обязательно перед опасным крупным обновлением:
- Отдельный контур, отдельные пустые целевые базы, отдельный файл окружения.
- Полный прогон по шагам с этой страницы, включая сверку количеств строк.
- Повтор запросов на удаление данных, поступивших после времени снимка.
- Замер: фактические потеря данных и время восстановления — не техническая длительность прогона, а время от решения восстанавливаться до проверенного переключения. В него входят согласования, проверки и сверка приватности.
- Запись результата и обновление ваших целей, если факт от них расходится.
Частые ошибки
| Симптом | Причина | Что делать |
|---|---|---|
| Прогон останавливается на проверке подписи | манифест неподписан, подписан неизвестным ключом или изменён | не восстанавливайте этот снимок; проверьте список публичных ключей и целостность хранилища |
| «Целевая база не пуста» | цель уже содержит объекты | создайте новую цель, а не разрешайте запись в непустую |
| Отказ по совпадению адресов | указан адрес базы-источника | цель должна отличаться от источника; «на месте» — отдельная процедура с отдельным подтверждением |
| Манифеста для снимка нет | снимок частичный | он не пригоден для восстановления, возьмите предыдущий полный |
| Объекты ClickHouse не найдены | адрес серверного копирования не совпадает с бакетом и префиксом раннера, либо у ClickHouse нет доступа | сверьте адрес и права; не подставляйте учётные данные в SQL для проверки |
| Отказ в доступе на шаге сверки по водяному знаку | у пользователя ClickHouse нет прав в целевой базе | выдайте права на целевую базу; снимок при этом не повреждён |
| Прогон завершился, но события не сходятся с ожиданием | сработала сверка по водяному знаку либо есть повторная доставка из транспорта | сравните водяной знак из манифеста с ожидаемой точкой и проверьте отставание транспорта |