基于Xtrabackup的mysql数据库备份与还原实践

在生产环境中,除了保证项目的基本业务功能外,还有一个很重要的就是数据了。想想如果在项目上碰到以下几个场景:

  • 客户:我昨天录的xxx单子怎么不见了。。?
  • 相关技术:xxx表的数据怎么不见了。。?
  • 相关技术:服务器怎么崩了。。?

所以,如何提高系统的高可用性和灾难恢复性,在数据崩溃时,以最小代价重新恢复数据就非常重要了?

关于备份

备份原因
在实际应用中,可能会因为各种意外情况导致数据异常:

硬件故障
软件故障
自然灾害
黑客攻击
误操作 (占比最大)
为了在数据丢失后能尽快的补救(恢复数据),提高系统的高可用性和灾难恢复性,数据崩溃时,以最小代价重新恢复数据,就需要我们提前对数据进行备份,而针对不同的应用场景备份策略和方式都不同,主要可以考虑这几点:

能够容忍丢失多少数据
恢复数据需要多长时间
需要恢复哪一些数据

备份分类

物理备份
指对数据库操作系统的物理文件(数据文件、日志文件)等的备份;通过tar,cp等命令直接打包复制数据库的数据文件达到备份的效果。

冷备份:必须在数据库关闭的状态下进行备份,能够更好的保证数据库的完整性;
热备份:能够在数据库处于正常运行的情况下备份,能够更高的保证服务的可用性;

逻辑备份

指对数据库的逻辑组件(数据库、表、数据对象)进行备份;通过特定工具从数据库中导出数据并另存备份(逻辑备份会丢失数据精度)。

全量备份:周期性的把所有数据从一个地方拷贝到另一个地方。
增量备份:根据某个更新点(一般为更新时间戳)更新部分数据
差异备份:备份自上一次完全备份以来变化的数据

备份数据

说了这么多的备份,我们还应该清楚,我们到底备份的是什么

  • 数据
  • 二进制日志、InnoDB事务日志
  • 代码(存储过程、存储函数、触发器、事件调度器)
  • 服务器配置文件

备份工具

  • mysqldump : 逻辑备份工具, 适用于所有的存储引擎, 支持温备、完全备份、部分备份、对于InnoDB存储引擎支持热备 ;
  • cp, tar 等归档复制工具: 物理备份工具, 适用于所有的存储引擎, 冷备、完全备份、部分备份 ;
  • lvm2 snapshot: 几乎热备, 借助文件系统管理工具进行备份 ;
  • mysqlhotcopy: 名不副实的的一个工具, 几乎冷备, 仅支持MyISAM存储引擎 ;
  • xtrabackup: 一款非常强大的InnoDB/XtraDB热备工具, 支持完全备份、增量备份, 由percona提供。

备份策略

针对不同的应用场景有不同的备份策略,备份策略主要分为以下几种:

  • 直接cp,tar复制数据库文件: 适用于数据量较小的时候, 直接复制数据库文件
  • mysqldump+复制BIN LOGS: 适用于数据量一般大小, 先使用mysqldump对数据库进行完全备份, 然后定期备份BINARY LOG达到增量备份的效果。其最大的缺陷是备份和恢复速度较慢,如果数据库大于50G,mysqldump备份就不太适合。
  • lvm2快照+复制BIN LOGS: 适用于数据量一般大小, 而又不过分影响业务运行的情况, 使用lvm2的快照对数据文件进行备份, 而后定期备份BINARY LOG达到增量备份的效果
  • xtrabackup: 适用于数据量很大, 而又不过分影响业务运行的情况,使用xtrabackup进行完全备份后, 定期使用xtrabackup进行增量备份或差异备份

接下来主要介绍一下采用xtrabackup工具来实现数据备份。

关于xtrabackup

Xtrabackup是由percona开源的免费数据库热备份软件,它能对InnoDB数据库和XtraDB存储引擎的数据库非阻塞地备份(对于MyISAM的备份同样需要加表锁),Xtrabackup安装完成后有4个可执行文件,其中2个比较重要的备份工具是innobackupex、xtrabackup。xtrabackup 是专门用来备份InnoDB表的,和mysql server没有交互;
innobackupex 是一个封装xtrabackup的Perl脚本,支持同时备份innodb和myisam,但在对myisam备份时需要加一个全局的读锁。
xbcrypt 加密解密备份工具
xbstream 流传打包传输工具,类似tar

Xtrabackup优点

  • 备份速度快,物理备份可靠
  • 备份过程不会打断正在执行的事务(无需锁表)
  • 能够基于压缩等功能节约磁盘空间和流量
  • 自动备份校验
  • 还原速度快
  • 可以流传将备份传输到另外一台机器上
  • 在不增加服务器负载的情况备份数据

Xtrabackup备份原理
备份开始时首先会开启一个后台检测进程,实时检测mysq redo的变化,一旦发现有新的日志写入,立刻将日志记入后台日志文件xtrabackup_log中,之后复制innodb的数据文件一系统表空间文件ibdatax,复制结束后,将执行flush tables with readlock,然后复制.frm MYI MYD等文件,最后执行unlock tables,最终停止xtrabackup_log

备份演练

环境准备

Xtrabackup安装

版本:percona-xtrabackup-24-2.4.13-1.el7.x86_64.rpm
安装依赖:

yum install bison libtool ncurses5-devel -y
yum -y install perl perl-devel perl-Time-HiRes perl-DBD-MySQL
yum -y install perl-Digest-MD5
rpm -ivh libev-4.15-3.el7.x86_64.rpm

安装XtraBackup:
rpm -ivh percona-xtrabackup-24-2.4.13-1.el7.x86_64.rpm

验证是否成功:
innobackupex --version


创建测试数据

mysql> create database test;
Query OK, 1 row affected (0.00 sec)

mysql> use test;
Database changed
mysql> create table T1 (name varchar(10) not null,sex varchar(10) not null);
Query OK, 0 rows affected (0.08 sec)

mysql> insert into T1 values(‘zhan’,‘man’);
Query OK, 1 row affected (0.03 sec)

mysql> insert into T1 values(‘sun’,‘woman’);
Query OK, 1 row affected (0.00 sec)

全量备份

sudo innobackupex --defaults-file=/etc/my.cnf --socket=/var/lib/mysql/mysql.sock --user=root --password= --backup /data/back_data

innobackupex 参数选项说明

–defaults-file=[MY.CNF] //指定配置文件:只能从给定的文件中读取默认选项。 且必须作为命令行上的第一个选项;必须是一个真实的文件,它不能是一个符号链接。

–databases=# //指定备份的数据库和表,格式为:–database=“db1[.tb1] db2[.tb2]” 多个库之间以空格隔开,如果此选项不被指定,将会备份所有的数据库。

–include=REGEXP //用正则表达式的方式指定要备份的数据库和表,格式为 --include=‘^mydb[.]mytb’ ,对每个库中的每个表逐一匹配,因此会创建所有的库,不过是空的目录。–include 传递给 xtrabackup --tables。

–tables-file=FILE //此选项的参数需要是一个文件名,此文件中每行包含一个要备份的表的完整名称,格式为databasename.tablename。该选项传递给
xtrabackup --tables-file,与–tables选项不同,只有要备份的表的库才会被创建。

注意:部分备份(–include、–tables-file、–database)需要开启 innodb_file_per_table

–compact //创建紧凑型备份,忽略所有辅助索引页,只备份data page;通过–apply-log中重建索引–rebuild-indexs。

–compress //此选项指示xtrabackup压缩备份的InnoDB数据文件,会生成 *.qp 文件。

–decompress //解压缩qp文件,为了解压缩,必须安装 qpress 工具。 Percona XtraBackup不会自动删除压缩文件,为了清理备份目录,用户应手动删除 * .qp文件:find /data/backup -name
“*.qp” | xargs rm。

–no-timestamp //指定了这个选项备份将会直接存储在 BACKUP-DIR 目录,不再创建时间戳文件夹。

–apply-log //应用 BACKUP-DIR 中的 xtrabackup_logfile 事务日志文件。一般情况下,在备份完成后,数据尚且不能用于恢复操作,因为备份的数据中可能会包含尚未提交的事务或已经提交但尚未同步至数据文件中的事务。因此,此时数据文件仍处于不一致状态。“准备”的主要作用正是通过回滚未提交的事务及同步已经提交的事务至数据文件使得数据文件处于一致性状态。

–use-memory=# //此选项接受一个字符参数(1M/1MB,1G/1GB,默认100M),仅与–apply-log一起使用,该选项指定prepare时用于崩溃恢复(crash-recovery)的内存。

–copy-back //拷贝先前备份所有文件到它们的原始路径。但原路径下不能有任何文件或目录,除非指定 --force-non-empty-directories 选项。

–force-non-empty-directories //恢复时指定此选项,可使 --copy-back 和 --move-back 复制文件到非空目录,即原data目录下可以有其他文件,但是不能有与恢复文件中同名的文件,否则恢复失败。

–rsync //此选项可优化本地文件(非InnoDB)的传输。rsync工具一次性拷贝所有非InnoDB文件,而不是为每个文件单独创建cp,在备份恢复很多数据库和表时非常高效。此选项不能和
–stream 一起使用。

–incremental //这个选项告诉 xtrabackup 创建一个增量备份,而不是完全备份。它传递到 xtrabackup 子进程。当指定这个选项,可以设置 --incremental-lsn 或
–incremental-basedir。如果这2个选项都没有被指定,–incremental-basedir 传递给 xtrabackup 默认值,默认值为:基础备份目录的第一个时间戳备份目录。

–incremental-basedir=DIRECTORY //该选项接受一个字符串参数,该参数指定作为增量备份的基本数据集的完整备份目录。它与 --incremental 一起使用。

–incremental-dir=DIRECTORY //该选项接受一个字符串参数,该参数指定了增量备份将与完整备份相结合的目录,以便进行新的完整备份。它与 --incremental
选项一起使用。

–redo-only //在“准备基本完整备份” 和 “合并所有的增量备份(除了最后一个增备)”时使用此选项。它直接传递给xtrabackup的 xtrabackup
–apply-log-only 选项,使xtrabackup跳过"undo"阶段,只做"redo"操作。如果后面还有增量备份应用到这个全备,这是必要的。有关详细信息,请参阅xtrabackup文档。

–parallel=NUMBER-OF-THREADS //此选项接受一个整数参数,指定xtrabackup子进程应用于同时备份文件的线程数。请注意,此选项仅适用于文件级别,也就是说,如果您有多个.ibd文件,则它们将被并行复制;
如果您的表一起存储在一个表空间文件中,它将不起作用。

数据保持一致性

使用此参数使用相关数据性文件保持一致性状态
sudo innobackupex --user=root --apply-log /data/back_data/2019-03-22_14-21-54/

修改表

这里通过删除刚刚新建的T1表来做备份验证
mysql> show tables;
±---------------+
| Tables_in_test |
±---------------+
| T1 |
±---------------+
1 row in set (0.00 sec)

mysql> drop table T1;
Query OK, 0 rows affected (0.04 sec)

数据恢复

接下来准备恢复删除的数据

1、停掉mysql服务
sudo service mysqld stop

2、替换数据文件并授权
sudo mv mysql mysqlback

3、恢复
sudo innobackupex --user=root --copy-back /data/back_data/2019-03-22_14-21-54/

4、授权
sudo chmod -R 777 mysql

5、重启mysq
sudo service mysqld start
然而。。启动失败了

但这些信息并不能提供服务启动失败的真正原因。
这时候,不妨打开MySQL的告警日志,毕竟,只要MySQL服务启动,告警日志都会有输出信息的
sudo tail -f /var/log/mysqld.log -n 200

error 13就是权限错误,首先检查数据目录和日志目录的权限和所属用户,权限和所属用户都没问题,那应该是SELINUX的权限限制了。
先查看当前配置信息.

就表明SELinux是启用状态,只需要关闭即可。
解决方案
执行:setenforce 0

关闭SELinux方法
1、临时关闭(不用重启机器):
setenforce 0 #设置SELinux 成为permissive模式
setenforce 1 #设置SELinux 成为enforcing模式
2、修改配置文件(需要重启机器):
修改/etc/selinux/config 文件 将SELINUX=enforcing改为SELINUX=disabled
重启机器即可

6、验证
查看前面删掉的表T1是否恢复

这说明利用xtrabackup进行数据的备份和恢复操作成功了。

完整的备份脚本参考:

将脚本设置在crontab定时任务,每天凌晨0点和中午12点进行备份动作,生成的备份压缩文件如下图所示:

0 */12 * * * /data/hscs_data_backup.sh
#!/bin/bash
# 数据库启动端口
PORT='3306'
# 用户名
USER='root'
# 密码
PASSWORD='HandHand123456'
# 数据库配置文件
MYSQL_CONFIG_FILE='/etc/my.cnf'
STREAM_TYPE="tar"
HOST=`/bin/hostname`
#socket文件
SOCKET='/var/lib/mysql/mysql.sock'

# 备份路径
BASEDIR="/data/backup"
DATADIR="/data/backup/${HOST}/data/full_back"
LSNDIR="/data/backup/${HOST}/data/lsndir"

# 备份命令
BACKUP_COMMAND="innobackupex"
# 时间
TIME=`date +%Y%m%d_%H%M%S`
# 日志路径
LOG_DIR="${BASEDIR}/${HOST}/log"
# 日志文件
LOGFILE="${LOG_DIR}/${TIME}info.log"


# 状态码
RETURN_CODE=0

# 获取运行时间函数
function getTiming() {
    start=$1
    end=$2
    start_s=$(echo $start | cut -d '.' -f 1)
    start_ns=$(echo $start | cut -d '.' -f 2)
    end_s=$(echo $end | cut -d '.' -f 1)
    end_ns=$(echo $end | cut -d '.' -f 2)
    time=$(( ( 10#$end_s - 10#$start_s ) * 1000 + ( 10#$end_ns / 1000000 - 10#$start_ns / 1000000 ) ))
    echo "$time ms"
}

# 执行备份函数
function execBackup(){
    # 开始时间
    START_TIME=`date +%Y%m%d_%H%M%S`
    # 备份文件
    BACKUP_FILE=${HOST}_full_${TIME}
    # 如果LSN文件夹不存在 则创建之 
    if [[ ! -d "${LSNDIR}" ]]; then
    	mkdir -p ${LSNDIR}
    	sudo chmod -R 777 ${LSNDIR}
    fi
    # 如果日志文件不存在 则创建之
    if [[ ! -d ${LOG_DIR} ]]; then
        mkdir -p ${LOG_DIR}
        sudo chmod -R 777 ${LOG_DIR}
    fi
    # 如果数据文件夹不存在则创建之
    if [[ ! -d ${DATADIR} ]]; then
        mkdir -p ${DATADIR}
        sudo chmod -R 777 ${DATADIR}
    fi
    # 判断mysql服务是否启动
    IS_MYSQL_START=`sudo netstat -anultp |grep ${PORT} |grep -v grep | grep LISTEN | wc -l`
    if [[ ${IS_MYSQL_START} -ne 1 ]]; then
    	echo "${STARTTIME}: [ERROR]: the mysql(port:${PORT}) server is not running, please start it." | tee -a ${LOGFILE}
        RETURN_CODE=1
        return
    fi
    # 判断是否安装备份工具
    which ${BACKUP_COMMAND}
    if [[ $? -ne 0 ]]; then
        echo "${STARTTIME}: [ERROR]: can not find the back command: ${BACKUP_COMMAND}, please install it first. " | tee -a ${LOGFILE}
        RETURN_CODE=1
        return
    fi

    # 备份开始时间
    TIMESTART2=`date +%Y%m%d_%H%M%S`
    TIME_BEGIN=$(date +%s.%N)
    echo "********************start backup time:${TIMESTART2}*********************" | tee -a ${LOGFILE}
    # 执行备份
    sudo ${BACKUP_COMMAND} --defaults-file=${MYSQL_CONFIG_FILE}  \
    		--socket=${SOCKET}                          \
                --user=${USER}                              \
                --password=${PASSWORD}                      \
                --extra-lsndir=${LSNDIR}                    \
                --stream=${STREAM_TYPE}                     \
                ${DATADIR} 2>> ${LOGFILE}|gzip > ${DATADIR}/${BACKUP_FILE}.tar.gz
    
    # 判断是否备份成功
    if [[ $? -ne 0 ]];then
        echo "${STARTTIME}: [ERROR]: mysql full backup error." | tee -a ${LOGFILE}
        RETURN_CODE=1
        return
    else
        echo "${STARTTIME}: [INFO]: mysql full backup successfully." |tee -a ${LOGFILE}
    fi
    
    # 备份截止时间
    STOPTIME=`date +%Y%m%d_%H%M%S`
    TIME_END=$(date +%s.%N)
    echo "********************stop backup time:${STOPTIME}*********************" | tee -a ${LOGFILE}
    RUNTIME=$(getTiming ${TIME_BEGIN} ${TIME_END})
    echo "full back use time: ${RUNTIME} " | tee -a ${LOGFILE}
}

# 执行备份函数
execBackup
# 如果状态码不为0 代表期间出错了 则程序退出
if [ $RETURN_CODE -ne 0 ]; then
    exit 1
fi

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值