Перейти к основному содержимому

Лекция 12. Резервное копирование

В этой главе:

  • Логическое резервное копирование.
  • Физическое резервное копирование.

Логическое резервное копирование

Предназначение логического копирования

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

Инструмент PostgreSQL для логического копирования - pg_dump.

Логическое копирование выполняют для:

  • копирования или переноса конкретных выбранных объектов;
  • переноса данных на другую мажорную версию PostgreSQL, на другую платформу или даже другую аппаратную архитектуру.

Логическое копирование не подходит для:

  • быстрого резервного копирования и восстановления;
  • создания экономичных по размеру копий;
  • восстановления на более раннее время, чем момент создания копии.

Штатная утилита, поставляющаяся в комплекте PostgreSQL - pg_dump. Это клиент, который подключается к базе данных от имени некоторой роли с целью создания SQL скрипта, позволяющего при его запуске воссоздать структуры и/или данные выбранных объектов:

  • всей базы данных;
  • схем или структур без данных;
  • конкретных объектов, например, таблиц.

Утилита pg_dump предоставляет опции командной строки, для выбора необходимых для логического резервирования данные. В простейшем случае используется "плоский формат" (plain format), в котором по результату выполнения резервного копирования появляется обычный текстовый файл со скриптом. Если этот скрипт выполнить в клиенте psql, то можно воспроизвести те объекты, которые подверглись резервному копированию.

Преимущества логического копирования в том, что скрипт может быть воспроизведен на другой мажорной версии PostgreSQL. Например, резервную копию, сделанную в 14-й версии можно восстановить в 15-й. Более того, можно восстановление выполнить в другой ОС или даже на другой аппаратной платформе. Главные недостатки в медлительности копирования и восстановления, а также больших размерах получающихся копий (особенно в plain формате). Невозможно выполнить восстановление к моменту времени в прошлом. https://www.postgresql.org/docs/15/app-pgdump.html.

https://www.postgresql.org/docs/15/backup-dump.html.

Пример работы pg_dump

[student@p620~]$ pg_dump -d my_db -C > my_db.dump
[student@p620~]$ sudo -u postgres dropdb my_db
[student@p620~]$ psql -U postgres -d postgres < my_db.dump
[student@p620 ~]$ psql -d my_db -q
my_db=> \d
Список отношений
Схема | Имя | Тип | Владелец
--------+-----------+---------+--------------
public | def_privs | таблица | student
public | ptab | таблица | student
public | studentab | таблица | grp_students
public | suptab | таблица | postgres
(4 строки)

Пример на слайде демонстрирует, как выполнить логическое резервное копирование всех объектов базы данных. Опция -C в команде pg_dump нужна для включения команды создания базы данных в скрипт:

$ grep -i 'create database' my_db.dump
CREATE DATABASE my_db WITH TEMPLATE = template0 ENCODING = 'UTF8'
LOCALE_PROVIDER = libc LOCALE = 'en_US.UTF8';

Обратите внимание на использовании template0 в команде создания базы данных из резервной копии. Далее в примере база данных была удалена и заново восстановлена из резервной копии. Подключившись к восстановленной базе данных, можно заметить, что все объекты на месте. https://www.postgresql.org/docs/15/app-pgdump.html.

https://www.postgresql.org/docs/15/app-dropdb.html.

Как pg_dump копирует содержимое таблиц

[student@p620 ~]$ psql -d my_db -c \ 'INSERT INTO studentab SELECT g.i, g.i::text FROM generate_series(0,5) AS g(i);'

[student@p620 ~]$ pg_dump -d my_db -t studentab -a | sed -n '/^COPY/,$p'
COPY public.studentab (id, str) FROM stdin;
0 0
1 1
2 2
3 3
4 4
5 5
\.

В базе данных my_db имеется таблица studentab:


Таблица "public.studentab"
Столбец | Тип | Правило сортировки | Допустимость NULL |
---------+---------+--------------------+-------------------+
id | integer | | |
str | text | | |

В эту таблицу командой на слайде записаны шесть строк. Задача получить логическую резервную копию таблицы. Утилита pg_dump предоставляет опцию -t для выбора нужной таблицы для копирования. В примере выполнено резервное копирование только содержимого таблицы (опция -a pg_dump). Вывод резервной копии, то есть SQL скрипта для восстановления, был произведен в стандартный поток вывода. Команда sed была использована в целях вывода только нужной для демонстрации части скрипта - строк, начинающихся с COPY, и до конца вывода. В примере видно, что именно команда COPY была использована при размещении содержимого таблицы (то есть, данных) в резервную копию. Команда COPY используется в скриптах логических резервных копий при восстановлении из них данных. https://www.postgresql.org/docs/15/sql-copy.html.

https://www.postgresql.org/docs/15/tutorial-populate.html.

Копирование данных

Команда SQL COPY работает на стороне сервера:

  • COPY <ТАБЛИЦА> TO - копирование данных из таблицы или результата запроса в stdout или файл;
  • COPY <ТАБЛИЦА> FROM - добавление в существующую таблицу данных из stdin или файла.

Можно указывать разделитель полей и формат потока.

При копировании на стороне сервера COPY должна иметь права на чтение/запись файлов для пользователя postgres.

В клиенте psql предусмотрена метакоманда \copy, аналогичная по возможностям SQL COPY, однако работающая на клиенте с правами пользователя, запустившего psql.

Команда COPY не только используется в резервных копиях pg_dump. С помощью этой команды можно сохранить в файле или вывести в стандартный поток вывода stdout содержимое таблицы в текстовом виде. Есть возможности включать и выключать заголовок, выбирать формат вывода, определять разделитель полей и т.п. Выводить можно заданные столбцы таблицы или результат выполнения запроса. Вывод осуществляет команда COPY TO, но есть возможность ввести данные. Для этого есть команда COPY FROM. В этой форме команда COPY читает строки данных из стандартного потока ввода stdin или из файла. В режиме COPY FROM команда копирует данные в существующую таблицу, добавляя их к ней. Следует отметить, что SQL COPY работает на стороне сервера с правами серверного процесса. То есть работает от имени пользователя ОС postgres (точнее, от имени того пользователя, который инициализировал кластер). https://www.postgresql.org/docs/15/sql-copy.html. Если же надо чтобы копирование происходило не силами сервера, а с помощью клиента psql, то для этого предусмотрена метакоманда \copy. Ее возможности практически такие же. https://www.postgresql.org/docs/15/app-psql.html.

Форматы резервных копий pg_dump

-Fp - формат скрипта SQL (plain):

– восстановление psql – нет компрессии – нет параллельной работы

-Fc - пользовательский (custom):

– восстановление pg_restore – компрессия – параллельное восстановление

-Fd - формат каталога (directory):

– восстановление pg_restore – компрессия – распараллеливание

-Ft - формат tar (tar - tape archive):

  • восстановление pg_restore
  • нет компрессии
  • нет параллельной работы

Плоский формат (plain), в котором pg_dump продуцирует обычный SQL скрипт, удобен для восприятия человеком, но обладает существенными недостатками:

  • нет компрессии;
  • нет параллельной работы.

Если использовать pg_dump -Fc резервное копирование будет выполнено в пользовательском (custom) формате. На выходе получится сжатый бинарный файл, восстанавливаться из которого придется с помощью специальной утилиты pg_restore. Она поддерживает параллельную работу, которая определяется опцией -j, с помощью которой можно указать количество параллельно работающих потоков восстановления.

Еще один формат pg_dump -Fd - при его использовании резервная копия будет создана в каталоге, где образуется несколько сжатых бинарных файлов, из которых восстановиться можно утилитой pg_dump. Несомненным преимуществом этого режима является возможность и резервное копирование и восстановление выполнить с распараллеливанием. Количество потоков определяет опция -j, которая имеется как у pg_dump, так и у pg_restore. Формат -Ft создает tar архив, в котором отсутствует сжатие и параллельная работа в этом формате не поддерживается. https://www.postgresql.org/docs/15/app-pgdump.html. https://www.postgresql.org/docs/15/app-pgrestore.html.

Утилита pg_dumpall

Утилиты pg_dump/pg_restore не работают с глобальными объектами. Например, они не могут сохранить роли. В поставке PostgreSQL есть специальная утилита pg_dumpall для логического копирования всего кластера, включая глобальные объекты. Однако она поддерживает лишь плоский (plain) формат, а потому параллельного режима работы нет. Восстановление производится с помощью psql также без возможностей распараллеливания. Утилита pg_dumpall обладает опцией -g, которая позволяет выполнить резервное копирование только глобальных объектов. Обычный сценарий логического копирования кластера таков:

1)создается копия глобальных объектов pg_dumpall -g 2)в цикле для каждой базы данных кластера pg_dump -j.. -Fd

https://www.postgresql.org/docs/15/app-pg-dumpall.html.

Утилита предназначена для получения логической копии всего кластера.

В отличие от pg_dump может выполнять логическое копирование глобальных объектов.

Поддерживает только плоский (plain) формат - на выходе SQL скрипт.

Нет сжатия и параллельной работы. Для копирования только глобальных объектов опция -g. Восстановление из копии с помощью psql.

Физическое резервное копирование

Физическое копирование

Физическое резервное копирование создает копии файлов каталога данных.

Различают физическое резервное копирование:

– холодное после корректного останова сервера - достаточно скопировать каталог данных; – холодное после аварийного останова - необходимо скопировать каталог данных и журнал предзаписи WAL; – горячее копирование без останова сервера - требуется специальные действия и работа с журналом предзаписи WAL.

Преимущества:

– основной способ защиты от сбоев и потери данных; – высокая скорость копирования и восстановления; – возможность восстановления к моменту времени.

Недостатки:

– нельзя восстановиться на другой мажорной версии, другой платформе или ОС; – нельзя выбрать объекты для копирования и восстановления, копируется весь кластер.

Основной способ резервного копирования с целью защиты от сбоев - физическое копирование. При этом выполняется копия данных и, возможно, WAL. В зависимости от того, работает ли сервер, или же он выключен, а также, был ли он выключен корректно, физическое копирование следует выполнять по-разному. Простейший случай - корректно остановленный сервер. В таком случае достаточно просто скопировать каталог данных в новое место любой утилитой операционной системы (cp, cpio, tar, dd и так далее). Если запустить сервер, указав опцией -D команды pg_ctl новое местоположение каталога данных, сервер просто запустится. Такую процедуру можно выполнить, например, при исчерпании места в исходной файловой системе, но только тогда, когда возможно выполнить останов на время, потребное для копирования. Если же сервер был остановлен некорректно, то опять же можно воспользоваться обычным копированием, но обязательно потребуются журналы предзаписи WAL с последней контрольной точки. Если требуется выполнить резервное копирование без останова сервера на горячую, то для этого потребуется скопировать данные и WAL за все время копирования, плюс специальные процедуры. При выполнении физического копирования кластера невозможно скопировать отдельный объект и даже отдельную базу данных. Копируется всегда весь кластер. При восстановлении требуется бинарная совместимость серверов - нельзя восстановиться на другой мажорной версии кластера, другой ОС или платформе. https://www.postgresql.org/docs/15/backup.html.

Инструмент pg_basebackup

Обычный способ выполнения физического копирования работающего кластера - использование pg_basebackup. Этот инструмент работает по сетевому протоколу репликации.

При копировании pg_basebackup выполняет следующие шаги:

  1. Создает соединение с сервером по протоколу репликации - это клиентский протокол PostgreSQL, отличающийся от обычного лишь тем, что работает не с SQL, а с командами резервного копирования.
  2. Выполняет контрольную точку для гарантии, что все грязные блоки в кеше буферов будут скопированы в файлы данных.
  3. В каталог, заданный опцией -D (или архив в режиме -Ft), копируются все файлы кластера данных.
  4. С помощью отдельного сетевого соединения по протоколу репликации (если это не отключено опцией -Xn) в копию помещаются все сегменты WAL за все время, затраченное на копирование. В них записаны все изменения в данных, которые надо будет воспроизвести при старте экземпляра из копии.

Полученную в результате копию называют автономной, так как в ней есть все необходимое для запуска и работы нового кластера. Использование протокола репликации требует значение параметра wal_level не хуже, чем replica (wal_level = replica по умолчанию). https://www.postgresql.org/docs/15/app-pgbasebackup.html.

В Pangolin имеется более продвинутый инструмент резервного копирования - pg_probackup. [file:///home/student/Distrib/documentation/PSQ/6.2.0/html/documents/admin istration-guide/administration-scenarios.html#id74](file:///home/student/Distrib/documentation/PSQ/6.2.0/html/documents/admin istration-guide/administration-scenarios.html#id74).

Штатный инструмент в поставке PostgreSQL для горячего физического копирования работающего сервера без прерываний в работе клиентов.

Копируется содержимое всего кластера, скопировать отдельную базу данных невозможно.

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

По умолчанию в копию помещаются все сегменты WAL, созданные сервером за все время копирования.

Инструмент pg_basebackup создает клиентское подключение, используя протокол репликации.

Требуется уровень журнала предзаписи wal_level = replica.

Для подключения по протоколу репликации необходимо разрешение в pg_hba.conf.

Создание автономной копии

[postgres@p620 ~]$ mkdir Bkp 
[postgres@p620 ~]$ pg_basebackup -D Bkp/
[postgres@p620 ~]$ ls -F Bkp/
backup_label pg_integrity/ pg_replslot/ PG_VERSION
backup_manifest pg_logical/ pg_serial/ pg_wal/
base/ pg_multixact/ pg_snapshots/ pg_xact/
global/ pg_notify/ pg_stat/ postgresql.auto.conf
pg_commit_ts/ pg_perf_insights/ pg_stat_tmp/ postgresql.conf
pg_dynshmem/ pg_pp_cache/ pg_subtrans/ PRODUCT_VERSION
pg_hba.conf pg_prep_stats/ pg_tblspc/ tracing/
pg_ident.conf pg_quota.conf pg_twophase/

По умолчанию копия получена в плоском формате -Fp - все файлы каталога данных скопированы в целевой каталог, заданный опцией -D.

Все файлы сегментов WAL скопированы в каталог pg_wal в потоковом режиме (по умолчанию опция -Xs).

Целевой каталог для копирования задается опцией -D утилиты pg_basebackup. По умолчанию pg_basebackup работает в plain формате (опция -Fp). Если необходимо создать tar архив с копией - используйте опцию -Ft.

В результате, в целевом каталоге точная копия каталога данных работающего кластера. Полученный каталог можно использовать в качестве каталога данных для нового экземпляра, но для одновременного запуска нового экземпляра необходимо лишь заменить ему прослушиваемый TCP порт.

В результате физического копирования pg_basebackup поместила в каталог pg_wal все сегменты WAL за время резервного копирования:

[postgres@p620 ~]$ ls -l Bkp/pg_wal/
итого 16388
-rw------- 1 postgres postgres 16777216 окт 28 09:56
000000010000000000000008
drwx------ 2 postgres postgres 4096 окт 28 09:56
archive_status

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

[postgres@p620 ~]$ chmod -R go= Bkp/
[postgres@p620 ~]$ sed -i.bak 's/^port =.*$/port = 5433/' Bkp/postgresql.conf [postgres@p620 ~]$ pg_ctl start -D ~/Bkp/ -l ~/PG_new.log
waiting for server to start..... done
server started
[postgres@p620 ~]$ pg_ctl status -D ~/Bkp/
pg_ctl: server is running (PID: 48084)
/usr/pangolin-6.2.0/bin/postgres "-D" "/var/lib/postgres/Bkp"
[postgres@p620 ~]$ psql -p 5433 -c 'SELECT product_version()'
product_version
---------------------------
Platform V Pangolin 6.2.0
(1 row)

Запущен новый экземпляр с каталогом данных, который был создан в результате работы pg_basebackup. Перед запуском на каталог и все его содержимое были изменены права командой chmod - оставлены права доступа лишь для владельца (postgres). Командой sed в примере в конфигурационном файле postgresql.conf установлен TCP порт 5433 для прослушивания. Далее сервер запущен. При запуске происходит накат по журналу предзаписи WAL, что видно на записям в журнале отчета:

$ sed -n '/was interrupted/,$p' PG_new.log | head -8
2024-10-28 10:19:30.319 MSK [48088] LOG: database system was interrupted; last known up at 2024-10-28 09:56:31
MSK
2024-10-28 10:19:30.323 MSK [48089] LOG: idle terminator started
2024-10-28 10:19:38.988 MSK [48088] LOG: redo starts at 0/8000028
2024-10-28 10:19:39.023 MSK [48088] LOG: consistent recovery state reached at 0/8000130
2024-10-28 10:19:39.023 MSK [48088] LOG: redo done at 0/8000130 system usage: CPU: user: 0.00 s, system: 0.00 s,
elapsed: 0.03 s
2024-10-28 10:19:39.401 MSK [48086] LOG: checkpoint starting: end-of-recovery immediate wait
2024-10-28 10:19:39.549 MSK [48086] LOG: checkpoint complete: wrote 3 buffers (0.0%); 0 WAL file(s) added, 0 removed, 1 recycled; write=0.031 s, sync=0.011 s, total=0.184 s; sync files=2, longest=0.006 s, average=0.006 s; distance=16384 kB, estimate=16384 kB
2024-10-28 10:19:39.569 MSK [48084] LOG: database system is ready to accept connections

В итоге запущено два отдельных экземпляра, прослушивающие порт TCP 5432 - старый и 5433 - новый. Все данные скопированы:

$ psql -p 5433 -l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access priv
------------+--------------+-----------+------------+------------+------------+------------------+-------------
dontduitdb | postgres | UTF8 | en_US.UTF8 | en_US.UTF8 | | libc |
my_db | grp_students | UTF8 | en_US.UTF8 | en_US.UTF8 | | libc |
postgres | postgres | UTF8 | en_US.UTF8 | en_US.UTF8 | | libc |
template0 | postgres | UTF8 | en_US.UTF8 | en_US.UTF8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/p
template1 | postgres | UTF8 | en_US.UTF8 | en_US.UTF8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/p
(5 rows)

Сохранение сегментов журнала предзаписи

В обычном режиме сервер регулярно удаляет сегменты журнала предзаписи, ставшие ненужными для восстановления после возможного сбоя.

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

Для исключения преждевременного удаления сервером сегментов WAL создаются слоты репликации.

Слот используется клиентом, например, pg_basebackup для гарантии неудаления нужных клиенту сегментов WAL.

Утилита pg_basebackup может использовать существующий слот, указав его после опции -s, либо для нее слот создается автоматически.

С точки зрения сервера pg_basebackup - это обычный клиент. При работе сервер регулярно удаляет старые сегменты журнала предзаписи (не требующиеся для восстановления после сбоя) для недопущения излишнего расходования дискового пространства. Но, с другой стороны, pg_basebackup должен поместить в автономную копию все сегменты журнала предзаписи, которые были произведены за время выполнения копии. То есть, сервер может удалить сегменты, которые еще не попали в копию. Соответственно, такая копия не может быть использована. Для исключения этой проблемы используются слоты репликации. Они гарантируют, что клиент точно получит требуемые ему сегменты и она не удаляются сервером до тех пор, пока клиент с этим не согласится. Слот физической репликации может быть создан функцией pg_create_physical_replication_slot(). Этот слот можно указать с помощью опции -S команды pg_basebackup. Но можно и данимически его создать, используя -C (по умолчанию). https://www.postgresql.org/docs/15/app-pgbasebackup.html.

https://www.postgresql.org/docs/15/warm-standby.html#STREAMING-REPLICATION-SLOTS.

Архив сегментов журнала предзаписи

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

Наличие архива расширяет возможности восстановления из копии - можно выполнять восстановление к моменту времени в прошлом.

Архив можно организовать двумя способами:

  • средствами сервера - файловый архив, в который помещаются заполненные сегменты после переключения на новый сегмент (неизбежна задержка):
    • archive_mode
    • archive_command
  • средствами клиента - потоковый архив pg_receivewal (штатный инструмент).

Если каким-либо способом организовать сбор сегментов журналов транзакций по мере их заполнения, например, копируя их в какой-либо каталог, то в результате получится архив сегментов журнала WAL. Такой архив существенно расширяет возможности восстановления, обеспечивая восстановление к заданному моменту времени (Point In Time Recovery - PITR).

Первый способ организации архива - файловый, средствами сервера. Для этого настраивается параметр archive_command и включается режим archive_mode = on. Параметр archive_command задает команду операционной системы, выполняемую серверным процессом для копирования записанного сегмента WAL после переключения на новый сегмент (то есть, после ротации). Это может быть просто команда cp, копирующая файл в каталог архива. Если команда копирования НЕ завершится успешно, сервер циклически продолжит попытки копирования сегмента в архив. Недостаток этого метода в том, что переключение на новый сегмент, после которого заполненный сегмент попадет в архив, может сопровождаться значительной задержкой. https://www.postgresql.org/docs/15/continuous-archiving.html.

Этого недостатка лишен подход к заполнению архива средствами специализированных клиентских утилит. Штатной утилитой является pg_receivewal. Она создает соединение по протоколу репликации с сервером, подобно pg_basebackup, и получает сегменты WAL, записывая их в каталог архива. https://www.postgresql.org/docs/15/app-pgreceivewal.html.

Восстановление при наличии архива

При наличии архива можно не помещать сегменты WAL в копию, в pg_basebackup опция -Xn.

Действия перед восстановлением:

  1. В полученном каталоге с копией настраивается параметр конфигурации restore_command, он задает команду ОС, выполняющую извлечение из архива нужных для восстановления сегментов WAL и размещение их в pg_wal.
  2. Может быть задана целевая точка восстановления параметрами recovery_target* .
  3. Создается пустой файл сигнализации recovery.signal.

Далее сервер запускается.

При наличии архива сегментов журнала предзаписи WAL процедура восстановления немного меняется. Необходимо указать, какие действия необходимо произвести для извлечения из архива необходимых для восстановления сегментов журнала WAL. Это делается с помощью параметра restore_command. Он противоположен параметру archive_command, который копирует из pg_wal в архив.

По умолчанию восстановление продолжается вплоть до достижения конца журнала WAL. Однако, можно задать точку восстановления одним из параметров recovery_target*.

postgres=# \dconfig recovery_target* Список параметров конфигурации Параметр | Значение --------------------------+---------- recovery_target | recovery_target_action | pause recovery_target_inclusive | on recovery_target_lsn | recovery_target_name | recovery_target_time | recovery_target_timeline | latest recovery_target_xid | (8 строк)

Например, до точки времени recovery_target_time. Необходимо также создать пустой сигнальный файл recovery.signal https://www.postgresql.org/docs/15/runtime-config-wal.html#RUNTIME-CONFIG-WAL-RECOVERY-TARGET.

Итоги

  • Логическое копирование выполняют pg_dump и pg_dumplall.
  • Восстановление из бинарных форматов - pg_restore.
  • Логическая копия - скрипт SQL.
  • В логических копиях данные из таблиц сохраняет COPY.
  • Восстановление из логической копии не требует бинарной совместимости.
  • Логическая копия - инструмент копирования отдельных объектов.
  • Физическая копия содержит бинарные файлы кластера.
  • Штатный инструмент - pg_basebackup.
  • В физическую копию помещается весь кластер.
  • Для восстановления требуются сегменты WAL.
  • Восстановление из физической копии требует бинарную совместимость.
  • Физическая копия - основной инструмент резервного копирования.