Дифференциальные и инкрементальные бэкапы MySQL

Kate

Administrator
Команда форума
Для MySQL существует широко известный инструмент по созданию резервных копий баз данных — mysqldump, который создаёт дамп посредством записи серии SQL-инструкций для восстановления таблиц и данных целевой базы данных.

Он неплохо подходит для резервного копирования небольших баз данных, но когда база данных набирает приличный «вес» и возникает необходимость резервного копирования чаще, чем раз в сутки, скорость создания и размеры дампов могут стать проблемой. В данном случае на помощь приходят утилиты, создающие копию бинарных файлов баз данных, например, такие как Percona XtraBackup.

Percona XtraBackup поддерживает «горячее» резервное копирование для серверов MySQL, Percona, MariaDB и Drizzle (бета) всех версий.

Среди преимуществ такого подхода можно выделить следующие:

Высокая скорость создания резервных копий — так как при резервном копировании используется прямое копирование файлов — скорость создания таких копий будет ограничена скоростью дисковой подсистемы.
Отсутствие блокировок для подсистем хранения InnoDB, XtraDB, и HailDB.
Автоматическая проверка целостности.
Инкрементальные бэкапы.
Компрессия «на лету» — что позволяет делать резервное копирование по сети быстрее.


Как это работает

XtraBackup начинает копировать файлы баз данных, запоминая номер транзакции на момент начала (LSN), так как копирование файлов занимает какое-то время, данные в них могут измениться, поэтому параллельно XtraBackup запускает процесс, который отслеживает файлы с логами транзакций и копирует все изменения прошедшие с начала копирования.

После того как файлы скопированы, для получения работоспособной копии XtraBackup должен выполнить этап восстановления (crash recovery), используя сохранённый лог транзакций, на данном этапе к файлам баз данных будут применены завершённые транзакции из файла лога транзакций. Транзакции, которые изменили данные, но не были завершены, будут отменены.

После этого этапа файлы баз данных можно использовать для восстановления сервера путём его остановки и копирования файлов в их первоначальное расположение — вручную или используя XtraBackup (обычно это /var/lib/mysql, если сервер MySQL настроен по умолчанию).

Дифференциальные и инкрементальные бэкапы



Часто бывает так, что потеря данных даже за короткий промежуток времени весьма чувствительна, и возникает необходимость делать резервное копирование как можно чаще.
Создание полных бэкапов больших баз данных чаще, чем раз в день, может быть затруднительным — как правило, из-за размера дампов, тут как раз возможность копирования только выполненных изменений будет как нельзя кстати.

В зависимости от стратегии копирования могут использоваться дифференциальные и инкрементальные бэкапы, дополнительно к полным. Дифференциальный бэкап содержит изменения в данных относительно полного бэкапа, инкрементальный — содержит изменения со времени последнего частичного бэкапа – последней инкрементальной копии.

В зависимости от размера баз данных и необходимой частоты резервного копирования стратегии могут заметно отличаться, я же рассмотрю вариант с «недельным» планом, когда в конце недели создаётся полный бэкап, в начале каждого рабочего дня создаётся дифференциальный бэкап, и каждый час в течение рабочего времени — создание инкрементального бэкапа.

Такой план в самом плохом сценарии позволит сохранить данные, не потеряв более одного часа, или восстановить состояние баз на начало любого рабочего часа. А наличие дифференциального бэкапа позволит сократить количество необходимых копий, используемых при восстановлении.

Установка XtraBackup и настройка расписания

Дальнейшие действия выполнялись на CentOS 8, скачать подходящую версию XtraBackup можно с официального сайта.

Для создания полной резервной копии нужно запустить xtrabackup с опцией --backup. Дополнительно можно использовать опцию --target-dir, которая указывает на директорию, где будет создан бэкап, если директория для создания бэкапа не существует, Xtrabackup создаст её.

По умолчанию XtraBackup ищет данные конфигурации сервера и данные подключения пользователя из файлов:

/etc/my.cnf
/etc/mysql/my.cnf
/usr/etc/my.cnf
~/.my.cnf

Если есть необходимость переопределить настройки сервера и клиента, можно создать отдельный .cnf файл и указать его с опцией --defaults-file, я не буду использовать эту опцию, так как логин и пароль пользователя для подключения клиента MySQL у меня заданы в /root/.my.cnf:

[client]
user=root
password=mysqlpassword


1. Установка:

Скачаем и установим XtraBackup из RPM:

wget
yum localinstall percona-xtrabackup-80-8.0.26-18.1.el8.x86_64.rpm

Если планируется использовать компрессию, потребуется установить Qpress:

wget
yum localinstall qpress-11-1.el8.x86_64.rpm

2. Проверим, что установка прошла успешно:

xtrabackup -v


3. Создадим минимальную версию скрипта, который можно будет вызывать по расписанию в cron:

#!/bin/sh

BACKUP_PATH="/data/backups/db"
BACKUP_FULL="$(date -dlast-monday +%Y%m%d)-FULL"
BACKUP_DIFF="$(date +%Y%m%d)-DIFF"
BACKUP_INCR="$(date +%Y%m%d)-INCR-$(date +%H%M)"
XTRABACKUP_THREADS="--parallel 2"
XTRABACKUP_COMPRESS_OPTIONS="--compress --compress-threads=2"

case "$1" in
"")
echo "Required parameter missing! Use full, diff, incr as first parameter to make corresponding backup."
;;

"full")
if [[ ! -e $BACKUP_PATH/$BACKUP_FULL ]]; then
/usr/bin/xtrabackup --backup $XTRABACKUP_THREADS $XTRABACKUP_COMPRESS_OPTIONS --no-timestamp --target-dir=$BACKUP_PATH/$BACKUP_FULL
echo "Full backup complete."
else
echo "ERROR: Full backup already exist for current stage!"
exit
fi
;;

"diff")
if [[ ! -e $BACKUP_PATH/$BACKUP_FULL ]]; then
echo "ERROR: Corresponding full backup doesnt exists!"
exit
elif [[ ! -e $BACKUP_PATH/$BACKUP_DIFF ]]; then
/usr/bin/xtrabackup --backup $XTRABACKUP_THREADS $XTRABACKUP_COMPRESS_OPTIONS --no-timestamp --target-dir=$BACKUP_PATH/$BACKUP_DIFF --incremental-basedir=$BACKUP_PATH/$BACKUP_FULL
echo "Differential backup complete."
else
echo "ERROR: Differential backup exists for current stage!"
fi
;;

"incr")
if [[ ! -e $BACKUP_PATH/$BACKUP_DIFF ]]; then
echo "ERROR: Corresponding differential backup doesnt exists!"
exit
elif ! compgen -G "$BACKUP_PATH/$(date +%Y%m%d)-INCR*" > /dev/null; then
echo "Incremental backup dir not found - differential backup used as incremental basedir..."
/usr/bin/xtrabackup --backup $XTRABACKUP_THREADS $XTRABACKUP_COMPRESS_OPTIONS --no-timestamp --target-dir=$BACKUP_PATH/$BACKUP_INCR --incremental-basedir=$BACKUP_PATH/$BACKUP_DIFF
echo "Incremental backup complete."
exit
else
echo "Incremental backup dir found - last incremental backup used as incremental basedir..."
INCR_PATH_BASE="$(find /data/backups/db/ -name "*INCR*" -printf "%P\n" | sort -n | tail -1)"
/usr/bin/xtrabackup --backup $XTRABACKUP_THREADS $XTRABACKUP_COMPRESS_OPTIONS --no-timestamp --target-dir=$BACKUP_PATH/$BACKUP_INCR --incremental-basedir=$BACKUP_PATH/$INCR_PATH_BASE
echo "Incremental backup complete."
exit
fi
;;
esac


4. Добавим расписание в /etc/crontab:

# Full mysql backup every monday at 00:00
0 0 * * MON root /opt/mysql-backup/mysql-backup full

# Differential backup every day at 08:00
0 8 * * * root /opt/mysql-backup/mysql-backup diff

# Incremental backup every hour between 09:00-20:00
0 9-20 * * * root /opt/mysql-backup/mysql-backup incr

Теперь резервное копирование будет выполняться по заданному расписанию в каталог /data/backups/db (как было задано в скрипте), но нужно учесть, что копирование не начнется, пока не будет создан полный и дифференциальный бэкап (в понедельник), поэтому, чтобы проверить работу скрипта, мы создадим их вручную:

/opt/mysql-backup/mysql-backup full
/opt/mysql-backup/mysql-backup diff


Восстановление

Для восстановления состояния баз на требуемое время, нам нужно будет выполнить последовательно этапы:

Разархивировать требуемые бэкапы, если использовалось компрессирование
Подготовить полный бэкап и применить требуемые бэкапы (полный, дифференциальный и все последующие инкрементальные до нужного момента времени)
Остановить сервер mysql, при необходимости сделать копию текущих файлов сервера
Скопировать файлы из подготовленной копии на место оригинальных файлов


1. Разархивирование

xtrabackup --decompress --target-dir=/data/backups/db/20210913-FULL/
xtrabackup --decompress --target-dir=/data/backups/db/20210916-DIFF/
xtrabackup --decompress --target-dir=/data/backups/db/20210916-INCR-2239/

В этапе подготовки, в случае когда к полному бэкапу будут применены последующие инкрементальные бэкапы, необходимо указать опцию --apply-log-only, чтобы не отменять незавершённые транзакции.

2. Подготовка:

xtrabackup --prepare --apply-log-only --target-dir=/data/backups/db/20210913-FULL/
xtrabackup --prepare --apply-log-only --target-dir=/data/backups/db/20210913-FULL/ --incremental-dir=/data/backups/db/20210916-DIFF/
xtrabackup --prepare --apply-log-only --target-dir=/data/backups/db/20210913-FULL/ --incremental-dir=/data/backups/db/20210916-INCR-2239/

Теперь, когда в каталоге /data/backups/db/20210913-FULL/ у нас готовые к использованию файлы баз данных, осталось остановить сервер, удалить или перенести старые файлы и скопировать новые файлы в оригинальное расположение и восстановить владельца файлов (mysql).

3. Применение резервной копии:

systemctl stop mysqld
rm -rf /var/lib/mysql/*
xtrabackup --copy-back --target-dir=/data/backups/db/20210913-FULL/
chown -R mysql. /var/lib/mysql
systemctl start mysqld


Заключение

Как известно, администраторы делятся на тех, кто не делает бэкап, и тех, кто уже делает. Последних же можно ещё поделить на тех, кто не проверяет целостность резервных копий, и тех, кто уже проверяет.

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

 
Сверху