Делаем резервную копию PostgreSQL
Есть несколько путей для проведения резервного копирования и которые могут быть сгруппированы в следующие категории:
логическое и физическое резервное копирование.
Логическое копирование
– это методика однократного “снимка” содержимого базы с учетом транзакционной целостности. Система экспортирует данные из кластера и сохраняет их в заданном файле, при этом транзакционные сессии сохраняются в том виде, в каком они были на момент экспорта; администратору базы данных не нужен доступ к директории PGDATA.
Физическое копирование
подразумевает, что у администратора есть доступ к этой директории и он может скопировать каждый файл оттуда. Естественно, что транзакционные сессии в этом случае, не могут быть правильно сохранены, поэтому при старте PostgreSQL нужно будет провести проверку на целостность.
Для этого, у СУБД должны быть логи по упреждающей журнализации WAL (Write Ahead Logs), которые СУБД использует при отказе аппаратуры и т.п. От уровня архивации этих логов зависит и степень физического архивирования: можно настроить архивирование от одной логической точки до другой, либо в качестве непрерывного процесса, либо отсылая логи на другую машину, которая в свою очередь будет использовать их и работать в качестве резервного “клонирующего” узла (вот, в принципе, как работает репликация данных).
Логическое архивирование: pg_dump
Стандартный способ для совершения логического архивирования – это задействовать команду pg_dump(1), которая выгрузит содержимое базы в виде текстового SQL-файла (обычного или сжатого). У этой команды есть много параметров и можно выбрать, что именно сохранять – только данные, только структуру базы, единичную таблицу или объект, либо же всё вместе. Также есть другая утилита под названием pg_dumpall(1), которую можно использовать для сохранения всего кластера, вместо одной какой-либо базы. Использование двух утилит похоже и в листинге 12 показано, как сделать архивирование нашего примера с базой bsddb. При установке из портов будет создан скрипт в /usr/local/etc/periodic/daily, который при его активации будет запускать pg_dump для сохранения всех баз из кластера (кроме template0).
Физическое архивирование и восстановление нужной временной отметки (Point in Time Recovery – PITR)
PITR является интересной функцией, разработанной в версии 8, и которая основана на физическом архивировании. Она позволяет вернуться к определенному состоянию базы в прошлом. Это можно описать так: система следит за состоянием логов WAL, в которых хранится состояние “образа” базы в
любой точке времени. Когда необходимо провести восстановление, то сервис останавливается и затем перезапускается с эмуляцией отказа (т.е. с “грязным” статусом). СУБД затем начинает процедуру отката с помощью WAL-логов так, чтобы была обеспечена внутренняя целостность транзакций. Определив, сколько информации в логах является лишней, можнооткатиться в нужную временную точку в прошлом. Чтобы посмотреть PITR в действии нам нужно
определить, где мы будет хранить WAL-логи, поэтому создадим директорию /postgresql/pitr и сконфигурируем следующие опции в файле postgresql.conf:
wal_level = archive
archive_mode = on
archive_command = ‘cp -i %p /postgresql/pitr/%f’
которые информируют кластер когда и как архивировать эти логи. После рестарта PostgreSQL мы можем подключиться и смоделировать загрузку. Для более подробного понимания нашего примера мы поменяем в таблице magazine кортежи, чтобы теперь сохранялись и временные метки (см. листинг 13).
Первым шагом по активизации PITR является сохранение физической копии директории PGDATA, за исключением содержимого каталога pg_xlog. Неважно, куда и когда будет производиться архивирование, а также сколько на это потребуется времени – просто оповестите кластер, что процесс
копирования начался и закончился. Сделать это можно запустив функции pg_start_backup() и pg_stop_backup(). В листинге 13 показано, что для упрощения процедур, наша копия выгружается в зеркальную директорию PGDATA, которая называется /postgresql/cluster2. Пока копирование идет, кластер может продолжать работу (т.е. пользовательские подключения разрешены). В конце процесса мы вставляем, с помощью четырех инструкций, миллион кортежей с четырьмя разными временными метками. А после этого все их удаляем
(см. листинг 13). Таким образом мы моделируем ошибку в приложении, но аналогично можно смоделировать и другие (более сложные) случаи отказов.
Листинг 13. Подготовка системы для PITR
~> oid2name
All databases:
Oid Database Name Tablespace
———————————-
16387 bsddb pg_default
11912 postgres pg_default
11904 template0 pg_default
1 template1 pg_default
~> oid2name -H 192.168.200.2 -d bsddb -U bsdmagic -t magazine
From database “bsddb”:
Filenode Table Name
———————-
16390 magazine
~> ls -l /postgresql/cluster1/base/16387/16390
-rw——- 1 pgsql pgsql 8192 Jan 19 14:26 /postgresql/cluster1/base/16387/16390
~> psql -U bsdmagic -c “ALTER TABLE magazine ADD COLUMN ts timestamp default ‘now’::text::timestamp;” bsddb
ALTER TABLE
~> psql -U bsdmagic -c “SELECT pg_start_backup(‘MY FIRST PITR’);” bsddb
pg_start_backup
——————
0/3C000020
(1 row)
~> cp -Rf /postgresql/cluster1/* /postgresql/cluster2/
~> rm /postgresql/cluster2/pg_xlog/*
~> rm /postgresql/cluster2/postmaster.pid
~> psql -U bsdmagic -c “SELECT pg_stop_backup();” bsddb
NOTICE: pg_stop_backup complete, all required WAL segments have been archived
pg_stop_backup
—————-
0/3C000094
(1 row)
bsddb=# INSERT INTO magazine(id, title)
VALUES( generate_series(1, 200000), ‘BATCH-1’);
INSERT 0 200000
bsddb=# INSERT INTO magazine(id, title)
VALUES( generate_series(200001, 400000), ‘BATCH-2’);
INSERT 0 200000
bsddb=# INSERT INTO magazine(id, title)
VALUES( generate_series(400001, 600000), ‘BATCH-3’);
INSERT 0 200000
bsddb=# INSERT INTO magazine(id, title)
VALUES( generate_series(600001, 1000000), ‘BATCH-4’);
INSERT 0 400000
bsddb=# SELECT ts::time, title FROM magazine GROUP BY ts,title ORDER BY title;
ts | title
——————+———
08:22:42.982515 | BATCH-1
08:22:51.401579 | BATCH-2
08:23:03.243077 | BATCH-3
08:23:17.011491 | BATCH-4
(4 rows)
bsddb=# TRUNCATE TABLE magazine;
TRUNCATE TABLE
Теперь представьте, что мы хотим вернуться в момент времени 08:23:18 (третья инструкция отработана, но четвертый блок еще не завершен – временные метки в листинге 13 определяются, когда запускается команда INSERT).
Чтобы восстановить систему к этому времени нам нужно:
• остановить экземпляр базы
• поменять директорию PGDATA в /etc/rc.conf на нашу физическую копию;
• создать файл recovery.conf в нашей новой директории PGDATA, в котором будет храниться позиция о сохраненных WAL-логах, а также время к которому мы хотим восстановить базу.
• создать файл recovery.conf в нашей новой директории PGDATA, в котором будет храниться место сохраненных WAL-логов, а также время к которому мы хотим восстановить базу.
В Листинге 14 показано, что при перезапуске базы содержимое таблицы magazine возвращается к состоянию, когда третий блок отработал.
Листинг 14. Тестируем PITR
~> cat /etc/rc.conf | grep postgres
postgresql_enable=”YES”
postgresql_data=”/postgresql/cluster2”
~> cat /postgresql/cluster2/recovery.done
restore_command = ‘cp /postgresql/pitr/%f “%p”’
recovery_target_time = ‘2012-01-20 08:23:18’
~> service postgresql start
~> psql -U bsdmagic -c “SELECT ts::time, title, count(title) FROM magazine GROUP BY ts,title ORDER BY title;” bsddb
ts | title | count
——————+———+———
08:22:42.982515 | BATCH-1 | 200000
08:22:51.401579 | BATCH-2 | 200000
08:23:03.243077 | BATCH-3 | 200000
~> cat /postgresql/cluster2/recovery.done
restore_command = ‘cp /postgresql/pitr/%f “%p”’
recovery_target_time = ‘2012-01-20 08:23:18’
Стоит отметить, что как только восстановление отработало, система переименовывает файл recovery. conf в recovery.done, а другой текстовый файл –backup_label – переименовывается в backup_label.old. В последнем хранится информация о том, когда физическое архивирование началось, название для
архива (которое было передано в pg_start_backup()), а также информация об WAL. Оба файла могут использоваться для анализа текущего состояния кластера.
Как видите, PITR – очень мощный инструмент для кластерного архивирования.Ограничений отката назад по времени для PITR нет,как и ограничений на сам метод архивирования логов WAL – достаточно выделить для них необходимое пространство и задействовать нужную команду (например, cp, scp, tar и т.д.), чтобы иметь возможность сохранить и восстановить всю историю СУБД.
Какую стратегию архивирования использовать?
Выбор правильной стратегии архивирования зависит от загрузки кластера. Логическое архивирование самое простое и должно быть использовано всякий раз, когда для него не потребуется много времени или места (или когда, вам требуется сделать полную копию базы). Когда же выгрузка занимает много времени (например, базы слишком большие) или же
для выгружаемых баз требуется слишком много места, то тогда следует обратить внимание на физическое архивирование.
Вы даже можете использовать оба варианта – логическое и физическое архивирование – делая архивные копии WAL-логов для нужд PITR в промежутках между двумя логическими архивами.
Таким образом вы получаете инкрементальный архив до следующего полного (логического) архива.
Убедитесь, что выбранная стратегия удовлетворяет вашим потребностям и работает правильно.