CentOS 7 下 MySQL 5.7 配置 Percona Xtrabackup

CentOS 7 下 MySQL 5.7 配置 Percona Xtrabackup 2017-05-10 | 标签: 
centos
mysql
xtrabackup
yum   https://qizhanming.com/  

前言

CentOS 7 下 MySQL 5.7 配置 Percona Xtrabackup ,记录一下大致的安装和配置过程。

Percona XtraBackup 的备份工具支持热备份(即不必停止 MySQL 服务而进行备份)。热备份方式主要是通过文件系统级别的文件拷贝,当需要执行崩溃恢复时,可以实现数据集内的一致性。

参考 How To Configure MySQL Backups with Percona XtraBackup on Ubuntu 16.04

参考文档使用的操作系统为 Ubuntu 16.04,本例将操作系统改为 CentOS 7,命令基本一致,主要示例一下数据库的全备份,增量备份以及数据恢复。

环境说明

CentOS 7(Minimal Install)

$ cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core) 

MySQL 5.7

$ mysql --version mysql Ver 14.14 Distrib 5.7.18, for Linux (x86_64) using EditLine wrapper 

本系统初始有两个用户
超级管理员: root
管理组用户: admin,本例中 ${USER} 就是这个用户

安装 Percona Xtrabackup 工具

参考 Installing Percona XtraBackup on Red Hat Enterprise Linux and CentOS

安装 yum 源

$ sudo yum install http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm 

查询一下安装包

$ sudo yum list | grep xtrabackup percona-xtrabackup.x86_64 2.3.8-1.el7 percona-release-x86_64 percona-xtrabackup-22.x86_64 2.2.13-1.el7 percona-release-x86_64 percona-xtrabackup-22-debuginfo.x86_64 2.2.13-1.el7 percona-release-x86_64 percona-xtrabackup-24.x86_64 2.4.7-1.el7 percona-release-x86_64 percona-xtrabackup-24-debuginfo.x86_64 2.4.7-1.el7 percona-release-x86_64 percona-xtrabackup-debuginfo.x86_64 2.3.8-1.el7 percona-release-x86_64 percona-xtrabackup-test.x86_64 2.3.8-1.el7 percona-release-x86_64 percona-xtrabackup-test-22.x86_64 2.2.13-1.el7 percona-release-x86_64 percona-xtrabackup-test-24.x86_64 2.4.7-1.el7 percona-release-x86_64 

安装 Xtrabackup 和 qpress 压缩工具。

$ sudo yum update $ sudo yum install percona-xtrabackup-24 qpress 

安装之后,innobackupexxtrabackupxbstream, 和 qpress 命令将可以使用,本例的脚本会使用这些命令进行数据的备份和恢复。

配置一个 MySQL 备份用户并且添加测试数据

首先使用 MySQL 的 root 用户登录。

$ mysql -u root -p 

创建一个 MySQL 用户并且授权

在 MySQL 中创建一个用户名为 backup 的用户,并且分配备份的相关权限给它。

mysql> CREATE USER ‘backup‘@‘localhost‘ IDENTIFIED BY ‘password‘; 

授予备份的相关权限

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

创建测试数据,创建一个 playground 的数据库,创建一个 equipment 的表,并且添加一条记录到这个表里。

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

此后我们将用这个数据库查看测试备份和恢复的效果。

mysql> SELECT * FROM playground.equipment; +----+-------+-------+-------+ | id | type | quant | color | +----+-------+-------+-------+ | 1 | slide | 2 | blue | +----+-------+-------+-------+ 1 row in set (0.00 sec) 

在我们退出 MySQL 会话前,我们先检查一下 datadir 变量。因为我们还要创建一个操作系统的 backup 用户,而且这个需要有权限访问这个目录。

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

记住这个目录,现在可以退出 MySQL 了。

mysql> exit Bye 

配置操作系统的备份用户并授权

创建 backup 用户,不需要登录系统,没有 home 目录

$ sudo useradd -M -s /sbin/nologin backup 

确认一下 backup 用户和组

$ grep backup /etc/passwd /etc/group /etc/passwd:backup:x:1001:1001::/home/backup:/sbin/nologin /etc/group:backup:x:1001: 

MySQL 的数据目录 /var/lib/mysql 的所有者和所有组是 mysql

  1. 我们需要将 backup 加入到 mysql 组里,这样 backup 就可以访问 mysql 组的目录和文件。
  2. 我们需要将 sudo 加入到 backup 组里,这样我们就可以访问 backup 用户和组权限的目录和文件。

命令执行如下

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

此时我们再检查一下 backup 的组

$ grep backup /etc/group mysql:x:27:backup backup:x:1001:admin 

新加入的组不会立即生效,需要执行如下命令

$ exec su - ${USER} 

执行之后,可以使用如下命令确认

$ id -nG admin wheel backup 

注意: admin 是 admin 的组,wheel 是 CentOS 默认的 sudo 组,backup 是新增的 mysql 备份的组。

创建备份相关的资源

现在我们已经有了 Mysql 用户 backup, 系统用户 backup,我们需要创建配置文件,密钥文件和其他脚本,这样我们就可以创建并保护备份的安全。

创建 MySQL 备份的配置文件

我们将 MySQL 备份用户 backup 的用户名和密码放到配置中。

$ sudo mkdir /etc/mysql $ sudo vi /etc/mysql/backup.cnf 

加入如下内容:

[client] user=backup password=password 

保存并退出 :wq,这样 MySQL 的配置文件就创建完毕,以后备份用户就会使用这个文件的配置登录 MySQL ,注意 password=password 这个密码是 MySQL 里面的用户 backup 的密码。

创建备份的根目录

本例使用 /backups/mysql 为备份文件的根目录,使用如下命令创建:

$ sudo mkdir -p /backups/mysql 

对这个目录的所有者和所有组进行分配, 所有者为 backup,所有组为 mysql

$ sudo chown backup:mysql /backups/mysql

CentOS 7 默认启用了 SELinux,这也需要进行授权,可以先查看一下

$ ls -lh -Zd /backups/mysql/ drwxr-x--x. backup mysql unconfined_u:object_r:var_lib_t:s0 /backups/mysql/ 

授权命令如下: 只更改类型即可

$ sudo chcon -R -u system_u -t mysqld_db_t /backups/mysql/ 

查看一下

$ ls -lh -Zd /backups/mysql/ drwxr-x--x. backup mysql system_u:object_r:mysqld_db_t:s0 /backups/mysql/ 

此时,SELinux 授权完成。

这样 backup 用户就可以进入并操作这个目录了

创建密钥保护备份文件安全

因为数据库文件是非常重要的文件,所以安全非常重要。 innobackupex 工具提供了加密和解密的功能。为此,我们只需要提供一个密钥即可。

我们使用 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 

创建备份和恢复的脚本

目前安全方面的准备已经完成,我们需要创建 3 个脚本,来执行备份(加密备份),释放(解密)和恢复准备的工作。

  • backup-mysql.sh: 这个脚本完成备份数据库,对备份的文件进行加密和压缩,他会根据日期创建全量和增量的备份,默认保存 3 天的备份。
  • extract-mysql.sh: 这个脚本会解压并解密备份文件,并将文件放到指定的文件夹中。
  • prepare-mysql.sh: 这个脚本为恢复做最后的准备,将增量文件合并到全备份中。并且记录执行的日志,如果这个脚本执行完,那么剩下的就是将恢复的数据库替换即可。

创建 backup-mysql.sh 脚本

$ sudo vi /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 innobackupex arguments #declare -ga innobackupex_args=( innobackupex_args=( "--defaults-file=${defaults_file}" "--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" "--incremental" ) 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") innobackupex_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 innobackupex "${innobackupex_args[@]}" "${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 

这个脚本完成了如下功能:

  • 每天第一次运行时创建一个加密的压缩的全备份
  • 第二次执行时,会创建加密的压缩的增量备份
  • 维护全备份的历史默认保留 3 天的全备份和增量备份,如需修改天数,请自行修改本脚本。

当这个脚本执行,一个日期的文件夹会被创建,如果是第一次备份,文件名以 full- 开头,表示全备份,从第二次开始,文件名以 incremental- 开头,表示增量备份,文件名后面代表备份时的系统时间。

脚本执行后,会生成一个文件名为 backup-progress.log 的日志文件,如有问题,可以查看。还有一个 xtrabackup_checkpoints 文件,用于存储备份时的元数据,这个文件不能删除,因为下一次创建增量备份时需要用到这里的参数。

创建完成后,保存这个文件,并更改这个脚本为可执行

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

创建 extract-mysql.sh 脚本

$ sudo vi /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}" innobackupex_args=( "--parallel=${processors}" "--decrypt=AES256" "--encrypt-key-file=${encryption_key_file}" "--decompress" ) innobackupex "${innobackupex_args[@]}" "${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 != 2 * $# )); 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 文件夹下,包含当天的全备份文件和增量备份的文件。您可以自己分析,恢复到哪个时点。

创建完成后,保存这个文件,并更改这个脚本为可执行

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

创建 prepare-mysql.sh 脚本

最后我们创建 prepare-mysql.sh,将确认后的增量备份合并到全量备份中,这样就生成了那个时点的数据库快照。

$ sudo vi /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}" innobackupex --redo-only --apply-log "${full_backup_dir}" for increment in "${incremental_dirs[@]}"; do printf "Applying incremental backup %s to %s\n" "${increment}" "${full_backup_dir}" innobackupex --redo-only --apply-log --incremental-dir="${increment}" "${full_backup_dir}" done printf "Applying final logs to full backup %s\n" "${full_backup_dir}" innobackupex --apply-log "${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} == 2 * (${#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 innobackupex --copy-back ${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 的日志应用提交的事务到全量备份,之后再将增量备份的事务提交到全量备份中。

如果所有的备份都被结合,那么未被提交的事务将会回滚,这时,这个 full- 开头的全量备份文件夹,里面的数据,就是当时 MySQL 的数据文件。

创建完成后,保存这个文件,并更改这个脚本为可执行

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

测试这个 MySQL 的备份和恢复脚本

创建一个全备份

使用 backup 用户执行 backup-mysql.sh

$ sudo -u backup /usr/local/bin/backup-mysql.sh Backup successful! Backup created at /backups/mysql/Wed/full-05-10-2017_17-16-44.xbstream 

如果一切顺利,输出会看到 Backup successful!,这样创建了一个当天的文件夹(本例为 Wed),并且创建了一个以 full- 开头的全量备份。

让我们进入这个目录看一下

$ cd /backups/mysql/"$(date +%a)" $ ls backup-progress.log full-05-10-2017_17-16-44.xbstream xtrabackup_checkpoints 

如上 backup-progress.log,为日志文件,我们看一下他的内容

$ tail backup-progress.log 170510 17:16:46 All tables unlocked 170510 17:16:46 [00] Compressing, encrypting and streaming ib_buffer_pool to <STDOUT> 170510 17:16:46 [00] ...done 170510 17:16:46 Backup created in directory ‘/backups/mysql/Wed/‘ 170510 17:16:46 [00] Compressing, encrypting and streaming backup-my.cnf 170510 17:16:46 [00] ...done 170510 17:16:46 [00] Compressing, encrypting and streaming xtrabackup_info 170510 17:16:46 [00] ...done xtrabackup: Transaction log of lsn (2541849) to (2541858) was copied. 170510 17:16:46 completed OK! 

看到 completed OK!,表示备份没有问题。

在看一下 xtrabackup_checkpoints 的内容

$ cat xtrabackup_checkpoints backup_type = full-backuped from_lsn = 0 to_lsn = 2541849 last_lsn = 2541858 compact = 0 recover_binlog_info = 0 

这个例子表示,全备份是将日志序列号 log sequence number (LSN) 从起始点(from_lsn) 0 到终止点(to_lsn) 2541849 的备份。 last_lsn 表示当执行备份操作到的日志序列号。

创建一个增量备份

全备份创建之后,下一次创建的是增量备份,它依赖这个全备份,再一次创建增量备份时依赖的就是上次的增量备份了,这是一种链式依赖。

本例添加一些数据到数据库,这样更好感受效果。

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

再次执行 backup-mysql.sh,就会创建增量备份。

$ sudo -u backup /usr/local/bin/backup-mysql.sh 

我们查看一下

$ cd /backups/mysql/"$(date +%a)" $ ls backup-progress.log full-05-10-2017_17-16-44.xbstream incremental-05-10-2017_18-39-39.xbstream xtrabackup_checkpoints 

此时查看一下 xtrabackup_checkpoints

$ cat xtrabackup_checkpoints backup_type = incremental from_lsn = 2541849 to_lsn = 2542208 last_lsn = 2542217 compact = 0 recover_binlog_info = 0 

此时 from_lsn 已经是上次(本例为第一次备份)的 to_lsn 了,from_lsn 是 0 的时候,表示是全备份,不为 0 就是增量备份了。

提取备份

接下来,我们要提取备份文件到本分文件夹。

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

看到 Extraction complete! 表示提取完毕。
这个脚本会生成一个 restore 目录 和 extract-progress.log 日志文件。

查看一下 extract-progress.log

$ tail extract-progress.log 170510 18:47:02 [01] decrypting and decompressing ./xtrabackup_logfile.qp.xbcrypt 170510 18:47:02 [01] decrypting ./xtrabackup_checkpoints.xbcrypt 170510 18:47:02 [01] decrypting and decompressing ./ib_buffer_pool.qp.xbcrypt 170510 18:47:02 [01] decrypting and decompressing ./backup-my.cnf.qp.xbcrypt 170510 18:47:02 [01] decrypting and decompressing ./xtrabackup_info.qp.xbcrypt 170510 18:47:02 completed OK! Finished work on incremental-05-10-2017_18-39-39.xbstream 

我们进入 restore 目录,备份文件已经准备就绪。

$ cd restore
$ ls -F
full-05-10-2017_17-16-44/  incremental-05-10-2017_18-39-39/

这是备份文件,但是还不是 MySQL 的数据文件。为达到最后的目的,我们开始准备文件。

准备文件

接下来,我们将合并这些文件。

  • 我们必须在 restore 文件夹下执行这个脚本
  • 这个文件夹下包含 full- 和 incremental- 的备份文件夹,如果我们不想恢复某些增量备份,请删除这些 incremental- 文件夹。

恢复命令如下(注意 要在 restore 目录下执行这个命令)

$ sudo -u backup /usr/local/bin/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 innobackupex --copy-back /backups/mysql/Wed/restore/full-05-10-2017_17-16-44 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 

这表示准备完成了,脚本会输出一些接下来恢复数据库的步骤

还原备份数据到 MySQL 数据目录

首先,停止 MySQL 服务

$ sudo systemctl stop mysqld 

因为备份目录与 MySQL 的数据目录可能有冲突,我们需要删除或剪切 /var/lib/mysql 目录

$ sudo mv /var/lib/mysql/ /tmp 

重新创建 /var/lib/mysql 目录,之后赋予正确的权限

$ sudo mkdir /var/lib/mysql 

现在,我们要使用 innobackupex 将备份文件拷贝到 MySQL 的数据目录

$ sudo innobackupex --copy-back /backups/mysql/Wed/restore/full-05-10-2017_17-16-44/  170510 19:04:22 innobackupex: Starting the copy-back operation IMPORTANT: Please check that the copy-back run completes successfully. At the end of a successful copy-back run innobackupex prints "completed OK!". innobackupex version 2.4.7 based on MySQL server 5.7.13 Linux (x86_64) (revision id: 6f7a799) ...... ...... 170510 19:04:33 completed OK! 

执行之后,completed OK! 说明拷贝完成,一旦文件已经就位,我们需要将修复所有者和权限,这样 MySQL 的用户和组就可以访问了。

$ sudo chown -R mysql:mysql /var/lib/mysql 

因为 CentOS 7 默认启用了 SELinux,这也需要进行授权,可以先查看一下

$ ls -lh -Zd /var/lib/mysql drwxr-x--x. mysql mysql unconfined_u:object_r:var_lib_t:s0 /var/lib/mysql 

授权命令如下: 更改类型和用户的属性

$ sudo chcon -R -t mysqld_db_t /var/lib/mysql $ sudo chcon -u system_u /var/lib/mysql 

查看一下

$ ls -lh -Zd /var/lib/mysql drwxr-x--x. mysql mysql system_u:object_r:mysqld_db_t:s0 /var/lib/mysql 

此时,SELinux 的权限已经恢复完全。

启动 MySQL 服务,完成数据恢复。

$ sudo systemctl start mysqld 

如果数据库启动顺利,接下来,我们查询一下数据库,验证一下数据是否恢复

$ sudo mysql -u root -p -e ‘SELECT * FROM playground.equipment;‘ Enter password: +----+-------+-------+--------+ | id | type | quant | color | +----+-------+-------+--------+ | 1 | slide | 2 | blue | | 2 | swing | 10 | yellow | +----+-------+-------+--------+ 

由此可以看到,数据顺利恢复了。

数据恢复完成之后,还要注意一个非常重要的事情,我们需要删除 restore 目录,因为新的增量备份,不能使用本次的结果文件,而且没有加密的备份文件,保存在磁盘也不安全。

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

下一次恢复,我们需要重新执行 extract-mysql.sh 脚本,生成 restore 目录,并执行 prepare-mysql.sh 准备数据。

创建 Cron 作业每小时增量备份

我们手工执行的 backup-mysql.sh 可以创建作业,定时(每小时)执行。

$ sudo vi /etc/cron.hourly/backup-mysql 

输入如下内容

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

保存并关闭 :wq,让这个脚本可以执行

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

这个脚本将每小时执行一次,并且自动清除 3 天以前的备份。

我们可以手动测试一下 cron 脚本

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

执行完之后,我们可以使用 journal 命令查看一下日志

$ sudo journalctl -t backup-mysql -- Logs begin at Wed 2017-05-10 18:28:55 CST, end at Wed 2017-05-10 19:27:58 CST. -- May 10 19:27:13 bogon backup-mysql[6704]: Backup successful! May 10 19:27:13 bogon backup-mysql[6704]: Backup created at /backups/mysql/Wed/incremental-05-10-2017_19-27-11.xbstream