Application: "PostgreSQL v9.2/10", "pg_basebackup".
Задача: обеспечить возможность максимально быстрого снятия резервной копии всех данных действующей СУБД "PostgreSQL", без блокирования работы таковой даже на кратчайший момент времени.
Резервное копирование крупных и активно изменяемых баз данных путём выгрузки классического "текстового (логического) дампа", состоящего из набора SQL-команд наполнения таблиц практически неприменимо: это очень долго (SQL-дампы БД за десятки Гигабайт могут более получаса генерироваться), сильно нагружает дисковую и вычислительную подсистемы несущего сервера валом запросов на чтение и последующую запись, а также не всегда гарантирует консистентное состояние финального набора данных (в силу того, что во время длительного процесса создания последовательного набора SQL-строк после сохранения в резервной копии строки из начала набора таковая может быть изменена, и связанные с ней данные в конце набора будут ссылаться на уже устаревшие сведения).
Естественно, что с ростом объёмов операционных данных были придуманы быстрые и эффективные способы их резервного копирования. В PostgreSQL это решено просто - вначале копируются файлы данных, как они есть, после чего архив дополняется файлами, содержащими журнал транзакций, скопившихся за время процедуры копирования. При этом СУБД не перестаёт обслуживать клиентов, а сама процедура протекает в десятки и сотни раз быстрее генерирования SQL-дампа.
Кроме того, что "бинарный дамп" создаётся быстрее "логического", так он ещё и в работу запускается за пару минут - это копия файлов данных, которые элементарно подкладывается пустому инстансу "PostgreSQL", который практически сразу начинает обслуживать запросы, самостоятельно догнав состояние "базы данных" до последней транзакции из прилагаемых WAL-журналов.
Никаких утилит или приложений, помимо комплектных самой СУБД "PostgreSQL" для решения нашей задачи не требуется. Приступим.
Предварительная настройка СУБД.
Функционал снятия "бинарных" резервных копий в "PostgreSQL" реализован через подсистемы репликации и журналирования транзакций WAL (Write-Ahead Log). Активируем таковые и определяем ряд ключевых параметров:
# vi /etc/postgresql/9.5/main/postgresql.conf
....
# Активируем режим журналирования, достаточный для снятия "горячих" резервных копий
wal_level = archive
# Задаём количество хранящихся в директории "pg_xlog" файлов журнала WAL, ротируемых по мере появления свежих данных
# (в среднем один файл по 16MB, то есть в примере мы забираем места до полугигабайта)
wal_keep_segments = 32
# Явно ограничиваем число обслуживаемых соединений передачи данных в режиме "репликации"
# (один поток для выгрузки файлов данных и второй для текущих транзакций)
max_wal_senders = 2
....
# Активируем режим журналирования, достаточный для снятия "горячих" резервных копий
wal_level = archive
# Задаём количество хранящихся в директории "pg_xlog" файлов журнала WAL, ротируемых по мере появления свежих данных
# (в среднем один файл по 16MB, то есть в примере мы забираем места до полугигабайта)
wal_keep_segments = 32
# Явно ограничиваем число обслуживаемых соединений передачи данных в режиме "репликации"
# (один поток для выгрузки файлов данных и второй для текущих транзакций)
max_wal_senders = 2
....
В процессе резервного копирования потребуется несколько раз подключиться к СУБД: вначале уведомить таковую о запуске процедуры резервного копирования (с этого момента запись будет осуществляться по возможности только в журналы транзакций), потом выгрузить данные как таковые, после чего сообщить об успешном завершении копирования файлов данных (с этого момента сервер возобновляет сброс транзакций в файлы данных) и в итоге запросить журналы транзакций, скопившихся за время копирования файлов "баз данных" (опционально транзакции можно отслеживать в процессе выгрузки основного массива данных).
Так как функционал выгрузки файлов "баз данных" и журналов транзакций в "PostgreSQL" реализован через подсистему репликации, а для получения доступа ко всему этому содержимому всё равно нужны весьма высокие полномочия доступа, то проще всего будет разрешить локально аутентифицированному пользователю "postgres" обращение к СУБД рамках специального режима исполнения функционала репликации, ограничив область подключений локальным "сокетом":
# vi /etc/postgresql/9.5/main/pg_hba.conf
....
# TYPE DATABASE USER ADDRESS METHOD
# --------------------------------------------
....
# Replication connections login by host trust
local replication postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# --------------------------------------------
....
# Replication connections login by host trust
local replication postgres peer
Изменение вышеприведённых параметров требует перезагрузки сервера СУБД:
# /etc/init.d/postgresql restart
Пример резервного копирования посредством "pg_basebackup".
Заготовим место для файлов резервных копий, передав его в полное исключительное владение пользователю, в контексте которого будет исполняться задача:
# mkdir -p /var/backups/postgresql
# chown -R postgres:postgres /var/backups/postgresql
# chmod -R go-rwx /var/backups/postgresql
# chown -R postgres:postgres /var/backups/postgresql
# chmod -R go-rwx /var/backups/postgresql
В комплекте программного обеспечения "PostgreSQL" имеется утилита "pg_basebackup", через механизм репликации вытаскивающая "бинарный (файловый) бэкап" и журнал транзакций. Данные между исходным каталогом СУБД и файловой структурой резервной копии синхронизируются в полном объёме, включая вообще всё внутри директории таковых (даже свежие журналы WAL, успевшие накопиться за время процедуры транспортировки), так что есть смысл предварительно зачистить место:
# rm -r /var/backups/postgresql/*
Запускаем процедуру снятия локальной полной "бинарной" резервной копии всех имеющихся на сервере "баз данных" PostgreSQL:
# sudo -u postgres pg_basebackup -v -X fetch -R -D /var/backups/postgresql
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
transaction log start point: ...
transaction log end point: ...
pg_basebackup: base backup completed
pg_basebackup: checkpoint completed
transaction log start point: ...
transaction log end point: ...
pg_basebackup: base backup completed
В итоге получается набор данных, полностью готовый к запуску в виде автономного инстанса "PostgreSQL".
Опция "-X fetch" указывает "pg_basebackup" осуществить загрузку в два этапа: вначале файлы "баз данных" как таковых, а потом добрать файлы журнала WAL, содержащие транзакции случившиеся после начала копирования файлов основного массива данных и приложить их к уже имеющимся журналам. Если выбрать метод загрузки данных "-X stream" (используемый по умолчанию, кстати), то файлы журналов WAL не будут загружаться, а случающиеся во время резервного копирования транзакции будут передаваться параллельным основному потоком и применяться к загруженным файлам данных "на лету". В целом второй способ удобнее, но он появился только в "PostgreSQL v9.2".
Как вариант, можно указать утилите упаковывать файлы в монолитный Tar-архив, сжимаемый на лету в формате GZip (но потом его придётся раскрывать, на что уходит время):
# sudo -u postgres pg_basebackup -X fetch -R -F tar -z -D /var/backups/postgresql
Пример восстановления данных из резервной копии.
Восстановление или запуск на новом месте из полной "бинарной" резервной копии, полученной в результате работы "pg_basebackup", элементарно - достаточно остановить целевой PostgreSQL-сервер и подменить содержимое его директории данных резервной копией:
# /etc/init.d/postgresql stop
# mv /var/lib/postgresql/9.5/main /var/lib/postgresql/9.5/main.old
# rsync -avrP /var/backups/postgresql /var/lib/postgresql/9.5/main
# chown -R postgres:postgres /var/lib/postgresql
# chmod -R go-rwx /var/lib/postgresql/
# /etc/init.d/postgresql start
# mv /var/lib/postgresql/9.5/main /var/lib/postgresql/9.5/main.old
# rsync -avrP /var/backups/postgresql /var/lib/postgresql/9.5/main
# chown -R postgres:postgres /var/lib/postgresql
# chmod -R go-rwx /var/lib/postgresql/
# /etc/init.d/postgresql start
Одно из требований "PostgreSQL" - наличие конфигурационного файла "recovery.conf" для перехода в режим восстановления "баз данных" путём применения транзакций из WAL-журнала - удовлетворяется утилитой "pg_basebackup" без особых на то указаний. Сразу после "проигрывания" всего WAL-журнала и восстановления целостности БД файл автоматически переименовывается в "recovery.conf.done", а сервер СУБД переходил в нормальный режим обслуживания клиентов.
5 января 2021 в 03:31
5 января 2021 в 11:50