Ошибочный DELETE выполнился в 14:37. Последний ночной pg_dump снят в 02:00. Если развернуть его поверх рабочей базы, пропадут изменения за двенадцать с лишним часов.

Сначала сохраните рабочий том PostgreSQL, архив WAL и репозиторий базовых копий. Работать нужно с дубликатами. Поднимите отдельный контейнер, разверните там физическую копию кластера и воспроизведите WAL до секунды перед ошибкой. Подключайте 1С только после проверки восстановленной базы.

PITR возвращает весь кластер PostgreSQL, а не отдельную таблицу или базу. Одну таблицу лучше извлечь из логического дампа в отдельной среде. В официальной документации PostgreSQL это различие сформулировано прямо: pg_dump не содержит данных для воспроизведения WAL.

Что сохранить до восстановления

Не очищайте Docker volume. Не перезапускайте PostgreSQL снова и снова. Даже если кластер уже не запускается, сначала скопируйте исходные данные.

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

Архив WAL копируйте отдельно. Каталог pg_wal внутри PGDATA его не заменяет: после контрольных точек PostgreSQL удаляет или переиспользует локальные сегменты.

Что сохранитьЗачем это нужноЧто произойдёт при потере
Рабочий PGDATAОставляет возможность вернуться к исходному состояниюНеудачное восстановление нельзя будет отменить
Последняя полная физическая копияДаёт начальное состояние кластера для PITRОдного архива WAL недостаточно для запуска
Непрерывный архив WALСодержит изменения после физической копииВосстановление остановится на первом пропавшем сегменте
Настройки restore_command и архивацииПоказывают расположение архива и способ выдачи сегментовPostgreSQL не сможет найти нужные файлы либо возьмёт не тот архив

Вывод: одного pg_dump, каталога pg_wal или нескольких последних WAL-сегментов для PITR не хватит.

До работы с копией запишите цель восстановления. PostgreSQL принимает время, LSN, идентификатор транзакции или именованную точку, созданную через pg_create_restore_point().

После ошибочного запроса выбирайте момент перед началом транзакции. Часы пользователя и контейнера могут показывать разное время. Проверьте часовой пояс PostgreSQL:

SHOW timezone;
SELECT now();

Цель должна идти после завершения физической копии. PostgreSQL не восстановит состояние, которого в этой копии ещё не существовало.

Почему ночной pg_dump не заменяет PITR

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

Физических страниц кластера и последовательности WAL в дампе нет. Взять ночной файл и «докрутить» его до 14:36 PostgreSQL не сможет.

Один дамп в сутки означает потерю почти всего интервала между копиями. Если выгрузка началась в 02:00, а ошибка случилась перед следующим запуском, под угрозой почти сутки изменений.

Для PITR нужны две части. pg_basebackup снимает физическую копию работающего кластера. Архив WAL принимает изменения, которые появились позднее. Во время восстановления PostgreSQL открывает копию и воспроизводит WAL до заданной точки.

Различия между логической и физической копией подробнее разобраны в материале про бэкап PostgreSQL для 1С.

Как проверить цепочку base backup и WAL

Сначала найдите дату и время последней физической копии. Затем проверьте WAL-сегменты от начала копирования до выбранной точки восстановления.

Официальная документация PostgreSQL требует непрерывной последовательности WAL как минимум с начала физической копии. Более новый сегмент не заменит пропущенный. Числовые имена файлов отражают их место в общей последовательности.

Файловый архив проверяйте отдельно от контейнера:

find /srv/postgres/wal-archive -maxdepth 1 -type f \
 -printf '%f %s %TY-%Tm-%Td %TH:%TM:%TS\n' |
 sort

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

Не переименовывайте WAL-сегменты вручную. restore_command запрашивает точное имя через %f и ждёт получить файл по пути %p.

Какие настройки нужны для будущего PITR

Архивацию включают до аварии. Если ошибочный DELETE уже прошёл, вернуть удалённые PostgreSQL сегменты WAL настройкой задним числом не получится.

Минимальный набор параметров выглядит так:

wal_level = replica
archive_mode = on
archive_command = 'test ! -f /wal-archive/%f && cp %p /wal-archive/%f'

archive_command должна вернуть код 0 только после успешной записи. Уже сохранённый сегмент команда перезаписывать не должна. Оба требования закреплены в руководстве PostgreSQL по непрерывной архивации.

Архив держите в постоянном томе. Вот фрагмент Compose:

services:
 postgres:
 image: postgres:18
 volumes:
 - pg_prod_data:/var/lib/postgresql/18/docker
 - pg_wal_archive:/wal-archive
 command:
 - postgres
 - -c
 - wal_level=replica
 - -c
 - archive_mode=on
 - -c
 - archive_command=test ! -f /wal-archive/%f && cp %p /wal-archive/%f

volumes:
 pg_prod_data:
 pg_wal_archive:

В официальном образе PostgreSQL 18 путь PGDATA изменился на /var/lib/postgresql/18/docker. Для другой основной версии сначала проверьте путь внутри образа. Не переносите пример дословно.

Архив растёт вместе с числом WAL-сегментов. Обычный сегмент занимает 16 МБ, но при initdb можно выбрать другой размер.

Объём за сутки считается так: N × 16 МБ, где N — число новых сегментов. При 900 сегментах архив вырастет на 14 400 МБ, или примерно на 14,1 ГиБ. Если размер сегмента меняли, подставьте фактическое значение.

Это объём суточного притока без сжатия и ротации. Для месячного запаса умножьте суточный объём на число дней хранения. Отдельно заложите место под физические копии.

Как поднять отдельный контейнер для восстановления

Создайте новый Docker volume. Рабочий pg_prod_data к восстановительному сервису не подключайте даже для чтения: во время recovery PostgreSQL меняет файлы кластера.

Назовите тома так, чтобы их нельзя было спутать:

services:
 postgres-recovery:
 image: postgres:18
 volumes:
 - pg_recovery_data:/var/lib/postgresql/18/docker
 - pg_wal_archive:/wal-archive:ro
 ports:
 - "55432:5432"

volumes:
 pg_recovery_data:
 pg_wal_archive:

Перед развёртыванием физической копии остановите только восстановительный сервис:

docker compose stop postgres-recovery
docker compose run --rm postgres-recovery \
 bash -lc 'rm -rf "$PGDATA"/*'

Эту очистку можно запускать только для нового pg_recovery_data. Сначала изучите итоговую конфигурацию:

docker compose config
docker volume inspect "$(docker compose config --volumes | grep pg_recovery_data)"

Сомневаетесь в имени тома — остановитесь. Ошибка в одной строке уничтожит данные быстрее исходного DELETE.

Теперь разверните физическую копию в PGDATA. Команда зависит от формата: обычный каталог, архив tar или репозиторий pgBackRest. Нельзя копировать лишь видимые файлы. PostgreSQL нужны служебные каталоги и backup_label.

Для копии в обычном каталоге порядок такой:

docker compose run --rm postgres-recovery \
 bash -lc 'cp -a /base-backup/. "$PGDATA"/ && chmod 700 "$PGDATA"'

Подключите том с физической копией к сервису, например как /base-backup:ro. Файлы внутри контейнера должны остаться во владении пользователя PostgreSQL.

Как задать точку восстановления

В postgresql.auto.conf восстановленной копии добавьте restore_command и цель. Для возврата к секунде перед ошибкой задайте время вместе с часовым поясом:

restore_command = 'cp /wal-archive/%f %p'
recovery_target_time = '2026-08-29 14:36:59+04'
recovery_target_action = 'pause'

Режим pause оставляет кластер в recovery после достижения цели. Вы успеете проверить данные, прежде чем переводить PostgreSQL в обычный режим.

Создайте сигнал восстановления:

docker compose run --rm postgres-recovery \
 bash -lc 'touch "$PGDATA/recovery.signal"'

Запустите сервис и сразу откройте журнал:

docker compose up -d postgres-recovery
docker compose logs -f postgres-recovery

Сценарии из /docker-entrypoint-initdb.d/ тут не выполнятся. Официальный образ Docker запускает их лишь при первой инициализации, когда каталог данных ещё пуст.

Что проверять во время запуска

Статуса running недостаточно. Он подтверждает лишь наличие работающего процесса. Полноту WAL и достижение целевой точки этот статус не проверяет.

ЭтапКак проверитьПризнак успеха
Физическая копия развернуласьПросмотреть начало журнала PostgreSQLСервер распознал backup и начал recovery
Архив WAL доступенСледить за запросами restore_commandЗапрошенные сегменты копируются без ошибок
Воспроизведение продолжаетсяВыполнить SELECT pg_is_in_recovery();Функция возвращает true до целевой точки
Цель достигнутаПроверить журнал и состояние recoveryPostgreSQL сообщил о достижении recovery target
Данные открываютсяПодключить отдельный тестовый контур 1СБаза открывается, а ошибочная операция отсутствует
Кластер готов к работеВыполнить promote после проверкиpg_is_in_recovery() возвращает false

Вывод: переключать 1С можно лишь после проверки базы в отдельном контейнере.

К восстановленному PostgreSQL подключайтесь через отдельный порт:

psql -h 127.0.0.1 -p 55432 -U postgres -d postgres \
 -c 'SELECT pg_is_in_recovery();'

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

Если задано recovery_target_action = 'pause', после проверки продолжите воспроизведение и выполните promote:

SELECT pg_wal_replay_resume();
SELECT pg_promote();

Ещё раз запросите состояние:

SELECT pg_is_in_recovery();

После завершения recovery функция должна вернуть false.

Что делать при пропавшем WAL-сегменте

В журнале PostgreSQL появится имя файла, который не получила restore_command. Ищите его во всех копиях: в основном каталоге, удалённом хранилище и репозитории программы резервного копирования.

Не подставляйте файл с похожим именем. Не переименовывайте следующий сегмент. Дамп тоже не закроет разрыв. Для PITR нужна точная непрерывная цепочка.

Если сегмент потерян, остаются два варианта:

Более новая копия подходит не всегда. Если её сняли после ошибочного DELETE, нужного состояния в начальной точке уже нет.

Сохраните журналы восстановления и исходные носители. Остальные сценарии повреждения и потери данных собраны на карте аварий 1С.

Если не помогло

Остановите восстановительный контейнер. Его том и архив WAL не удаляйте. Сохраните журнал PostgreSQL, конфигурацию Compose, время ошибки и список доступных физических копий.

Если цепочка WAL полна, но PostgreSQL не запускается или 1С не открывает копию, передайте собранные материалы специалисту. На сайте есть аварийная помощь по 1С и SQL. Срок и объём возврата данных станут понятны только после проверки копий и WAL.

Чтобы ошибка не повторилась

Включённый archive_mode ещё не означает, что PITR готов. Настройка считается рабочей после пробного восстановления последней физической копии в отдельном контейнере.

Проверьте сегодня:

  1. Рабочий том скопирован и не меняется во время эксперимента.
  2. Физическая копия разворачивается в новый volume.
  3. Архив содержит непрерывную цепочку WAL от начала копии.
  4. PostgreSQL доходит до контрольной точки и завершает recovery.
  5. Тестовый контур 1С открывает восстановленную базу.

Не прошёл хотя бы один пункт — рабочий том не меняйте. Расписание копий, ротацию и хранение вне сервера сверьте с полным руководством по резервному копированию 1С.

Можно ли через PITR восстановить одну базу PostgreSQL?

Нет. PostgreSQL воспроизводит WAL для всего физического кластера. Нужную базу или таблицу извлекают из восстановленного кластера отдельно.

Нужен ли pg_dump, если настроен PITR?

Да, для возврата отдельных объектов и переноса между версиями. Но pg_dump не заменяет физическую копию и архив WAL.

Что делать, если пропал один WAL-сегмент?

Искать его во всех копиях архива и репозиториях. Если сегмент утерян, продолжить PITR через разрыв нельзя.

Можно ли восстанавливать поверх рабочего Docker volume?

Нет. Разворачивайте копию в новом томе и подключайте 1С только после проверки результата.

Как понять, что восстановление закончилось?

Проверьте журнал PostgreSQL и выполните SELECT pg_is_in_recovery();. После завершения recovery функция вернёт false.

docker pitr postgresql Аварии 1С восстановление базы резервное копирование