如何备份你的MySQL数据库

简介

数据库通常会在存储一些有价值的信息。因此,在发生事故或硬件故障时,必须具有可靠的备份以防止数据丢失。

Percona XtraBackup备份工具提供了一种在系统运行时执行MySQL数据“热”备份的方法。他们通过在系统级别复制数据文件,然后执行崩溃恢复以实现数据集内的一致性。

在本文中,我们将创建一个备份系统,以在Ubuntu服务器上自动备份MySQL数据。我们将在脚本中使用cron和Percona工具来创建定期的安全备份,以便在出现问题时进行恢复。

准备

要完成本文,您需要一台Ubuntu 服务器,没有服务器的同学,我建议您使用腾讯云免费的开发者专属在线实验平台进行试验。

您将需要安装MySQL。您可以选择下面的方案进行安装

安装MySQL后,继续以sudo用户身份登录服务器。

安装Percona Xtrabackup工具

我们需要做的第一件事是安装Percona备份工具。该项目维护自己的存储库,我们可以将其添加到MySQL服务器以获取数据包的访问权限。

首先,转到Ubuntu的Percona发布页面,找到.deb用于安装存储库的最新软件包。由于我们使用的是代号为“Xenial Xerus”的Ubuntu 16.04,我们应该选择“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安装下载的软件包,使用apt命令安装配置Percona 存储库:

sudo dpkg -i percona*

配置新存储库后,我们将更新本地程序包索引以提取有关新的可用程序包的信息。然后,我们将从qpress存储库安装XtraBackup工具:

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

安装后,xtrabackupxbstreamqpress命令就可以使用了。接下来改怎么操作呢?

配置MySQL并添加测试数据

首先,启动MySQL root用户的MySQL会话:

mysql -u root -p

系统将提示您输入MySQL的管理密码。输入密码后,您将进入MySQL会话。

创建MySQL用户

要做的第一件事是为处理备份任务的新MySQL用户创建一个配置。我们只会为该用户提供复制数据所需的权限。

我们将新用户的昵称设置为backup。并设置一个安全复杂的密码:

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

接下来,我们需要为新backup用户授予在数据库系统上执行所有备份操作所需的权限。输入以下内容:

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中需要做的所有事情。输入以下命令退出shell:

exit

接下来,我们可以看一些系统级配置。

配置系统备份并分配权限

现在我们有一个MySQL用户来执行备份。在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:sammy
mysql:x:116:backup

新组在我们当前的会话中不可用。要重新登录我们sudo用户可用的组,请注销并重新登录,或输入:

exec su - ${USER}

系统将提示您输入sudo用户密码以继续。backup通过再次检查我们用户的组,确认您当前的会话现在可以访问该组:

id -nG
sammy sudo backup

我们的sudo用户现在该backup组中。

接下来,我们需要通过添加组执行权限/var/lib/mysql来使mysql组可以访问该目录及其子目录。否则,即使backup用户是该mysql组的成员,用户也将无法输入这些目录。

注意:如果您之前在MySQL内部检查过的datadir值不是/var/lib/mysql,请在后面的命令中替换您自己的目录。

要授予mysql组访问MySQL数据目录的权限,请输入:

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

我们的backup用户现在可以访问MySQL目录。

创建备份

既然MySQL和系统备份用户可用,我们就可以开始设置创建和保护备份所需的配置文件,加密密钥和其他资料。

使用备份参数创建MySQL配置文件

首先创建备份脚本将使用的最小MySQL配置文件。这将包含MySQL用户的MySQL凭据。

在文本编辑器中打开/etc/mysql/backup.cnf文件:

sudo nano /etc/mysql/backup.cnf

[client]部分并设置你在MySQL中定义的MySQL备份用户和密码用户:

[client]
user=backup
password=password

完成后保存并关闭文件。

将文件的所有权授予backup用户,让其他用户无法访问该文件:

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

备份用户将能够访问此文件以获取正确的凭据,但其他用户将受到限制。

创建备份根目录

接下来,为备份内容创建一个目录。我们将/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

此密钥将在备份过程中以及需要从备份还原时使用。

创建备份和还原脚本

为了使我们的备份和恢复步骤可重复,我们将编写自动备份的脚本。我们将创建以下脚本:

  • backup-mysql.sh:此脚本备份MySQL数据库,加密和压缩进程中的文件。它可以创建完整和增量备份,默认情况下,该脚本维护3天的备份。
  • extract-mysql.sh:此脚本解压缩和解密备份文件,以创建具有备份内容的目录。
  • prepare-mysql.sh:此脚本通过处理文件和应用日志来“准备”备份目录。任何增量备份都将应用于完整备份。准备脚本完成后,文件就可以移回数据目录了。

如果您不想复制和粘贴下面的内容,可以直接从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脚本

如果您没有从GitHub下载backup-mysql.sh脚本,请在/usr/local/bin目录中创建一个新文件backup-mysql.sh

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 [ "$(id --user --name)" != "$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数据目录结构。

如果未从Git下载脚本,请创建并打开目录中调用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日志将已提交的事务应用于完整备份。然后,它将增量备份应用于完整备份,使用更新的信息更新数据,再次应用已提交的事务。

一旦合并了所有备份,就会回滚未提交的事务。此时,full-备份将表示可以移动到MySQL数据目录中的一组一致数据。

为了最大限度地减少数据丢失的可能性,脚本不会将文件复制到数据目录中。这样,用户可以手动验证创建的备份内容和日志文件,并决定如何处理MySQL数据目录的当前内容。退出命令时,将显示完全还原文件所需的命令。

完成后保存并关闭文件。请输入以下内容将文件赋予可执行权限:

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

此脚本是我们在将备份文件移动到MySQL的数据目录之前运行的最终脚本。

测试MySQL备份和还原脚本

现在,我们就应该测试脚本是否能够正常执行了。

执行全量备份

首先通过backup用户调用backup-mysql.sh脚本:

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数字表示在备份过程中发生了某些操作。

执行增量备份

现在我们有了完整备份,我们可以进行额外的增量备份。增量备份记录自上次执行备份以来所做的更改。第一个增量备份基于完整备份,后续增量备份基于先前的增量备份。

应该在进行另一次备份之前向我们的数据库添加一些数据,以便我们可以确定已应用了哪些备份。

equipmentplayground数据库表中插入另一条记录。在此过程中,系统将提示您输入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

Outputbackup_type = incremental

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

备份类型列为“增量”,而不是像我们的完整备份那样从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目录。

如果我们提取日志,我们可以确认已成功提取最新备份。其他备份成功消息显示在文件的前面。

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目录中删除这些增量备份目录的最后机会(增量备份文件仍将在父目录中可用)。incremental-当前目录中的任何剩余目录都将应用于full-备份目录。

准备好后,调用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 systemctl stop mysql

重新创建一个空/var/lib/mysql目录。我们需要暂时修复权限。

sudo mv /var/lib/mysql/ /tmp

现在,我们可以使用xtrabackup工具将完整备份复制到MySQL数据目录。在以下命令中将路径替换为准备好的完整备份:

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表的内容来检查数据是否已恢复。同样,系统将提示您输入MySQL的root密码以继续:

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

下次我们需要备份目录的干净副本时,我们可以从备份文件中再次提取它们。

创建一个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

请在几个小时后再回来查看是否正在进行其他备份。

结论

在本文中,我们安装了Percona Xtrabackup工具,帮助定期创建MySQL数据的实时快照。我们配置了MySQL和系统备份用户,设置加密密钥以保护我们的备份文件,然后设置脚本以自动执行部分备份和还原过程。

备份脚本在每天开始时生成完整备份,之后每小时生成一次增量备份,随时保留三天备份。加密文件和加密密钥可以与其他备份技术结合使用,以便将数据传输到场外以便妥善保管。提取和准备脚本允许我们将当天的备份组合成一组可用于还原系统的一致数据。

自建数据库难免会遇到上面的问题,那么,我们还是建议您使用云数据库进行搭建,省去数据迁移等麻烦操作,购买数据库详见:https://cloud.tencent.com/product/cdb-overview


参考文献:《How To Configure MySQL Backups with Percona XtraBackup on Ubuntu 16.04》

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

zabbix部署(Linux上部署/监控端/被监控端)

一、监控系统的简单介绍 (1)cacti:存储数据能力强,报警性能差 (2)nagios:报警性能差,存储数据仅有简单的一段可以判断是否在合理范围内的数据长度...

3894
来自专栏开发技术

mysql5.7.18的安装与主从复制

    # tar -zxvf mysql-5.7.18-linux-glibc2.5-i686.tar.gz -C /usr/local

1193
来自专栏Laoqi's Linux运维专列

Mysql常用基础指令

一、设置更改mysql的root密码 1.1 初次使用mysql的密码为空 /usr/local/mysql/bin/mysql -uroot 但是这样极度的不...

3555
来自专栏向治洪

android值得珍藏的6个开源框架技术

1、volley  项目地址 https://github.com/smanikandan14/Volley-demo JSON,图像等的异步下载; 网络请...

2119
来自专栏Laoqi's Linux运维专列

parted分区GPT格式

2133
来自专栏ml

linux 下mysql的安装,并设置必要的密码

首先,我使用的是redhat linux ,版本号为: 1 [root@localhost init.d]# cat /proc/version 2 Linux...

51310
来自专栏Java后端生活

Linux(十八)RPM

2237
来自专栏程序员同行者

开启mysql慢查询

1252
来自专栏程序员互动联盟

六款值得推荐的android(安卓)开源框架简介

1、volley 项目地址 https://github.com/smanikandan14/Volley-demo (1) JSON,图像等的异步下载...

37410
来自专栏禅林阆苑

mysql学习总结05 — 用户权限

mysql中所有用户信息保存在mysql数据库下的user表中。在安装mysql时,如果不创建匿名用户,那么默认用户只有root超级用户。mysql使用host...

1372

扫码关注云+社区

领取腾讯云代金券