Настройка резервного копирования MySQL с помощью Percona XtraBackup в Ubuntu 16.04

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

Средство резервного копирования Percona XtraBackup позволяет выполнять горячее резервное копирование данных MySQL во время работы системы. При этом инструмент копирует файлы данных на уровне файловой системы, а затем выполняет аварийное восстановление для достижения согласованности в наборе данных.

Данный мануал поможет создать систему для автоматизации резервного копирования данных MySQL на сервере Ubuntu 16.04. Для создания регулярных безопасных бэкапов в сценариях будут использоваться cron и инструменты Percona.

Требования

1: Установка инструментов Percona Xtrabackup

Сначала нужно установить утилиты для резервного копирования Percona. Проект поддерживает свои собственные репозитории, которые можно добавить на сервер MySQL, чтобы получить доступ к пакетам.

Откройте страницу релизов Percona для Ubuntu и найдите последний deb пакет, чтобы установить репозиторий. Кодовое имя Ubuntu 16.04 – Xenial Xerus, потому нужно найти пакет xenial. Кликните правой кнопкой по соответствующей ссылке и скопируйте адрес.

Примечание: Чтобы проверить кодовое имя сервера, введите:

lsb_release -c
Codename:   xenial

Скопировав ссылку, перейдите в каталог /tmp, а затем загрузите пакет конфигурации репозитория с помощью curl:

cd /tmp
curl -LO https://repo.percona.com/apt/percona-release_0.1-4.xenial_all.deb

Затем используйте dpkg для установки загруженного пакета, который настроит репозиторий Percona:

sudo dpkg -i percona*

Когда новый репозиторий будет настроен, обновите индекс локальных пакетов, чтобы добавить информацию о новых доступных пакетах. Затем установите инструменты XtraBackup и утилиту сжатия qpress из нового репозитория:

sudo apt-get update
sudo apt-get install percona-xtrabackup-24 qpress

Среди других укомплектованных утилит теперь доступны команды xtrabackup, xbstream и qpress. Сценарии бэкапов будут использовать каждую из них для выполнения резервного копирования и восстановления данных.

2: Настройка пользователя для резервного копирования MySQL и добавление тестовых данных

Для начала запустите интерактивный сеанс MySQL как пользователь root:

mysql -u root -p

MySQL запросит пароль администратора.

Создание пользователя MySQL и настройка прав

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

Выберите описательное имя для этого пользователя (например, backup). Учетные данные пользователя будут храниться в защищенном файле; выберите сложный пароль:

CREATE USER 'backup'@'localhost' IDENTIFIED BY 'password';

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

GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT, CREATE TABLESPACE, PROCESS, SUPER, CREATE, INSERT, SELECT ON *.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;

Теперь пользователь для резервного копирования MySQL настроен и имеет необходимые права доступа.

Создание тестовых данных

Затем создайте тестовые данные. Выполните следующие команды, чтобы создать БД playground с таблицей equipment и добавить в нее первую запись:

CREATE DATABASE playground;
CREATE TABLE playground.equipment ( id INT NOT NULL AUTO_INCREMENT, type VARCHAR(50), quant INT, color VARCHAR(25), PRIMARY KEY(id));
INSERT INTO playground.equipment (type, quant, color) VALUES ("slide", 2, "blue");

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

Прежде чем завершить сеанс MySQL, проверьте значение переменной datadir, чтобы убедиться, что пользователь backup на системном уровне имеет доступ к файлам данных MySQL.

Чтобы отобразить значение datadir, введите:

SELECT @@datadir;
+-----------------+
| @@datadir       |
+-----------------+
| /var/lib/mysql/ |
+-----------------+
1 row in set (0.01 sec)

Запишите полученный путь.

Теперь можно закрыть оболочку MySQL:

exit

3: Настройка системного пользователя для резервного копирования и настройка прав

Теперь, когда у вас есть пользователь MySQL, нужно создать соответствующего пользователя Linux с аналогичными ограниченными привилегиями.

В Ubuntu 16.04 уже имеется пользователь backup и соответствующая группа backup. Чтобы убедиться в этом, проверьте файлы /etc/passwd и /etc/group:

grep backup /etc/passwd /etc/group
/etc/passwd:backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
/etc/group:backup:x:34:

Первая строка из файла /etc/passwd описывает пользователя backup, а вторая строка из файла /etc/group определяет группу backup.

Каталог /var/lib/mysql, где хранятся данные MySQL, принадлежит пользователю и группе mysql. Можно добавить пользователя backup в группу mysql, чтобы обеспечить безопасный доступ к файлам и каталогам БД. Также нужно добавить пользователя sudo в группу backup, чтобы у него был доступ к резервным копиям.

Введите следующие команды, чтобы добавить пользователя backup в группу mysql, а пользователя sudo в группу backup.

sudo usermod -aG mysql backup
sudo usermod -aG backup ${USER}

Попробуйте снова проверить файлы /etc/group; вы увидите, что текущий пользователь добавлен в группу backup, а пользователь backup – в группу mysql.

grep backup /etc/group
backup:x:34:8host
mysql:x:116:backup

Новая группа недоступна в текущем сеансе автоматически. Чтобы обновить список групп, доступных пользователю sudo, выйдите из системы и войдите снова, либо введите:

exec su - ${USER}

При этом будет запрошен пароль пользователя sudo. Убедитесь, что в текущем сеансе у вас есть доступ к группе backup:

id -nG
8host sudo backup

Теперь пользователь sudo сможет пользоваться данными группы backup.

Далее нужно сделать каталог /var/lib/mysql и его подкаталоги доступными для группы mysql, предоставив права на изменение. В противном случае пользователь backup не сможет войти в эти каталоги, хотя он является членом группы mysql.

Примечание: Если значение datadir – не /var/lib/mysql, укажите правильный путь к каталогу.

Чтобы дать группе mysql доступ к каталогам данных MySQL, введите:

sudo find /var/lib/mysql -type d -exec chmod 750 {} \;

4: Создание активов резервного копирования

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

Создание конфигурационного файла MySQL

Начните с создания базового конфигурационного файла MySQL, который будет использовать сценарий резервного копирования. Он будет содержать учетные данные MySQL для пользователя MySQL.

Откройте /etc/mysql/backup.cnf в редакторе:

sudo nano /etc/mysql/backup.cnf

Создайте раздел [client] и поместите в него данные о пользователе backup:

[client]
user=backup
password=password

Сохраните и закройте файл.

Передайте права на файл пользователю backup и ограничьте доступ к файлу для других пользователей.

sudo chown backup /etc/mysql/backup.cnf
sudo chmod 600 /etc/mysql/backup.cnf

Пользователь backup сможет получить доступ к этому файлу, чтобы найти соответствующие учетные данные, но другие пользователи не смогут открыть файл.

Создание корневого каталога для бэкапа

Затем создайте каталог для хранения резервных копий. В мануале в качестве базового каталога для резервных копий используется /backups/mysql:

sudo mkdir -p /backups/mysql

Передайте права на каталог /backups/mysql пользователю backup и группе mysql:

sudo chown backup:mysql /backups/mysql

Теперь пользователь backup может записывать данные в этот каталог.

Создание ключа шифрования

Поскольку резервные копии содержат все данные из СУБД, важно обеспечить их надлежащую защиту. Утилита xtrabackup имеет возможность шифровать каждый файл при его резервном копировании и архивировании. Нужно просто предоставить ключ шифрования.

Можно создать ключ шифрования в корневом каталоге с помощью команды openssl:

printf '%s' "$(openssl rand -base64 24)" | sudo tee /backups/mysql/encryption_key && echo

Очень важно также ограничить доступ к этому файлу. Опять же, передайте права пользователю backup и запретите доступ к нему всем другим пользователям:

sudo chown backup:backup /backups/mysql/encryption_key
sudo chmod 600 /backups/mysql/encryption_key

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

5: Создание сценариев резервного копирования и восстановления

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

Чтобы автоматизировать резервное копирование и восстановление, нужно создать сценарии всего процесса:

  • backup-mysql.sh: этот сценарий создает резервные копии баз данных MySQL, шифруя и сжимая файлы. Он создает полные и инкрементные резервные копии и автоматически систематизирует контент. По умолчанию сценарий поддерживает резервные копии в течение 3 дней.
  • extract-mysql.sh: этот сценарий распаковывает и расшифровывает файлы резервных копий для создания каталогов с резервными данными.
  • prepare-mysql.sh: этот сценарий подготавливает резервные каталоги, обрабатывая файлы и логи. Все инкрементные резервные копии применяются к полной резервной копии. После завершения этого сценария файлы готовы к возврату в каталог данных.

Вы можете просмотреть сценарии в репозитории на GitHub. Если вы не хотите копировать и вставлять код сценариев вручную, вы можете загрузить их непосредственно с GitHub:

cd /tmp
curl -LO https://raw.githubusercontent.com/do-community/ubuntu-1604-mysql-backup/master/backup-mysql.sh
curl -LO https://raw.githubusercontent.com/do-community/ubuntu-1604-mysql-backup/master/extract-mysql.sh
curl -LO https://raw.githubusercontent.com/do-community/ubuntu-1604-mysql-backup/master/prepare-mysql.sh

Обязательно проверьте сценарии после загрузки, чтобы убедиться, что они были загружены успешно и не делают ничего лишнего. Если вы довольны сценариями, сделайте их исполняемыми, а затем переместите их в каталог /usr/local/bin:

chmod +x /tmp/{backup,extract,prepare}-mysql.sh
sudo mv /tmp/{backup,extract,prepare}-mysql.sh /usr/local/bin

Ниже мы рассмотрим эти сценарии более подробно

Создание сценария backup-mysql.sh

Если вы хотите создать сценарий backup-mysql.sh вручную, а не загружать его с GitHub, создайте файл в каталоге /usr/local/bin:

sudo nano /usr/local/bin/backup-mysql.sh

Скопируйте и вставьте в него следующий сценарий:

#!/bin/bash
export LC_ALL=C
days_of_backups=3  # Must be less than 7
backup_owner="backup"
parent_dir="/backups/mysql"
defaults_file="/etc/mysql/backup.cnf"
todays_dir="${parent_dir}/$(date +%a)"
log_file="${todays_dir}/backup-progress.log"
encryption_key_file="${parent_dir}/encryption_key"
now="$(date +%m-%d-%Y_%H-%M-%S)"
processors="$(nproc --all)"
# Use this to echo to standard error
error () {
printf "%s: %s\n" "$(basename "${BASH_SOURCE}")" "${1}" >&2
exit 1
}
trap 'error "An unexpected error occurred."' ERR
sanity_check () {
# Check user running the script
if [ "$USER" != "$backup_owner" ]; then
error "Script can only be run as the \"$backup_owner\" user"
fi
# Check whether the encryption key file is available
if [ ! -r "${encryption_key_file}" ]; then
error "Cannot read encryption key at ${encryption_key_file}"
fi
}
set_options () {
# List the xtrabackup arguments
xtrabackup_args=(
"--defaults-file=${defaults_file}"
"--backup"
"--extra-lsndir=${todays_dir}"
"--compress"
"--stream=xbstream"
"--encrypt=AES256"
"--encrypt-key-file=${encryption_key_file}"
"--parallel=${processors}"
"--compress-threads=${processors}"
"--encrypt-threads=${processors}"
"--slave-info"
)
backup_type="full"
# Add option to read LSN (log sequence number) if a full backup has been
# taken today.
if grep -q -s "to_lsn" "${todays_dir}/xtrabackup_checkpoints"; then
backup_type="incremental"
lsn=$(awk '/to_lsn/ {print $3;}' "${todays_dir}/xtrabackup_checkpoints")
xtrabackup_args+=( "--incremental-lsn=${lsn}" )
fi
}
rotate_old () {
# Remove the oldest backup in rotation
day_dir_to_remove="${parent_dir}/$(date --date="${days_of_backups} days ago" +%a)"
if [ -d "${day_dir_to_remove}" ]; then
rm -rf "${day_dir_to_remove}"
fi
}
take_backup () {
# Make sure today's backup directory is available and take the actual backup
mkdir -p "${todays_dir}"
find "${todays_dir}" -type f -name "*.incomplete" -delete
xtrabackup "${xtrabackup_args[@]}" --target-dir="${todays_dir}" > "${todays_dir}/${backup_type}-${now}.xbstream.incomplete" 2> "${log_file}"
mv "${todays_dir}/${backup_type}-${now}.xbstream.incomplete" "${todays_dir}/${backup_type}-${now}.xbstream"
}
sanity_check && set_options && rotate_old && take_backup
# Check success and print message
if tail -1 "${log_file}" | grep -q "completed OK"; then
printf "Backup successful!\n"
printf "Backup created at %s/%s-%s.xbstream\n" "${todays_dir}" "${backup_type}" "${now}"
else
error "Backup failure! Check ${log_file} for more information"
fi

Сценарий имеет следующие функции:

  • Создает зашифрованную, сжатую полную резервную копию при первом запуске каждый день.
  • Генерирует зашифрованные сжатые инкрементные резервные копии на основе ежедневной полной резервной копии при повторном вызове в тот же день.
  • Систематизирует копии по дням. По умолчанию резервные копии хранятся три дня. Это можно изменить, отредактировав параметр days_of_backups в сценарии.

Когда сценарий запускается, он ежедневно создает новый каталог, в котором будут храниться временные файлы, представляющие отдельные резервные копии. Первый файл с меткой времени будет представлять собой полную резервную копию с префиксом full-. Последующие резервные копии этого дня будут инкрементными (они обозначены префиксом incremental-), они представляют изменения с момента последнего полного или инкрементного резервного копирования.

Резервные копии будут генерировать файл backup-progress.log, в котором будет храниться вывод последней операции резервного копирования. Там также будет создан файл xtrabackup_checkpoints, содержащий последние метаданные резервных копий. Этот файл необходим для создания будущих инкрементных резервных копий, поэтому важно не удалять его. Также создается файл xtrabackup_info, который содержит дополнительные метаданные, но сценарий не ссылается на этот файл.

Сохраните и закройте файл.

Сделайте его исполняемым:

sudo chmod +x /usr/local/bin/backup-mysql.sh

Теперь вы можете запустить резервное копирование MySQL с помощью одной команды.

Создание сценария extract-mysql.sh

Затем нужно создать сценарий extract-mysql.sh для извлечения структуры каталога данных MySQL из отдельных файлов резервных копий.

Если ранее вы не загрузили сценарий из репозитория, создайте и откройте файл extract-mysql.sh в каталоге /usr/local/bin:

sudo nano /usr/local/bin/extract-mysql.sh

Затем вставьте в файл:

#!/bin/bash
export LC_ALL=C
backup_owner="backup"
encryption_key_file="/backups/mysql/encryption_key"
log_file="extract-progress.log"
number_of_args="${#}"
processors="$(nproc --all)"
# Use this to echo to standard error
error () {
printf "%s: %s\n" "$(basename "${BASH_SOURCE}")" "${1}" >&2
exit 1
}
trap 'error "An unexpected error occurred.  Try checking the \"${log_file}\" file for more information."' ERR
sanity_check () {
# Check user running the script
if [ "${USER}" != "${backup_owner}" ]; then
error "Script can only be run as the \"${backup_owner}\" user"
fi
# Check whether the qpress binary is installed
if ! command -v qpress >/dev/null 2>&1; then
error "Could not find the \"qpress\" command.  Please install it and try again."
fi
# Check whether any arguments were passed
if [ "${number_of_args}" -lt 1 ]; then
error "Script requires at least one \".xbstream\" file as an argument."
fi
# Check whether the encryption key file is available
if [ ! -r "${encryption_key_file}" ]; then
error "Cannot read encryption key at ${encryption_key_file}"
fi
}
do_extraction () {
for file in "${@}"; do
base_filename="$(basename "${file%.xbstream}")"
restore_dir="./restore/${base_filename}"
printf "\n\nExtracting file %s\n\n" "${file}"
# Extract the directory structure from the backup file
mkdir --verbose -p "${restore_dir}"
xbstream -x -C "${restore_dir}" < "${file}"
xtrabackup_args=(
"--parallel=${processors}"
"--decrypt=AES256"
"--encrypt-key-file=${encryption_key_file}"
"--decompress"
)
xtrabackup "${xtrabackup_args[@]}" --target-dir="${restore_dir}"
find "${restore_dir}" -name "*.xbcrypt" -exec rm {} \;
find "${restore_dir}" -name "*.qp" -exec rm {} \;
printf "\n\nFinished work on %s\n\n" "${file}"
done > "${log_file}" 2>&1
}
sanity_check && do_extraction "$@"
ok_count="$(grep -c 'completed OK' "${log_file}")"
# Check the number of reported completions.  For each file, there is an
# informational "completed OK".  If the processing was successful, an
# additional "completed OK" is printed. Together, this means there should be 2
# notices per backup file if the process was successful.
if (( $ok_count !=  $# )); then
error "It looks like something went wrong. Please check the \"${log_file}\" file for additional information"
else
printf "Extraction complete! Backup directories have been extracted to the \"restore\" directory.\n"
fi

В отличие от сценария backup-mysql.sh, который предназначен для автоматизации, этот скрипт предназначен планирования восстановления данных из резервной копии. Поэтому сценарий ожидает, что вы передадите ему файлы .xbstream, данные которых нужно извлечь.

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

По завершении этого процесса каталог restore должен содержать каталоги для каждой из переданных резервных копий. Это позволяет вам предварительно проверить содержимое резервных копий и решить, какие из них вы хотите подготовить и восстановить.

Сохраните и закройте файл. Сделайте сценарий исполняемым:

sudo chmod +x /usr/local/bin/extract-mysql.sh

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

Создание сценария prepare-mysql.sh

Теперь загрузите или создайте сценарий prepare-mysql.sh в каталоге /usr/local/bin. Этот сценарий будет применять логи каждой резервной копии для создания согласованного снапшота базы данных. Он будет применять все инкрементные резервные копии для полной резервной копии, чтобы встроить последующие изменения.

Создайте файл для сценария:

sudo nano /usr/local/bin/prepare-mysql.sh

Затем вставьте в него такой код:

#!/bin/bash
export LC_ALL=C
shopt -s nullglob
incremental_dirs=( ./incremental-*/ )
full_dirs=( ./full-*/ )
shopt -u nullglob
backup_owner="backup"
log_file="prepare-progress.log"
full_backup_dir="${full_dirs[0]}"
# Use this to echo to standard error
error() {
printf "%s: %s\n" "$(basename "${BASH_SOURCE}")" "${1}" >&2
exit 1
}
trap 'error "An unexpected error occurred.  Try checking the \"${log_file}\" file for more information."' ERR
sanity_check () {
# Check user running the script
if [ "${USER}" != "${backup_owner}" ]; then
error "Script can only be run as the \"${backup_owner}\" user."
fi
# Check whether a single full backup directory are available
if (( ${#full_dirs[@]} != 1 )); then
error "Exactly one full backup directory is required."
fi
}
do_backup () {
# Apply the logs to each of the backups
printf "Initial prep of full backup %s\n" "${full_backup_dir}"
xtrabackup --prepare --apply-log-only --target-dir="${full_backup_dir}"
for increment in "${incremental_dirs[@]}"; do
printf "Applying incremental backup %s to %s\n" "${increment}" "${full_backup_dir}"
xtrabackup --prepare --apply-log-only --incremental-dir="${increment}" --target-dir="${full_backup_dir}"
done
printf "Applying final logs to full backup %s\n" "${full_backup_dir}"
xtrabackup --prepare --target-dir="${full_backup_dir}"
}
sanity_check && do_backup > "${log_file}" 2>&1
# Check the number of reported completions.  Each time a backup is processed,
# an informational "completed OK" and a real version is printed.  At the end of
# the process, a final full apply is performed, generating another 2 messages.
ok_count="$(grep -c 'completed OK' "${log_file}")"
if (( ${ok_count} == ${#full_dirs[@]} + ${#incremental_dirs[@]} + 1 )); then
cat << EOF
Backup looks to be fully prepared.  Please check the "prepare-progress.log" file
to verify before continuing.
If everything looks correct, you can apply the restored files.
First, stop MySQL and move or remove the contents of the MySQL data directory:
sudo systemctl stop mysql
sudo mv /var/lib/mysql/ /tmp/
Then, recreate the data directory and  copy the backup files:
sudo mkdir /var/lib/mysql
sudo xtrabackup --copy-back --target-dir=${PWD}/$(basename "${full_backup_dir}")
Afterward the files are copied, adjust the permissions and restart the service:
sudo chown -R mysql:mysql /var/lib/mysql
sudo find /var/lib/mysql -type d -exec chmod 750 {} \\;
sudo systemctl start mysql
EOF
else
error "It looks like something went wrong.  Check the \"${log_file}\" file for more information."
fi

Скрипт просматривает текущий каталог на наличие в нем каталогов, начинающихся с префиксов full- или incremental-. Он использует логи MySQL, чтобы встроить совершенные транзакции в полную резервную копию. Затем он использует все инкрементные резервные копии для создания полной резервной копии и обновляет данные с помощью более поздних данных.

После того как все резервные копии были объединены, он откатывает незавершенные транзакции. На этот момент полная резервная копия будет представлять собой согласованный набор данных, которые могут быть перемещены в каталог данных MySQL.

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

Сохраните и закройте файл. Сделайте его исполняемым:

sudo chmod +x /usr/local/bin/prepare-mysql.sh

Это последний сценарий, который нужно запустить перед перемещением файлов резервных копий в каталог данных MySQL.

6: Тестирование сценариев резервного копирования и восстановления MySQL

Теперь все сценарии готовы и их нужно протестировать.

Полное резервное копирование

Вызовите сценарий backup-mysql.sh как пользователь backup:

sudo -u backup backup-mysql.sh
Backup successful!
Backup created at /backups/mysql/Thu/full-04-20-2017_14-55-17.xbstream

Если все пойдет так, как планировалось, сценарий сообщит об успешном копировании и выведет местоположение нового файла резервной копии. Как видно из вышеприведенного вывода, для хранения резервных копий за этот день был создан ежедневный каталог «Thu». Имя файла резервной копии начинается с префикса full-, который сообщает, что это полная резервная копия.

Перейдите в каталог резервного копирования и просмотрите содержимое:

cd /backups/mysql/"$(date +%a)"
ls
backup-progress.log  full-04-20-2017_14-55-17.xbstream  xtrabackup_checkpoints  xtrabackup_info

Здесь вы найдете файл резервной копии (full-04-20-2017_14-55-17.xbstream), лог события резервного копирования (backup-progress.log), файл xtrabackup_checkpoints, который включает в себя метаданные о бэкапе и файл xtrabackup_info, который содержит дополнительные метаданные.

Запросите последние строки из backup-progress.log, чтобы подтвердить, что резервная копия была создана успешно.

tail backup-progress.log
170420 14:55:19 All tables unlocked
170420 14:55:19 [00] Compressing, encrypting and streaming ib_buffer_pool to <STDOUT>
170420 14:55:19 [00]        ...done
170420 14:55:19 Backup created in directory '/backups/mysql/Thu/'
170420 14:55:19 [00] Compressing, encrypting and streaming backup-my.cnf
170420 14:55:19 [00]        ...done
170420 14:55:19 [00] Compressing, encrypting and streaming xtrabackup_info
170420 14:55:19 [00]        ...done
xtrabackup: Transaction log of lsn (2549956) to (2549965) was copied.
170420 14:55:19 completed OK!

Если открыть файл xtrabackup_checkpoints, можно просмотреть информацию о резервном копировании. Хотя этот файл предоставляет полезную для администраторов информацию, в основном он используется для последующих заданий резервного копирования, сообщая, какие данные уже были обработаны.

Это копия файла, который включен в каждый архив. Несмотря на то, что эта копия перезаписывается каждой новой операцией бэкапа, каждый исходный файл будет по-прежнему доступен в архиве резервных копий.

cat xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 2549956
last_lsn = 2549965
compact = 0
recover_binlog_info = 0

В приведенном выше примере сообщается, что на сервере была сделана полная резервная копия СУБД, которой присвоены номера последовательности логов (LSN)  от 0 до 2549956. Номер last_lsn указывает на то, что во время процесса резервного копирования произошли некоторые операции.

Инкрементное резервное копирование

Теперь, когда у вас есть полная резервная копия, вы можете попробовать использовать дополнительные инкрементные резервные копии. Инкрементные резервные копии записывают изменения, внесенные с момента последней резервной копии. Первая инкрементная резервная копия основана на полной резервной копии, а все последующие – на предыдущей инкрементной копии.

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

Вставьте еще одну запись в таблицу equipment в базе playground. При этом будет предложено ввести пароль администратора MySQL:

mysql -u root -p -e 'INSERT INTO playground.equipment (type, quant, color) VALUES ("swing", 10, "yellow");'

Теперь данные в СУБД изменились со времени последней резервной копии, и вы можете создать инкрементную резервную копию, чтобы зафиксировать эти изменения. Сценарий backup-mysql.sh будет выполнять инкрементную резервную копию, если в текущий день уже была создана полная резервная копия.

sudo -u backup backup-mysql.sh
Backup successful!
Backup created at /backups/mysql/Thu/incremental-04-20-2017_17-15-03.xbstream

Проверьте каталог резервных копий за текущий день и найдите архив инкрементной копии.

cd /backups/mysql/"$(date +%a)"
ls
backup-progress.log                incremental-04-20-2017_17-15-03.xbstream  xtrabackup_info
full-04-20-2017_14-55-17.xbstream  xtrabackup_checkpoints

В файле xtrabackup_checkpoints хранится результат последнего инкрементного копирования.

cat xtrabackup_checkpoints
backup_type = incremental
from_lsn = 2549956
to_lsn = 2550159
last_lsn = 2550168
compact = 0
recover_binlog_info = 0

Тип резервной копии – incremental. Кроме того, теперь LSN начинается не с 0, как в полной копии, а с того LSN, на котором останавливается последняя резервная копия.

Извлечение резервной копии

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

Вы можете извлечь резервные копии, передав файлы .xbstream сценарию extract-mysql.sh. Опять же, это должно выполняться пользователем backup:

sudo -u backup extract-mysql.sh *.xbstream
Extraction complete! Backup directories have been extracted to the "restore" directory.

Вышеприведенный вывод указывает, что процесс был успешно завершен. Если вы снова проверите содержимое каталога резервного копирования за текущий день, вы обнаружите файл extract-progress.log и каталог restore.

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

tail extract-progress.log
170420 17:23:32 [01] decrypting and decompressing ./performance_schema/socket_instances.frm.qp.xbcrypt
170420 17:23:32 [01] decrypting and decompressing ./performance_schema/events_waits_summary_by_user_by_event_name.frm.qp.xbcrypt
170420 17:23:32 [01] decrypting and decompressing ./performance_schema/status_by_user.frm.qp.xbcrypt
170420 17:23:32 [01] decrypting and decompressing ./performance_schema/replication_group_members.frm.qp.xbcrypt
170420 17:23:32 [01] decrypting and decompressing ./xtrabackup_logfile.qp.xbcrypt
170420 17:23:33 completed OK!
Finished work on incremental-04-20-2017_17-15-03.xbstream

Если вы откроете каталог restore, вы найдете каталоги, соответствующие извлеченным файлам резервной копии:

cd restore
ls -F
full-04-20-2017_14-55-17/  incremental-04-20-2017_17-15-03/

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

Подготовка файлов к восстановлению

Затем нужно подготовить резервные файлы. Для этого вы должны находиться в каталоге restore, содержащем резервные копии full- и incremental-. Сценарий будет использовать изменения всех каталогов incremental- в каталоге full-. Затем он использует логи для создания согласованного набора данных, который может использовать MySQL.

Если по какой-либо причине вы не хотите восстанавливать некоторые изменения, сейчас ваш последний шанс удалить инкрементные каталоги этих резервных копий из каталога restore (инкрементные файлы резервных копий все равно будут доступны в родительском каталоге). Любые оставшиеся инкрементные каталоги в текущем каталоге будут использоваться при создании финального набора данных.

Когда каталог будет готов, вызовите сценарий prepare-mysql.sh. Убедитесь, что вы находитесь в каталоге restore, где хранятся каталоги резервных копий:

sudo -u backup prepare-mysql.sh
Backup looks to be fully prepared.  Please check the "prepare-progress.log" file
to verify before continuing.
If everything looks correct, you can apply the restored files.
First, stop MySQL and move or remove the contents of the MySQL data directory:
sudo systemctl stop mysql
sudo mv /var/lib/mysql/ /tmp/
Then, recreate the data directory and  copy the backup files:
sudo mkdir /var/lib/mysql
sudo xtrabackup --copy-back --target-dir=/backups/mysql/Thu/restore/full-04-20-2017_14-55-17
Afterward the files are copied, adjust the permissions and restart the service:
sudo chown -R mysql:mysql /var/lib/mysql
sudo find /var/lib/mysql -type d -exec chmod 750 {} \;
sudo systemctl start mysql

Вышеприведенный вывод указывает, что сценарий полностью подготовил резервную копию, теперь она представляет собой согласованный набор данных. согласно выводу, нужно проверить файл prepare-progress.log, чтобы убедиться, что во время процесса не возникло ошибок.

Сценарий не будет копировать файлы в каталог данных MySQL, чтобы вы могли проверить данные.

Восстановление резервных копий в каталоге данных MySQL

Если итоговый набор данных вас устраивает, вы можете следовать инструкциям, изложенным в файле prepare-mysql.sh.

Во-первых, прекратите работу процесса MySQL:

sudo systemctl stop mysql

Поскольку данные резервного копирования могут конфликтовать с текущим содержимым каталога данных MySQL, нужно удалить или переместить каталог /var/lib/mysql. Если у вас есть место в файловой системе, лучше переместить текущее содержимое в каталог /tmp или в другое место:

sudo mv /var/lib/mysql/ /tmp

Восстановите каталог /var/lib/mysql.

sudo mkdir /var/lib/mysql

Теперь можно скопировать полную резервную копию в каталог данных MySQL с помощью утилиты xtrabackup. Укажите путь к готовой полной резервной копии в следующей команде:

sudo xtrabackup —copy-back —target-dir=/backups/mysql/Thu/restore/full-04-20-2017_14-55-17

Лог копируемых файлов будет отображаться на протяжении всего процесса. После того как файлы будут перемещены, вам нужно снова установить права собственности и доступа, чтобы пользователь и группа MySQL могли получить доступ к восстановленной структуре:

sudo chown -R mysql:mysql /var/lib/mysql
sudo find /var/lib/mysql -type d -exec chmod 750 {} \;

Теперь восстановленные файлы перемещены в каталог данных MySQL.

Снова запустите MySQL:

sudo systemctl start mysql

Убедитесь, что данные были восстановлены, просмотрев содержимое таблицы playground.equipment. При этом опять будет предложено ввести root пароль MySQL:

mysql -u root -p -e 'SELECT * FROM playground.equipment;'
+----+-------+-------+--------+
| id | type  | quant | color  |
+----+-------+-------+--------+
|  1 | slide |     2 | blue   |
|  2 | swing |    10 | yellow |
+----+-------+-------+--------+
2 rows in set (0.02 sec)

Данные успешно восстановлены.

После восстановления данных важно удалить каталог restore. Будущие инкрементные резервные копии нельзя применить к полной копии после ее подготовки, поэтому нужно удалить ее. Кроме того, резервные каталоги не должны оставаться на диске незашифрованными из соображений безопасности:

cd ~
sudo rm -rf /backups/mysql/"$(date +%a)"/restore

7: Настройка cron для ежечасного резервного копирования

Теперь вы знаете, что процесс резервного копирования и восстановления работает должным образом. После этого нужно создать cron для автоматизации резервного копирования.

Создайте небольшой скрипт в каталоге /etc/cron.hourly, чтобы автоматически запускать сценарий резервного копирования и регистрировать результаты. Процесс cron будет автоматически запускаться каждый час:

sudo nano /etc/cron.hourly/backup-mysql

Внутри файла нужно вызвать сценарий резервного копирования с помощью утилиты systemd-cat, чтобы вывод был доступен в логе. Поставьте метку backup-mysql, чтобы легко фильтровать логи:

#!/bin/bash
sudo -u backup systemd-cat --identifier=backup-mysql /usr/local/bin/backup-mysql.sh

Сохраните и закройте файл. Сделайте сценарий исполняемым:

sudo chmod +x /etc/cron.hourly/backup-mysql

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

Попробуйте протестировать скрипт cron, выполнив его вручную:

sudo /etc/cron.hourly/backup-mysql

После этого проверьте сообщения в логе:

sudo journalctl -t backup-mysql
-- Logs begin at Wed 2017-04-19 18:59:23 UTC, end at Thu 2017-04-20 18:54:49 UTC. --
Apr 20 18:35:07 myserver backup-mysql[2302]: Backup successful!
Apr 20 18:35:07 myserver backup-mysql[2302]: Backup created at /backups/mysql/Thu/incremental-04-20-2017_18-35-05.xbstream

Повторите проверку через несколько часов, чтобы убедиться, что в нем появились записи о новых резервных копиях.

Tags: , ,