Bollywood HungamaEXCLUSIVE: Abhishek Varman to direct modern mythological superhero spectacle Gadadhari Bheem; film to be produced by Dharma ProductionsInquirerFoul odor prompts shoreline inspection in MamburaoPunchDenmark probes hack of national database affecting 8.8m peopleThe Jerusalem PostIndian police detain Israeli for staying without valid travel documents following drug chargesESPN DeportesPortugal da cuenta de Noruega, tras polémica de CristianoCNN TürkSAĞLIK OCAĞI ÇALIŞMA SAATLERİ 2026: Aile Hekimliği kaçta açılıyor, kaça kadar açık? Sağlık ocağı hafta sonu açık mı?한겨레계단·화장실·복사기 앞 …관객 선 자리가 ‘극, 장’ZDF heuteAktuelle Pressemitteilungen des ZDFBBC عربياجتماع للجان "اتفاقية مكة" في الرياض اليوم، والقوات اليمنية تنفّذ 1,122 عملية ضد الحوثيينسكاي نيوز عربية"واقعة البصق" تزيد الاحتقان في مباراة أيرلندا وإسرائيلDaily MailAnti-migrant protesters scuffle with police after nearly 150 small boat arrivals use 'new route' to land at historic naval port20 MinutenPfleger feuerte sechs Schüsse auf zwei Polizisten ab
The Daily Newsstand · Free, Always
Monday, October 5, 2026

Копия базы 1С оборвалась, а gzip -t и psql вернули 0

Translate

Ежедневную копию баз 1С на тестовом стенде я поставил 2 октября: cron, pg_dump каждой базы через gzip в файл и строчка в журнал. На следующий день одна копия оборвалась. Привычные проверки этого не увидели.

Журнал кончался строкой “End backup DB2”. gzip -t по файлу вернул 0. Я залил файл в пустую базу - снова 0, без единой ошибки. Только индексов в базе не оказалось совсем, а строк набралось примерно 42 % от исходной.

Если ваша ночная копия собрана из cron, pg_dump и gzip, посмотрите на последний файл. Хватит одной строки - zcat копия.sql.gz | tail -n 5 | grep -c ‘dump complete’ показывает, дописал ли pg_dump файл до конца.

У целой копии выходит 1, у оборванной 0. А gzip -t доволен обеими.

Аварии у клиента здесь нет. Стенд наш, и PostgreSQL посреди копии перезапустили мы сами, соседним тестом.

Как было устроено

Стенд - Debian 13.7 и PostgreSQL 18.4 в сборке для 1С. Копия стартует в 17:00 по часам сервера, это МСК+2.

Скрипт обходит базы циклом: “Start backup” в журнал, pg_dump в gzip, “End backup” в журнал. Вторая строка пишется при любом исходе. pipefail не включён. Двадцать с лишним лет в ИТ не помешали мне поставить на свой стенд копию, которая не смотрит ни на код pg_dump, ни на готовый файл.

3 октября, 17:23:05

В 17:22:36 очередь дошла до DB2, она в списке десятая и последняя. Это копия рабочих данных 1С.

Через 29 секунд соседний тест настройки shared_buffers перезапустил PostgreSQL. В журнале sudo осталась команда systemctl restart postgresql@18-main. Строку “End backup DB2” скрипт записал в ту же секунду, 17:23:05.

Связь я вывожу только из этого совпадения. Текста ошибки нет нигде, код pg_dump скрипт не сохранил.

Терминал стенда: копии DB2 за 2 и 3 октября

Терминал стенда: копии DB2 за 2 и 3 октября

На кадре: журнал копии, размеры копий DB2 за 2 и 3 октября, gzip -t, проверка конца и строка cron. Имя базы в кадре заменено на DB2.

Нижняя строка кадра - из журнала cron: “No MTA installed, discarding output”. Почты на сервере нет, и всё, что задание печатало, ушло в никуда. Было ли там сообщение pg_dump, я могу судить только по времени. Та же строка в журнале cron вашего сервера - повод выяснить, куда деваются сообщения ночной копии.

Вчерашняя копия той же базы снималась три минуты и весила 1 120 951 158 байт. Оборванная - 29 секунд и 95 043 271 байт, почти в 12 раз меньше.

Я по образованию финансист, и для меня такой файл - скрытый долг: лежит рядом с целыми, с записью “End backup”, а платить по нему пришлось бы в день восстановления.

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

Файл я залил в пустую базу той же командой, что и базы стенда: zcat в psql без ключей. Через 25 секунд код 0, ошибок ни одной.

В новой базе оказались все 4 687 таблиц, но индексов ноль, а в исходной DB2 их 10 362.

Строк 3 393 049 из 8 060 005, отсюда и 42 %. Число приблизительное: исходную базу я считал уже после копии, а за день число строк в ней меняется на десятки.

Строгая заливка - одной транзакцией, с остановкой на первой ошибке - тоже вернула 0, база вышла такой же недолитой.

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

Убитый pg_dump: код 0 и чистый gzip -t

Файлы мы ломали и руками, на DB11 - синтетической базе теста Гилева. pg_dump убивали сигналом KILL спустя 0,3 секунды после старта. OOM, kill или перезагрузка обрывают копию так же.

Терминал стенда: pg_dump убит, код 0

Терминал стенда: pg_dump убит, код 0

Прогон на кадре отдельный, поэтому размеры файлов в нём не те, что ниже, а gilev - настоящее имя DB11. Убитый pg_dump в кадре выдают только команда с timeout -s KILL 0.3 и размер файла.

Без pipefail конвейер вернул 0: его код здесь - код gzip. С pipefail вышло 137, код убитого pg_dump.

gzip -t оба раза ответил 0, потому что gzip получил конец потока и закрыл файл штатно. Файл, у которого 1 октября мы отрезали половину сжатых байтов, gzip -t зато отбраковал с кодом 1, хотя заливка без ключей вернула 0 и на нём.

Файл из прогона с pipefail весил 240 189 байт при 3 987 740 у целого дампа, и проверка конца на нём дала 0. Залитый в пустую базу, он дал код 0, ноль индексов и 15 007 строк из 135 121.

Как стало: фрагмент копии

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

#!/bin/bash
set -o pipefail
db=$1; dir=$2; log=$dir/backup.log
f=$dir/$db-$(date +%H%M%S).sql.gz
if pg_dump -d "$db" | gzip > "$f" \
   && zcat "$f" | tail -n 5 | grep -q 'dump complete'; then
  echo "$(date '+%F %T') OK $db $(stat -c%s "$f")" >> "$log"
else
  rc=$?
  echo "$(date '+%F %T') FAIL $db код=$rc" >> "$log"
fi

Между двумя OK по часам сервера, в 18:46:14 и 18:46:18 3 октября, стоит FAIL код=137 в 18:46:15. Это второй запуск на DB11: pg_dump в нём прожил 0,3 секунды, его убил таймер, которого в листинге нет.

Первая версия фрагмента записала в журнал “FAIL DB11 код=0”. Подстановка с date в той же строке echo выполняется раньше и затирает $?, поэтому теперь первая команда ветки сохраняет код в rc.

Обрыв 3 октября pipefail поймал бы только при ненулевом коде pg_dump, а этот код не сохранился.

Фрагмент, как и старый скрипт, отдаёт сообщения pg_dump на откуп cron. Что cron с ними делает, видно на первом кадре.

Проверка при заливке

Строгая заливка текстового дампа - это psql с ключом -1 и переменной ON_ERROR_STOP=1.

Наткнувшись на ошибку, psql по умолчанию просто едет дальше. С ON_ERROR_STOP он на ошибке прервётся и вернёт 3, но база всё равно будет недолитой. Глава “SQL Dump” документации PostgreSQL 18 так и пишет: “Either way, you will only have a partially restored database”.

Против недолитой базы глава советует ключ -1: дамп идёт одной транзакцией, и при ошибке ничего не остаётся на полпути - “either fully completed or fully rolled back”. Цена - время: мелкая ошибка, как предупреждает та же глава, может откатить многочасовое восстановление. По-моему, это дешевле недолитой базы, принятой за целую.

Страница psql привязывает -1 к ключам -c и -f, а откат при ошибке обещает только с ON_ERROR_STOP. На файле, обрезанном посередине, строгая заливка дала код 3 и пустую базу и с -f, и через стандартный ввод.

Забыть ON_ERROR_STOP опасно. Файл, оборванный посреди строки данных, одной транзакцией дал пустую базу и код 0 - тоже обоими способами. Скрипт, который смотрит только на код, сочтёт такую базу восстановленной.

Почему база пустая, страница psql не объясняет - гадать не буду.

Custom-архив можно проверить без базы, прогнав pg_restore -f /dev/null вхолостую и посмотрев код возврата.

На половине архива это чтение дало 1 и “не удалось прочитать входной файл: конец файла”, восстановление в базу - тоже 1. А pg_restore -l такую же половину пропустил: код 0, оглавление как у целого. Отрезанный хвост в 64 КБ это чтение не поймало, но и восстановление без него ничего не потеряло.

Чего я не знаю

Почему pg_dump оборвался ровно после целого блока данных, не установлено. Случай один, база одна, в 1С залитую базу я не открывал. Строку конца я искал только в текстовых дампах pg_dump 18.4 и 15.6, а формат directory не проверял ни так, ни через pg_restore. Документация PostgreSQL 18 написана для ванильной СУБД, а стенд работает на сборке под 1С.

Надеюсь, пригодится. Если проверяете custom-архивы больших баз, напишите в комментариях, чем: мой архив весил всего 5,3 МБ, а что будет на сотнях гигабайт, не знаю.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.