# Резервное копирование и восстановление БД Для организации бекапа базы мы рекомендуем локальное снятие дампа. Это происходит быстрее, не грузит сеть. Администратор должен следить за свободным местом на диске, свободного места должно хватать для снятия дампа. Лучше всего для сохранения дампа использовать отдельный том. Это позволяет избежать аварийной остановки постгреса при нехватке места на диске. Локально снятый дамп архивируется и помещается на внешнее NAS хранилище. Возможно применение сторонних средств резервного копирования, таких как [Кибер Бэкап](https://cyberprotect.ru/products/backup/) для PostgreSQL ## Снятие дампа ![pgdump](img/pgDump.png) Снятие дампа выполняется штатной утилитой [pg_dump](https://postgrespro.ru/docs/postgresql/14/app-pgdump) Для бекапа снимаем только схему `public`, ее достаточно для сохранения всех данных системы. Отдельно снимаем структуру всех объектов схемы `aud`. Это позволяет при восстановлении не пересоздавать структуры хранения аудита из системы Global. Если требуется сохранить аудит, то схему `aud` рекомендуется снимать отдельно. ```{tip} При включенном аудите в системе Global и высокой интенсивности работы схема aud может содержать большие объемы данных (Несколько терабайт). Создание резервной копии схемы aud может занимать продолжительное время. ``` Обычно все схемы снимаются для переустановки PostgreSQL или обновления версии PostgreSQL, с последующим нагоном полного дампа. Для снятия дампа используйте формат "Директория". Это позволяет снимать дамп в многопоточном режиме и существенно ускоряет процесс. Общий пример запуска утилиты снятия дампа ```bash ${sDumpUtl} -F d --dbname=postgresql://${sUser}:${sPass}@${sHost}:5432/${sDbName} --jobs=$nColDbJobs --schema=public --blobs --verbose ``` где - ${sDumpUtl} - путь к утилите pg_dump - ${sUser} - логин - ${sPass} - пароль - ${sHost} - хост - ${sDbName} - имя бд - $nColDbJobs - количество потоков (выставляется по количеству ядер на сервере postgresql) Общий пример запуска утилиты для снятия схемы `aud` без данных ```bash ${sDumpUtl} -F d --dbname=postgresql://${sUser}:${sPass}@${sHost}:5432/${sDbName} --jobs=$nColDbJobs --schema=aud --schema-only --blobs --verbose --file=$sOutputDumpDir ``` где - ${sDumpUtl} - путь к утилите pg_dump - ${sUser} - логин - ${sPass} - пароль - ${sHost} - хост - ${sDbName} - имя бд - $nColDbJobs - количество потоков (выставляется по количеству ядер на сервере postgresql) ```{tip} Параметр `--schema-only` позволяет выгружать только определения объектов (схемы), без данных. ``` После снятия дампа запаковываем директорию архиватором tar ```bash tar -cvf ${sArchiveDir}/${sTarFileName} $sOutputDumpDir ``` где - ${sArchiveDir} - директория для архива - ${sTarFileName} - имя архивного файла - $sOutputDumpDir - директория с дампом ## Развертывание дампа Развертывание дампа выполняет штатная утилита [pg_restore](https://postgrespro.ru/docs/postgresql/14/app-pgrestore) Перед развертыванием дампа обязательно удаляем все объекты схемы `public` ```bash $psqlUtl postgresql://${sUser}:${sPass}@${sHost}:5432/${sDbName} -f $SCRIPTPATH/drop.sql ``` где - ${psqlUtl} - путь к утилите psql - ${sUser} - логин - ${sPass} - пароль - ${sHost} - хост - ${sDbName} - имя бд - $SCRIPTPATH - путь до файла drop.sql файл drop.sql ```sql SET search_path TO public; -- DO $$ DECLARE r RECORD; BEGIN FOR r IN (SELECT p.oid::regprocedure as sFunctionName FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) inner join pg_roles a on p.proowner =a.oid WHERE ns.nspname = current_schema and a.rolname =current_user and p.probin is null) LOOP EXECUTE 'DROP FUNCTION IF EXISTS ' || r.sFunctionName || ' CASCADE'; commit; END LOOP; END $$; -- DO $$ DECLARE r RECORD; BEGIN FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE'; commit; END LOOP; END $$; -- DO $$ DECLARE r RECORD; BEGIN FOR r IN (SELECT c.relname FROM pg_class c inner join pg_catalog.pg_namespace n on c.relnamespace =n.oid inner join pg_roles a on c.relowner =a.oid WHERE (c.relkind = 'S') and n.nspname =current_schema and a.rolname =current_user) LOOP EXECUTE 'drop sequence IF EXISTS ' || quote_ident(r.relname) || ' CASCADE'; commit; END LOOP; END $$; -- DO $$ DECLARE r RECORD; BEGIN FOR r IN (SELECT c.relname FROM pg_class c inner join pg_catalog.pg_namespace n on c.relnamespace =n.oid inner join pg_roles a on c.relowner =a.oid where c.relkind ='v' and n.nspname =current_schema and a.rolname =current_user) LOOP EXECUTE 'drop view IF EXISTS ' || quote_ident(r.relname) || ' CASCADE'; commit; END LOOP; END $$; -- SELECT lo_unlink(l.oid) FROM pg_largeobject_metadata l inner join pg_roles a on l.lomowner =a.oid WHERE a.rolname =current_user; ``` Перед развертыванием дампа его нужно распаковать ```bash tar -xvf ${dumpArchiveFile} -C $sTempPath ``` запустите утилиту развертывания дампа ```bash $sRestoreUtl --dbname=postgresql://${sUser}:${sPass}@${sHost}:5432/${sDbName} -O -x -v --no-tablespaces --jobs=$nColDbJobs $sRealDumpDir ``` где - $sRestoreUtl - путь к утилите pg_restore - ${sUser} - логин - ${sPass} - пароль - ${sHost} - хост - ${sDbName} - имя бд - $nColDbJobs - количество потоков (выставляется по количеству ядер на сервере postgresql) - $sRealDumpDir - путь к каталогу с файлами дампа