MySQL备份恢复:从Xtrabackup完整备份中恢复单个表

现在大多数同学在线上采取的备份策略都是xtrabackup全备+binlog备份,那么当某天某张表意外的删除,那么如何快速从xtrabackup全备中恢复呢?从MySQL 5.6版本开始,支持可传输表空间(Transportable Tablespace),那么利用这个功能就可以实现单表的恢复,同样利用这个功能还可以把innodb表移动到另外一台服务器上。可以参考:https://yq.aliyun.com/articles/59271

下面进行从xtrabackup全备恢复单表的测试。

1.开启了参数innodb_file_per_table

2.安装工具:mysql-utilities,其中mysqlfrm可以读取表结构。

$ yum install mysql-utilities -y

查看原表中的数据:

mysql> select count(*) from sbtest.sbtest1;
+----------+
| count(*) |
+----------+
|    10000 |
+----------+
1 row in set (0.00 sec)

执行备份:

$ innobackupex --defaults-file=/etc/my.cnf --user=root --password=123456 /data/

apply-log

$ innobackupex --defaults-file=/etc/my.cnf --apply-log /data/2018-03-21_08-09-43

删除sbtest1表

mysql> drop table sbtest.sbtest1;

利用mysql-utilities工具读取表结构(不支持MariaDB哦)

$ mysqlfrm --diagnostic /data/2018-03-21_08-09-43/sbtest/sbtest1.frm

得到表结构

CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

加一个写锁,确保安全

mysql> lock tables sbtest1 write;

丢弃表空间

mysql> alter table sbtest1 discard tablespace;  
Query OK, 0 rows affected (0.00 sec)

从备份中拷贝ibd文件,并且修改权限

$ cp /data/2018-03-21_08-09-43/sbtest/sbtest1.ibd /var/lib/mysql/sbtest/
$ chown -R mysql.mysql /var/lib/mysql/sbtest/sbtest1.ibd

这里有警告,可以忽略。详情可以看:https://yq.aliyun.com/articles/59271

查询数据是否一致:

mysql> alter table sbtest1 import tablespace; 
Query OK, 0 rows affected, 1 warning (0.08 sec)

mysql> select count(*) from sbtest1;  
+----------+
| count(*) |
+----------+
|    10000 |
+----------+
1 row in set (0.00 sec)

最后解锁:

mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)

XtraBackup不停机不锁表热备mysql数据库

环境

  • mysql版本 Server version: 5.6.42-log MySQL Community Server
  • 数据库data目录 /data/mysql/
  • binlog日志目录 /data/bin_logs/
  • 备份目录 /data/backup/

完全备份脚本 (每日一次,00:10:00执行)

#!/bin/bash
base_dir=”/data/backup/`date +%F`”
[ -d ${base_dir} ] || mkdir ${base_dir}
[ -d ${base_dir}/full_`date +%F` ] && exit 0
innobackupex –defaults-file=/etc/my.cnf –user=root –password=’123456′ –no-timestamp ${base_dir}/full_`date +%F`
[ $? -eq 0 ] || echo “$(date +”%F_ %T”) 完全备份失败,请重新备份” >> /data/backup/backup.log

增量备份脚本 (每小时一次,xx:30:00执行)

#!/bin/bash
base_dir=”/data/backup/`date +%F`”
full_dir=”/data/backup/`date +%F`/full_`date +%F`”
inc_dir=”${base_dir}/inc_`date +%H`”
[ -d ${inc_dir} ] && exit 0
innobackupex –defaults-file=/etc/my.cnf –user=root –password=’123456′ –no-timestamp –incremental-basedir=${full_dir} –incremental ${inc_dir} &> /dev/null
[ $? -eq 0 ] || echo “$(date +”%F_ %T”) ${inc_dir}增量备份失败,请重新备份” >> /data/backup/backup.log

一键还原脚本

#!/bin/bash
base_dir=”/data/backup/`date +%F`”
full_dir=”${base_dir}/full_`date +%F`”
inc_dir=”${base_dir}/`ls ${base_dir} | tail -1`”
cp -a ${base_dir} /data/backup/`date +”%F-%T”`_bak
innobackupex –defaults-file=/etc/my.cnf –user=root –apply-log –redo-only ${full_dir}
innobackupex –defaults-file=/etc/my.cnf –user=root –apply-log –redo-only ${full_dir} –incremental-dir=${inc_dir}

service mysqld stop
mv /data/mysql /data/mysql_bak`date +”%F_%T”`
mkdir /data/mysql
innobackupex –defaults-file=/etc/my.cnf –user=root –copy-back ${full_dir}
chown -R mysql.mysql /data/mysql
service mysqld start

###binlog日志还原
###这里选择的是最后一个binlog日志,如果增量备份的一个小时内,有多个mysql-bin.0000xx生成,需要手动选择bin-log日志;
###还原执行13:30点后的所有sql命令
Hour=`basename ${inc_dir}|grep -o ‘[0-9]*’`
binlog=`ls /data/bin_logs/|grep [0-9]|tail -1`
mysqlbinlog –start-datetime=”`date +%F` ${Hour}:30:00″ /data/mysql/${binlog} | mysql -uroot -p ‘123456’

###还原执行13:30-14:10之间的所有sql命令
##mysqlbinlog –start-datetime=”2018-11-21 13:30:00″ –stop-datetime=”2012-03-15 14:10:00″ /data1/log/mysql/mysql-bin.000001 > /tmp/mysql_restore_030915.sql

计划任务

10 00 * * * /bin/bash /root/.scripts/full_back.sh
30 * * * * /bin/bash /root/.scripts/inc_back.sh

MySQL-Xtrabackup备份还原

前言

通常我们都是使用xtrabackup工具来备份数据库,它是一个专业的备份工具,先来简单介绍下它。

Xtrabackup

percona提供的mysql数据库备份工具,惟一开源的能够对innodb和xtradb数据库,它的增量备份不是基于二进制日志文件来还原数据的,是基于mysql数据块。

特点:

  • 备份还原过程快速、可靠
  • 备份过程不会打断正在执行的事务
  • 能够基于压缩等功能节约磁盘空间和流量
  • 自动实现备份检验
  • 开源,免费

Xtrabackup用法

备份时选项

xtrabackup –backup

--user:该选项表示备份账号

--password:该选项表示备份的密码

--host:该选项表示备份数据库的地址

--databases:该选项接受的参数为数据名,如果要指定多个数据库,彼此间需要以空格隔开;如:”xtra_test dba_test”,同时,在指定某数据库时,也可以只指定其中的某张表。如:”mydatabase.mytable”。该选项对innodb引擎表无效,还是会备份所有innodb表

--defaults-file:该选项指定从哪个文件读取MySQL配置,必须放在命令行第一个选项位置

--incremental:该选项表示创建一个增量备份,需要指定–incremental-basedir

--incremental-basedir:该选项指定为前一次全备份或增量备份的目录,与–incremental同时使用

--incremental-dir:该选项表示还原时增量备份的目录

--include=name:指定表名,格式:databasename.tablename

Prepare于准备选项

prepare

--apply-log:此选项作用是通过回滚未提交的事务及同步已经提交的事务至数据文件使数据文件处于一致性状态

--use-memory:该选项表示和–apply-log选项一起使用,prepare 备份的时候,xtrabackup做crash recovery分配的内存大小,单位字节。也可(1MB,1M,1G,1GB),推荐1G

--export:表示开启可导出单独的表之后再导入其他Mysql中

--redo-only:此选项在prepare base full backup,往其中merge增量备份时候使用

还原时选项

--copy-back:复制

--move-back:移动

备份生产的相关文件

1)xtrabackup_info:innobackupex工具执行时的相关信息,包括版本,备份选项,备份时长,备份LSN,BINLOG的位置

2)xtrabackup_checkpoints:备份类型(如完全或增量)、备份状态(如是否已经为prepared状态)和LSN(日志序列号)范围信息,每个InnoDB页(通常为16k大小)都会包含一个日志序列号,即LSN。LSN是整个数据库系统的系统版本号,每个页面相关的LSN能够表明此页面最近是如何发生改变的

3)xtrabackup_binlog_info:MySQL服务器当前正在使用的二进制日志文件及至备份这一刻为止二进制日志事件的位置,可利用实现基于binlog的恢复

4)backup-my.cnf:备份命令用到的配置选项信息

5)xtrabackup_logfile:备份生成的日志文件

还原注意事项

1.datadir目录必须为空。除非指定innobackupex –force-non-emptydirectorires选项指定,否则–copy-backup选项不会覆盖

2.restore还原之前,必须shutdown停止 MySQL服务,不能将一个运行中的实例restore到datadir目录中

3.修改恢复文件的权限为mysql

4.最后一次增量备份还原要回滚事务

5.二进制安装的mysql要是出现停止不了服务就用killall –9 mysqld 杀掉进程进而实现停止服务

实战

规划

1、两台主机17和37,其中17当主mysql服务器,37用来还原的主机,

2、目录,1个存放完整备份的目录,N个存放增量备份的目录

未分类

说明:

full目录: 存放完全备份

inc1目录:存放第一次的增量备份

inc2目录:存放第二次的增量备份

备份阶段

1、完全备份数据库

xtrabackup -pcentos --backup --target-dir=/backups/full/
# --backup表示备份
# --target-dir=填写备份到哪里

2、往表中增加数据

mysql -pcentos hellodb -e "insert students (name,age) values('gaodao01',20)"

未分类

3、第一次增量备份

xtrabackup –pcentos --backup --target-dir=/backups/inc1/ --incremental-basedir=/backups/full
# --incremental-basedir表示基于谁的增量备份,写上上一次的备份路径
#

未分类

4、再次修改数据表

mysql -pcentos hellodb -e "insert students (name,age) values('gaodao02',21)"

未分类

5、第二次增量备份

xtrabackup -pcentos --backup --target-dir=/backups/inc2/ --incremental-basedir=/backups/inc1/

未分类

还原阶段

说明:还原的时候我们要考虑到前几次不要回滚,最后一次还原要回滚,还原主机要安装xtrabackup工具

1、把备份的目录传送到要还原的主机上

scp -r /backups/ 192.168.43.37:/

2、停服务并清空mysql数据

systemctl stop mysqld
rm -rf /app/mysql/*

3、完全备份的预处理

xtrabackup  --prepare --apply-log-only --target-dir=/backups/full
# --prepare 表示还原
# --apply-log-only 表示不回滚

4、第一次增量备份预处理

xtrabackup --prepare --apply-log-only --target-dir=/backups/full --incremental-dir=/backups/inc1
# 同样不回滚

5、第二次增量备份预处理

xtrabackup --prepare  --target-dir=/backups/full --incremental-dir=/backups/inc2
# 这是最后一次,所以要回滚不完整的事务

6、复制处理好的数据到真正的存放数据库目录下

xtrabackup --copy-back --target-dir=/backups/full
# 它会根据你的配置文件my.cnf来读取存放位置

7、修改数据库文件权限

chown -R mysql.mysql /app/mysql/

以上还原到了备份时的状态,我们备份完二次增量后又加了条记录,还没来得急三次增量备份就宕机了,所以再次利用二进制日志文件还原到最新状态

8、通过二进制文件还原到最新状态

1)以下图中文件记录了还原到的位置

未分类

2)从原主机导出二进制文件日志

mysqlbinlog --start-position=1039 /app/logs/mysql-bin.000003 >/app/binlog.sql

3)scp传送到目标主机来还原

  • 首先在配置文件中加入禁止所有人访问选项
skip-networking
  • 启动服务
systemctl start mysqld
  • 导入二进制日志
mysql -pcentos <binlog.sql

4)进入数据库验证

未分类

5)OK 恢复完成,删除配置文件中的skip-networking并重启服务

systemctl restart mysqld

Mysql中-Xtrabackup备份和恢复应用

关于Xtrabackup(又或innobackupex)的介绍,详细参考官方文档https://www.percona.com/doc/percona-xtrabackup/2.1/index.html

Xtrabackup安装指南

文件准备

[root@wuxiang11 ~]# cd percona-xtrabackup/
[root@wuxiang11 percona-xtrabackup]# ls
libev-4.15-1.el6.rf.x86_64.rpm  percona-release-0.1-4.noarch.rpm  percona-xtrabackup-24-2.4.4-1.el7.x86_64.rpm

开始安装依赖文件

[root@wuxiang11 percona-xtrabackup]# rpm -ivh libev-4.15-1.el6.rf.x86_64.rpm 
warning: libev-4.15-1.el6.rf.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 6b8d79e6: NOKEY
Preparing...                ########################################### [100%]
   1:libev                  ########################################### [100%]

安装-01

[root@wuxiang11 percona-xtrabackup]# rpm -ivH percona-release-0.1-4.noarch.rpm
Preparing packages for installation...
percona-release-0.1-4
[root@wuxiang11 percona-xtrabackup]# yum list | grep percona

马上就安装完成

[root@wuxiang11 percona-xtrabackup]# yum install percona-xtrabackup-24

Loaded plugins: fastestmirror, security
Setting up Install Process
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package percona-xtrabackup-24.x86_64 0:2.4.11-1.el6 will be installed
--> Processing Dependency: perl(DBD::mysql) for package: percona-xtrabackup-24-2.4.11-1.el6.x86_64
--> Running transaction check
---> Package perl-DBD-MySQL.x86_64 0:4.013-3.el6 will be installed
--> Processing Dependency: perl(DBI::Const::GetInfoType) for package: perl-DBD-MySQL-4.013-3.el6.x86_64
--> Processing Dependency: perl(DBI) for package: perl-DBD-MySQL-4.013-3.el6.x86_64
--> Processing Dependency: libmysqlclient.so.16(libmysqlclient_16)(64bit) for package: perl-DBD-MySQL-4.013-3.el6.x86_64
--> Processing Dependency: libmysqlclient.so.16()(64bit) for package: perl-DBD-MySQL-4.013-3.el6.x86_64
--> Running transaction check
---> Package Percona-Server-shared-51.x86_64 0:5.1.73-rel14.12.625.rhel6 will be installed
---> Package perl-DBI.x86_64 0:1.609-4.el6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

===============================================================================================================================================================================================
 Package                                           Arch                            Version                                               Repository                                       Size
===============================================================================================================================================================================================
Installing:
 percona-xtrabackup-24                             x86_64                          2.4.11-1.el6                                          percona-release-x86_64                          8.1 M
Installing for dependencies:
 Percona-Server-shared-51                          x86_64                          5.1.73-rel14.12.625.rhel6                             percona-release-x86_64                          2.1 M
 perl-DBD-MySQL                                    x86_64                          4.013-3.el6                                           centos6.7_64                                    134 k
 perl-DBI                                          x86_64                          1.609-4.el6                                           centos6.7_64                                    705 k

Transaction Summary
===============================================================================================================================================================================================
Install       4 Package(s)

Total download size: 11 M
Installed size: 12 M
Is this ok [y/N]: y
Downloading Packages:
(1/4): Percona-Server-shared-51-5.1.73-rel14.12.625.rhel6.x86_64.rpm                                                                                                    | 2.1 MB     00:02     
(2/4): percona-xtrabackup-24-2.4.11-1.el6.x86_64.rpm                                                                                                                    | 8.1 MB     00:01     
(3/4): perl-DBD-MySQL-4.013-3.el6.x86_64.rpm                                                                                                                            | 134 kB     00:00     
(4/4): perl-DBI-1.609-4.el6.x86_64.rpm                                                                                                                                  | 705 kB     00:00     
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                                          2.5 MB/s |  11 MB     00:04     
warning: rpmts_HdrFromFdno: Header V4 DSA/SHA1 Signature, key ID cd2efd2a: NOKEY
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Percona
Importing GPG key 0xCD2EFD2A:
 Userid : Percona MySQL Development Team <[email protected]>
 Package: percona-release-0.1-4.noarch (installed)
 From   : /etc/pki/rpm-gpg/RPM-GPG-KEY-Percona
Is this ok [y/N]: y
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
Warning: RPMDB altered outside of yum.
** Found 3 pre-existing rpmdb problem(s), 'yum check' output follows:
2:postfix-2.6.6-6.el6_5.x86_64 has missing requires of libmysqlclient.so.16()(64bit)
2:postfix-2.6.6-6.el6_5.x86_64 has missing requires of libmysqlclient.so.16(libmysqlclient_16)(64bit)
2:postfix-2.6.6-6.el6_5.x86_64 has missing requires of mysql-libs
  Installing : perl-DBI-1.609-4.el6.x86_64                                                                                                                                                 1/4 
  Installing : Percona-Server-shared-51-5.1.73-rel14.12.625.rhel6.x86_64                                                                                                                   2/4 
  Installing : perl-DBD-MySQL-4.013-3.el6.x86_64                                                                                                                                           3/4 
  Installing : percona-xtrabackup-24-2.4.11-1.el6.x86_64                                                                                                                                   4/4 
  Verifying  : percona-xtrabackup-24-2.4.11-1.el6.x86_64                                                                                                                                   1/4 
  Verifying  : perl-DBD-MySQL-4.013-3.el6.x86_64                                                                                                                                           2/4 
  Verifying  : Percona-Server-shared-51-5.1.73-rel14.12.625.rhel6.x86_64                                                                                                                   3/4 
  Verifying  : perl-DBI-1.609-4.el6.x86_64                                                                                                                                                 4/4 

Installed:
  percona-xtrabackup-24.x86_64 0:2.4.11-1.el6                                                                                                                                                  

Dependency Installed:
  Percona-Server-shared-51.x86_64 0:5.1.73-rel14.12.625.rhel6                      perl-DBD-MySQL.x86_64 0:4.013-3.el6                      perl-DBI.x86_64 0:1.609-4.el6                     

Complete!

检验是否安装成功

[root@wuxiang11 percona-xtrabackup]# rpm -qa|grep xtrabackup
percona-xtrabackup-24-2.4.11-1.el6.x86_64
[root@wuxiang11 percona-xtrabackup]#

备份思路

Xtrabackup提供了全量备份和增量备份两种方式,全量就不解释了,增量是指其可以只备份指定位置后的新增数据。本文介绍的增量备份方法使用到了LSN(Log Sequence Number),可以从备份成功文件夹的xtrabackup_checkpoints文件中获取,其中to_lsn就是下次增量备份的起始位置。
结合两者,我们可以得到下图的备份思路。

未分类

解释如下:

由于全量备份和增量备份的命令参数不同,所以首先要判断是否需要全量备份。
如果是全量备份,那么便执行命令,备份成功后,记录xtrabackup_checkpoints文件中的to_lsn,以便后面进行增量备份
如果是增量备份,那么首先读取上次备份时记录下的to_lsn,如果读取失败,报错并结束。否则执行相应命令,备份成功后记录to_lsn。
编写一个简单的脚本:db-backup.sh,如下所示:

#!/bin/sh

# xtrabackup的相关配置
INNOBACKUPEX="innobackupex "
MY_CNF="/home/config/mysql/3307.backup.cnf"
MY_USER="xtrabackup"
MY_PASSWORD="xtrabackup"
MY_SOCKET="/home/socket/mysql/3307.sock"

# 远程备份机 文件名配置
REMOTE_HOST="dbbackup"
REMOTE_DIR="/home/backup/mysql/test"
LOCAL_LSN_FILE="~/.to_lsn_important"
DATE_NAME=`date +%Y-%m-%d-%H-%M-%S`
REMOTE_FILE=$DATE_NAME.tar.gz
LOCK_FILE="~/.mysql.backup.lock"
LOCAL_BACKUP_DIR="/home/backup/mysql/test/$DATE_NAME"

# 输出帮助信息
function usage()
{
    echo "Usage:"
    echo "-f db will be backuped fully with this parameter. If not , incrementally. "
}

#防止同时执行两个备份命令,发生冲突
if [ -f $LOCK_FILE ] ;then
    echo 'Mysql backup lockfile is locked!'
    exit 0
fi

full=0

while getopts "fh" arg #选项后面的冒号表示该选项需要参数
do
    case $arg in
        f)  
            full=1
            ;;
        h)  # 输出帮助信息
            usage
            exit 0
            ;;
    esac
done

echo "backup dir is $REMOTE_DIR/$REMOTE_FILE"

# backup up db to remote host
echo "start to backup db!"`date +%Y-%m-%d-%H-%M-%S`
if [ "$full"x = "1"x ] ;then
    # 全量备份
    echo '1' > $LOCK_FILE
    $INNOBACKUPEX --defaults-file=$MY_CNF --user=$MY_USER --password=$MY_PASSWORD --socket=$MY_SOCKET ./ --stream=tar | gzip | ssh $REMOTE_HOST "cat - > $REMOTE_DIR/FULL-$REMOTE_FILE"
    ssh $REMOTE_HOST "cd $REMOTE_DIR;rm -f xtrabackup_checkpoints;tar zxfi $REMOTE_DIR/FULL-$REMOTE_FILE xtrabackup_checkpoints "
    toLSN=$( ssh $REMOTE_HOST "cat $REMOTE_DIR/xtrabackup_checkpoints|grep to_lsn|awk -F= '{gsub(/ /,"",$2);print $2}'" )
    if [ $toLSN ] ;then
        echo $toLSN > $LOCAL_LSN_FILE
    else
        echo 'no lsn from remote host!please check!'
    fi
else
    # 增量备份
    if [ -f $LOCAL_LSN_FILE ] ;then
        toLSN=`cat $LOCAL_LSN_FILE`
    fi

    if [ ! $toLSN ] ;then
        echo 'last LSN is not set !please check!'
        exit 0
    fi

    echo '1' > $LOCK_FILE
    mkdir -p $LOCAL_BACKUP_DIR
    echo "last to lsn is "$toLSN
    $INNOBACKUPEX --parallel=6 --defaults-file=$MY_CNF --user=$MY_USER --password=$MY_PASSWORD --socket=$MY_SOCKET --incremental --incremental-lsn=$toLSN $LOCAL_BACKUP_DIR 2>/tmp/innobackexLog
    toLSN=$( cd $LOCAL_BACKUP_DIR/*; cat xtrabackup_checkpoints|grep to_lsn|awk -F= '{gsub(/ /,"",$2);print $2}' )
    echo "new to lsn is "$toLSN;
    if [ $toLSN ] ;then
        echo $toLSN > $LOCAL_LSN_FILE
        cd $LOCAL_BACKUP_DIR/*;tar zc .|ssh $REMOTE_HOST "cat - > $REMOTE_DIR/$REMOTE_FILE"
        echo "save file to $REMOTE_HOST @ $REMOTE_DIR/$REMOTE_FILE"
    else
        echo 'no lsn from local backup file!delete remote backup file!'$LOCAL_BACKUP_DIR/$REMOTE_FILE
    fi
    echo "remove $LOCAL_BACKUP_DIR"
    rm -rf $LOCAL_BACKUP_DIR
fi

rm -f $LOCK_FILE
echo "end to backup db!"`date +%Y-%m-%d-%H-%M-%S`

将上述脚本配置好后,放到mysql主机上,执行 sh db-backup.sh -f进行全量备份,之后将sh backup.sh添加到crontab中每小时增量备份一次就可以了。

注意–parallel=6使用是有条件的,参考文档https://www.percona.com/doc/percona-xtrabackup/2.1/innobackupex/parallel_copy_ibk.html

恢复思路

一旦线上数据库发生宕机之类的灾难性事故,备份数据就要立马发挥作用了。打开备份文件夹一看,如上面的图,每小时一个压缩文件,时间久了,茫茫多,上百个压缩文件,简直是一定的,这必须得来个脚本自动化恢复数据才成。思路很简单,见下图:

未分类

解释如下:

  1. 先解压,没啥说的。
  2. 找到全量备份的数据,因为增量备份也是以此为基准进行的。上面备份的时候,全量备份文件命名以FULL开头便是为了此处便于查找。
  3. 先恢复全量备份数据,然后按照时间顺序恢复增量备份的数据。
  4. 将数据恢复到mysql中
  5. 启动mysql,连上看看有没问题。

简单的实现脚本,我们叫它restore.sh,如下所示

#!/bin/sh
BACK_DIR="/home/backup/mysql/test"
RESTORE_DIR="/home/tmpback/test"

# xtrabackup恢复时使用的配置文件可能与数据库配置文件不同
RESTORE_MY_CNF="/home/config/mysql/3307.backup.cnf"

# 启动mysql需要的配置文件,按需设定
MY_CNF="/home/config/mysql/3307.cnf"
MY_DATA_DIR="/home/data/mysql/3307"
MY_SOCK_DIR="/home/socket/mysql/"
MY_LOG_DIR="/home/logs/mysqld/3307"

#extract all tar file
fullFileName=""
for file in $( ls $BACK_DIR | grep "tar.gz" )
do
    fileName=${file%.tar.gz}
    full=${file%%-*}
    if [ "${full}"x = "FULL"x ] ;then
        fullFileName=$fileName
    fi
    DEST_DIR="$RESTORE_DIR/$fileName"
    if [ -d $DEST_DIR ] ;then
        echo "$DEST_DIR exists!"
    else
        mkdir -p $DEST_DIR
        echo "start to extract file $file to $DEST_DIR"
        tar zxif $BACK_DIR/$file -C $RESTORE_DIR/$fileName
        echo "end to extract file "$file
    fi
done

echo "full backup dir is "$fullFileName

echo "**start to repare full backup dir"

# 恢复全量数据
echo "innobackupex --apply-log --redo-only --use-memory=4G $RESTORE_DIR/$fullFileName"
innobackupex --apply-log --redo-only --use-memory=4G "$RESTORE_DIR/$fullFileName"

echo "**end to repare full backup dir"

# 恢复增量数据
for file in $( ls $RESTORE_DIR|grep -v "FULL" )
do
    echo "**start to repare $file"
    echo "innobackupex --apply-log --redo-only --use-memory=4G $RESTORE_DIR/$fullFileName --incremental-dir=$RESTORE_DIR/$file"
    innobackupex --apply-log --redo-only --use-memory=4G "$RESTORE_DIR/$fullFileName" --incremental-dir="$RESTORE_DIR/$file"

    echo "**end to repare $file"

done

echo "**start to copy back data to mysql"
rm -rf $MY_DATA_DIR
mkdir $MY_DATA_DIR
mkdir $MY_SOCK_DIR
mkdir $MY_LOG_DIR

#将数据恢复到mysql中
echo "innobackupex --defaults-file=$RESTORE_MY_CNF --copy-back $RESTORE_DIR/$fullFileName"
innobackupex --defaults-file=$RESTORE_MY_CNF --copy-back $RESTORE_DIR/$fullFileName
echo "**end to copy back data to mysql"

chown -R mysql:mysql $MY_DATA_DIR
chown -R mysql:mysql $MY_SOCK_DIR
chown -R mysql:mysql $MY_LOG_DIR

echo "All data has been restored! Try to start mysql now"

echo "mysqld_multi --defaults-file=$MY_CNF start 1"

使用方法很简单,配置好后,直接运行sh restore.sh就可以了。

Mysql/Mariadb备份(xtrabackup)还原实战

一、概述

之前的文章说到mysql的安装与mysql的基本使用;本文是后续补充,主要说明针对mysql或mariadb的备份与还原;众所周知,数据是重中之重,因此平时对企业数据需要做备份,当数据系统崩溃,数据丢失异常时,才能依据备份文件进行恢复!

本次的环境:
CentOS7.4_x64 , mysql5.7.21, xtrabackup

mysql的安装配置可参考之前系列文章;只补充相关配置项的开启;以及xtrabackup安装使用;
用到的演示数据导入mysql数据库

[root@db ~]# mysql -uroot -predhat < testdb.sql
或
mysql> source   testdb.sql
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| example            |
| mysql              |
| performance_schema |
| study              |
| sys                |
以上study即为测试数据库包含以下测试表

mysql> show tables;
+-----------------+
| Tables_in_study |
+-----------------+
| class           |
| course          |
| part            |
| score           |
| student         |
| tb31            |
| tb32            |
| teacher         |
| test1           |
| test2           |
| user_info       |
+-----------------+

测试数据库及数据表准备完成,在进行数据的备份与恢复前,我们先简单了解下数据库备份与恢复的相关概念原理;

关于数据库的备份与还原

为什么备份?
主要是为了灾难恢复如:硬件故障(冗余)、软件故障(bug)、自然灾害、黑客攻击、误操作、以及测试需要导出数据等;
还原或叫恢复时即基于以往的备份文件;

备份类型

全量备份、增量备份、差异备份:
完全备份: 备份数据的副本(某时间点);
增量备份:仅备份自上一次完全备份或 增量备份以来变量的那部数据;
差异备份:仅备份自上一次完全备份以来变量的那部数据;

物理备份、逻辑备份:
物理备份:复制数据文件进行的备份;
逻辑备份:从数据库导出数据另存在一个或多个文件中;

根据数据服务是否在线:
热备:读写操作均可进行的状态下所做的备份;
温备:可读但不可写状态下进行的备份;
冷备:读写操作均不可进行的状态下所做的备份
以上的各备份类型备份执行时只能备份数据在备份时的状态,如想要恢复数据库崩溃那一刻的状态,需要打开binary log功能,需要基于备份的数据+binary log来恢复到数据崩溃前一刻的状态;
备份的工具有mysqldump(温备,不适合大型数据的在线备份),xtrabackup(支持对InnoDB热备,开源专业的备份数据,支持mysql/mariadb)本文将通过mysqldump与xtrabackup来说明数据的备份与恢复(异地);

无论那种工具备份,在恢复时均要binary log才能恢复到崩溃前的状态;因此需要配置数据库开启binary log功能;以下能mysql5.7.21

#cat /usr/local/mysql/etc/my.cnf
server-id       = 1
log_bin         = /data1/mysqldb/mysql-bin.log

二、mysqldump备份与恢复

mysqldump使用说明

单进程逻辑备份、完全备份、部分备份;

Usage: 
mysqldump [OPTIONS] database [tables]
         OR     mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]
         OR     mysqldump [OPTIONS] --all-databases [OPTIONS]

mysqldump mydb:表级别备份(还原时库需要存在)
mysqldump --databases mydb:库级别备份(库不在会自行创建库)

MyISAM存储引擎:支持温备,备份时要锁定表;
         -x, --lock-all-tables:锁定所有库的所有表,读锁;
         -l, --lock-tables:锁定指定库所有表;

InnoDB存储引擎:支持温备和热备;
         -x, --lock-all-tables:锁定所有库的所有表,读锁;
         -l, --lock-tables:锁定指定库所有表;
        --single-transaction:创建一个事务,基于此快照执行备份;
                -R, --routines:存储过程和存储函数;
                --triggers      触发器
                -E, --events      事件

                 --master-data[=#]
                        1:记录为CHANGE MASTER TO语句,此语句不被注释;
                        2:记录为CHANGE MASTER TO语句,此语句被注释;

                --flush-logs:锁定表完成后,即进行日志刷新操作(重新生成binlog日志);

基于mysqldump备份study数据库

热备,备份存储过程和存储函数,事件,并记得下事件位置;(便于从binlog中的位置开始恢复到故障前)
#mysqldump -uroot -predhat --single-transaction  -R -E --triggers --master-data=2 --databases study >/home/san/studydb.sql

说明:

less studydb.sql

会看到以下内容

-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000005', MASTER_LOG_POS=154;

这就是–master-data=2 选项作用,注释了,binary log 点在154

模拟备份后数据修改操作

修改前的:
mysql> select * from user_info;
+-----+-------+------+--------+----------+
| nid | name  | age  | gender | part_nid |
+-----+-------+------+--------+----------+
|   1 | san   |   20 | 男     |        1 |
|   2 | dong  |   29 | 男     |        2 |
|   4 | Ling  |   28 | 男     |        4 |
|   5 | ling  |   28 | 男     |        3 |
|   6 | dong  |   30 | 男     |        1 |
|   7 | b     |   11 | 女     |        1 |
|   8 | c     |   12 | 女     |        1 |
|   9 | d     |   18 | 女     |        4 |
|  10 | e     |   22 | 男     |        3 |
|  11 | f     |   23 | 男     |        2 |
|  12 | dongy |   22 | 男     |        1 |
+-----+-------+------+--------+----------+
11 rows in set (0.00 sec)
增加一条:
mysql> insert into user_info values(13,'hi',18,'男',4);
Query OK, 1 row affected (0.03 sec)
删除一条:
mysql> delete  from user_info where nid=1;
Query OK, 1 row affected (0.01 sec)
最终在上次备份后user_info数据如下:
mysql> select * from user_info;
+-----+-------+------+--------+----------+
| nid | name  | age  | gender | part_nid |
+-----+-------+------+--------+----------+
|   2 | dong  |   29 | 男     |        2 |
|   4 | Ling  |   28 | 男     |        4 |
|   5 | ling  |   28 | 男     |        3 |
|   6 | dong  |   30 | 男     |        1 |
|   7 | b     |   11 | 女     |        1 |
|   8 | c     |   12 | 女     |        1 |
|   9 | d     |   18 | 女     |        4 |
|  10 | e     |   22 | 男     |        3 |
|  11 | f     |   23 | 男     |        2 |
|  12 | dongy |   22 | 男     |        1 |
|  13 | hi    |   18 | 男     |        4 |
+-----+-------+------+--------+----------+
11 rows in set (0.00 sec)
可以看出少了一条,加了一条;

模拟数据库损坏并恢复study数据库

关闭mysql并到数据目录删除study数据库;

假设发现study数据已经丢失了;

数据库运行正常;查看binlog位置
mysql> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       815 |
| mysql-bin.000002 |       177 |
| mysql-bin.000003 |       177 |
| mysql-bin.000004 |   1890875 |
| mysql-bin.000005 |       725 |
+------------------+-----------+
记住这里最后一个binlog文件及位置是mysql-bin.000005   725
结合上面备份文件中的-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000005', MASTER_LOG_POS=154; 可以分析出备份时位置是154而数据库丢失前是725
因此我们恢复study数据库里需要恢复上次的全备+加mysql-bin.000005中的154-725内容;

模拟study丢失过程(传说溃的删库路)
[root@db mysqldb]# service stop mysqld
[root@db mysqldb]# pwd
/data1/mysqldb
[root@db mysqldb]# rm -rf  study/
启动数据库
[root@db mysqldb]# service stop mysqld
登录数据库并查看发现study数据库已经丢失了

还原数据库

mysql -uroot -predhat < studydb.sql
mysql> show databases;
可发现已经恢复;但是之前完整备份的到崩溃前的修改不见了;如下:
mysql> select * from user_info;
+-----+-------+------+--------+----------+
| nid | name  | age  | gender | part_nid |
+-----+-------+------+--------+----------+
|   1 | san   |   20 | 男     |        1 |
|   2 | dong  |   29 | 男     |        2 |
|   4 | Ling  |   28 | 男     |        4 |
|   5 | ling  |   28 | 男     |        3 |
|   6 | dong  |   30 | 男     |        1 |
|   7 | b     |   11 | 女     |        1 |
|   8 | c     |   12 | 女     |        1 |
|   9 | d     |   18 | 女     |        4 |
|  10 | e     |   22 | 男     |        3 |
|  11 | f     |   23 | 男     |        2 |
|  12 | dongy |   22 | 男     |        1 |
+-----+-------+------+--------+----------+
11 rows in set (0.00 sec)

结合binlog恢复:

从binlog上导出sql文件
[root@db mysqldb]# mysqlbinlog mysql-bin.000005 >/root/binlog.sql
登录mysql恢复
恢复过程中临时关闭binlog记录
mysql> set @@session.sql_log_bin=OFF;
mysql> source binlog.sql;
Query OK, 0 rows affected (0.00 sec

mysql> set @@session.sql_log_bin=ON;
mysql> use study; 
mysql> select * from user_info;
+-----+-------+------+--------+----------+
| nid | name  | age  | gender | part_nid |
+-----+-------+------+--------+----------+
|   2 | dong  |   29 | 男     |        2 |
|   4 | Ling  |   28 | 男     |        4 |
|   5 | ling  |   28 | 男     |        3 |
|   6 | dong  |   30 | 男     |        1 |
|   7 | b     |   11 | 女     |        1 |
|   8 | c     |   12 | 女     |        1 |
|   9 | d     |   18 | 女     |        4 |
|  10 | e     |   22 | 男     |        3 |
|  11 | f     |   23 | 男     |        2 |
|  12 | dongy |   22 | 男     |        1 |
|  13 | hi    |   18 | 男     |        4 |
+-----+-------+------+--------+----------+
11 rows in set (0.00 sec)

可以看出study数据库已经恢复到崩溃损坏前的状态;另外完全 可以新准备一台数据库服务器;把sql转移到新机器上恢复;前提数据配置参数需要一样;

三、xtrabackup备份与恢复

xtrabackup简介

xtrabackup是Percona一款开源工具,支持innodb,Xtradb(mariadb)引擎数据库的热备;
对MyISAM:温备,不支持增量备份;InnoDB:热备,增量;
物理备份,速率快、可靠;备份完成后自动校验备份结果集是否可用;还原速度快
功能介绍与Innobackup(mysql企业版收费)对比参考官网
所数据库引擎请使用innodb引擎

xtrabackup安装与使用说明

安装
[官方下载地址](https://www.percona.com/downloads/XtraBackup/LATEST/)
本次使用percona-xtrabackup-24-2.4.8-1
[root@db ~]# wget https://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.4.8/binary/redhat/7/x86_64/percona-xtrabackup-24-2.4.8-1.el7.x86_64.rpm
[root@db ~]# yum install ./percona-xtrabackup-24-2.4.8-1.el7.x86_64.rpm -y

**获取帮助与使用:**
可以通过man  xtrabackup 获取详细使用说明与实例
Usage: 
 innobackupex [--defaults-file=#] --backup | innobackupex [--defaults-file=#] --prepare] [OPTIONS]
 备份用到的主要选项:
    --defaults-file=     #mysql或mariadb配置文件
        --user=                  #备份时使用的用户(对备份的数据库有备份权限)
        --password=         #备份用户密码
        -H | --host=            #localhost或远程主机

**恢复时到的主要选项:**
        --apply-log         #分析获取binary log文件生成backup_binlog_info文件
        ---copy-back      #基于backup_binlog_info等文件恢复
注:innobackupex是xtrabackup的软件链接;

xtrabackup全备与恢复:

注意:备份时数据库是在线状态;恢复时需要离线并且mysql数据目录为空;
备份:

创建备份目录 
mkdir -pv /data/backup
创建备份授权账号root(可以是其他用户最小权限)
mysql> GRANT ALL ON *.* TO 'root'@'127.0.0.1' identified by "redhat";
Query OK, 0 rows affected, 1 warning (0.00 sec)

[root@db mysqldb]# innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf --user=root --password=redhat  --host=127.0.0.1 /data/backup
看到类似如下信息表示备份成功:
xtrabackup: Transaction log of lsn (7701576) to (7701585) was copied.
180401 11:52:35 completed OK!
同时在/data/backup目录中产生以时间为目录的备份目录
[root@db backup]# ll /data/backup/
drwxr-x--- 14 root root 4096 4月   1 11:52 2018-04-01_11-52-29

备份后对数据库study 中的表进行修改

删除student表
mysql> drop table student;
Query OK, 0 rows affected (0.04 sec)
往user_info表中插入两行
mysql> insert into user_info values(1,"san",18,"男",4),(14,"Hello",28,"女",2);
Query OK, 1 row affected (0.00 sec)

模拟数据库崩溃

注意binlog文件备份好;如果binglog和数据目录在一起
[root@db backup]# service mysqld stop
[root@db backup]# rm -rf /data1/mysqldb/*

恢复数据:

切换到备份数据目录
[root@db backup]# cd /data/backup/2018-04-01_11-52-29
事务回滚不提交
[root@db 2018-04-01_11-52-29]# innobackupex  --defaults-file=/usr/local/mysql/etc/my.cnf --apply-log ./
类似以下提示表示完成:
InnoDB: Shutdown completed; log sequence number 7702056
180401 12:13:40 completed OK!

数据还原

由于centos7默认有/etc/my.cnf文件
因此需要重命名my.cnf或移除以免影响恢复;
[root@db 2018-04-01_11-52-29]# innobackupex  --defaults-file=/usr/local/mysql/etc/my.cnf --copy-back ./
类似以下提示表示恢复完成:
180401 12:16:15 [01]        ...done
180401 12:16:15 completed OK!

恢复binlog中信息

查看全备中的binlog信息(文件和位置)

[root@db backup]# cat /data/backup/2018-04-01_11-52-29/xtrabackup_binlog_info
mysql-bin.000008        14775
由引可知在上次全备时的binglog文件是mysql-bin.000008位置为14775
获取binlog信息
[root@db backup]# mysqlbinlog -j 14775 mysql-bin.000008 >/data/backup/binlog.sql
还原binlog中的内容(全备后的修改数据内容)
切换到mysql数据目录(/data1/mysqldb)并修改权限
[root@db mysqldb]# cd /data1/mysqldb
[root@db mysqldb]# chown mysql.mysql *  -R
启动mysql
[root@db mysqldb]# service mysqld start

登录数据库并导入binlog.sql

mysql> source /data/backup/binlog.sql
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user_info;
+-----+-------+------+--------+----------+
| nid | name  | age  | gender | part_nid |
+-----+-------+------+--------+----------+
|   1 | san   |   18 | 男     |        4 |
|   2 | dong  |   29 | 男     |        2 |
|   4 | Ling  |   28 | 男     |        4 |
|   5 | ling  |   28 | 男     |        3 |
|   6 | dong  |   30 | 男     |        1 |
|   7 | b     |   11 | 女     |        1 |
|   8 | c     |   12 | 女     |        1 |
|   9 | d     |   18 | 女     |        4 |
|  10 | e     |   22 | 男     |        3 |
|  11 | f     |   23 | 男     |        2 |
|  12 | dongy |   22 | 男     |        1 |
|  13 | hi    |   18 | 男     |        4 |
|  14 | Hello |   28 | 女     |        2 |
+-----+-------+------+--------+----------+
13 rows in set (0.00 sec)

xtrabackup 增量备份与恢复

备份流程:
首次增量备份是基于完整备份后做的增量备份 ,后面的增量备份将基于前一次增量备份;
恢复流程:
合并完整备份事务 –>再合并第一次增量的事务–>….最后一次增量备份 +binlog日志

完整备份:

[root@db ~# innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf --user=root --password=redhat  --host=127.0.0.1 /data/backup
提示类似如下信息完成 :
xtrabackup: Transaction log of lsn (7802468) to (7802477) was copied.
180401 13:13:13 completed OK!
[root@db ~# ll /data/backup
2018-04-01_13-13-10    ######完整备份目录

模拟数据库的修改操作

删除第10行并新增一行
mysql> delete from user_info where nid=10;
Query OK, 1 row affected (0.01 sec)

mysql> insert into user_info value(15,'hehe',22,'男',1);
Query OK, 1 row affected (0.01 sec)

第一次增量备份

[root@db ~# innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf --incremental --user=root --password=redhat  --host=127.0.0.1 /data/backup/ --incremental-basedir=/data/backup/2018-04-01_13-13-10/
提示类似如下信息完成 :
xtrabackup: Transaction log of lsn (7803424) to (7803433) was copied.
180401 13:17:26 completed OK!

再次模拟数据库的修改操作

mysql> select * from user_info;
+-----+-------+------+--------+----------+
| nid | name  | age  | gender | part_nid |
+-----+-------+------+--------+----------+
|   1 | san   |   18 | 男     |        4 |
|   2 | dong  |   29 | 男     |        2 |
|   4 | Ling  |   28 | 男     |        4 |
|   5 | ling  |   28 | 男     |        3 |
|   6 | dong  |   30 | 男     |        1 |
|   7 | b     |   11 | 女     |        1 |
|   8 | c     |   12 | 女     |        1 |
|   9 | d     |   18 | 女     |        4 |
|  11 | f     |   23 | 男     |        2 |
|  12 | dongy |   22 | 男     |        1 |
|  13 | hi    |   18 | 男     |        4 |
|  14 | Hello |   28 | 女     |        2 |
|  15 | hehe  |   22 | 男     |        1 |
+-----+-------+------+--------+----------+
13 rows in set (0.01 sec)
插入一行再删除一行
mysql> insert into user_info value(16,'haha',21,'女',3);
Query OK, 1 row affected (0.01 sec)

mysql> delete from user_info where nid=2;
Query OK, 1 row affected (0.01 sec)
mysql> select * from user_info;
+-----+-------+------+--------+----------+
| nid | name  | age  | gender | part_nid |
+-----+-------+------+--------+----------+
|   1 | san   |   18 | 男     |        4 |
|   4 | Ling  |   28 | 男     |        4 |
|   5 | ling  |   28 | 男     |        3 |
|   6 | dong  |   30 | 男     |        1 |
|   7 | b     |   11 | 女     |        1 |
|   8 | c     |   12 | 女     |        1 |
|   9 | d     |   18 | 女     |        4 |
|  11 | f     |   23 | 男     |        2 |
|  12 | dongy |   22 | 男     |        1 |
|  13 | hi    |   18 | 男     |        4 |
|  14 | Hello |   28 | 女     |        2 |
|  15 | hehe  |   22 | 男     |        1 |
|  16 | haha  |   21 | 女     |        3 |
+-----+-------+------+--------+----------+
13 rows in set (0.00 sec)

第二次增量备份:

[root@db backup]# innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf --incremental --user=root --password=redhat  --host=127.0.0.1 /data/backup/ --incremental-basedir=/data/backup/2018-04-01_13-17-21/
注意:这里的 --incremental-basedir=/data/backup/2018-04-01_13-17-21/ 是上一次增量备份 产生的备份 目录 
如果基于第一次完整备份 则成为差异备份 

找出最近一次增量备份的binlog文件及信息

cd /data/backup/2018-04-01_13-21-56
[root@db 2018-04-01_13-21-56]# cat xtrabackup_binlog_info 
mysql-bin.000001    17452
备份 mysql-bin.000001 到/data/backup中
[root@db backup]# cd /data/backup
[root@db backup]# cp /data1/mysqldb/mysql-bin.000001 .
[root@db backup]# mysqlbinlog mysql-bin.000001 >binlog.sql

模拟数据库崩溃数据丢失

[root@db backup]# service mysqld stop
[root@db backup]# rm -rf /data1/mysqldb/*

数据恢复

[root@n1 backup]# ls
2018-04-01_13-13-10     2018-04-01_13-17-21    2018-04-01_13-21-56     binlog.sql    mysql-bin.000001

依次是完全整备份 ,第一次和第二次增量备份 目录 ,以及备份出来的binlog文件与binlog.sql
恢复过程:
首先对第1个(完整备份)合并只提交事务不回滚 再把第2个目录合并提交事务不回滚到第一个,再把第3个合并到第1个中;最后做一次回滚,再做统一事务提交;最后再加binlog恢复

完整备份 的事务合并
[root@db backup]# innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf --apply-log --redo-only 2018-04-01_13-13-10/
合并第一次增量事务
[root@db backup]# innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf --apply-log --redo-only 2018-04-01_13-13-10/ --incremental-dir=2018-04-01_13-17-21/
合并第二次增量事务
[root@db backup]# innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf --apply-log --redo-only 2018-04-01_13-13-10/ --incremental-dir=2018-04-01_13-21-56/
合并所有的事务
[root@db backup]# innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf  --apply-log 2018-04-01_13-13-10/
提交还原事务
[root@db backup] innobackupex --defaults-file=/usr/local/mysql/etc/my.cnf  --copy-back 2018-04-01_13-13-10/

修改还原数据权限与启动数据库:

[root@db backup]chown mysq.mysql /data1/mysqldb -R
[root@db backup] systemctl start mysqld

binlog事务恢复

mysql> source /data/backup/binlog.sql
mysql> select * from user_info;
+-----+-------+------+--------+----------+
| nid | name | age | gender | part_nid |
+-----+-------+------+--------+----------+
| 1 | san | 18 | 男 | 4 |
| 4 | Ling | 28 | 男 | 4 |
| 5 | ling | 28 | 男 | 3 |
| 6 | dong | 30 | 男 | 1 |
| 7 | b | 11 | 女 | 1 |
| 8 | c | 12 | 女 | 1 |
| 9 | d | 18 | 女 | 4 |
| 11 | f | 23 | 男 | 2 |
| 12 | dongy | 22 | 男 | 1 |
| 13 | hi | 18 | 男 | 4 |
| 14 | Hello | 28 | 女 | 2 |
| 15 | hehe | 22 | 男 | 1 |
| 16 | haha | 21 | 女 | 3 |
+-----+-------+------+--------+----------+
13 rows in set (0.00 sec)

到此增量备份 与恢复 已经 完成!

总结

日常数据库的备份是十分有必要的,而且不管用什么方法恢复,开启binary log十分重要,否则恢复不完整;binary log最好不要和数据目录一起,另外建议数据目录和binary log所在目录不要放在同一块物理磁盘;同时需要计划备份并实现异地备份;这样出现删库跑或崩溃数据丢失时就不怕了!本文很多步骤,可能存在遗漏之处,如有错误之处,欢迎指点。

mysql-物理备份-Percona xtrabackup

xtrabackup是percona公司开发的一个用于mysql物理热备的备份工具。

软件安装后一共有4个可执行文件:

  • innobackupex:perl脚本,用来备份非innodb表,同时会调用xtrabackup来备份innodb表,会和mysql server进行交互。如:加读锁(FTWRL),获取位点(show slave status)等。即封装了xtrabackup

  • xbcrypt:用来解密

  • xbstream:类似tar,一种支持并发写的流文件格式。和xbcrypt都在备份和解压会用到

  • xtrabackup:c/c++编译的二进制,用来备份innodb表,和mysql server没有交互

原理

通信方式:xtrabackup和innobackupex之间的交互和协调是通过控制文件的创建和删除来实现的。

主要文件:

    xtrabackup_suspended_1
    xtrabackup_suspended_2
    xtrabackup_log_copied

例:看看备份时xtrabackup_suspended_2是怎么协调2个工具进程的:

  1. innobackupex在启动xtrabackup进程后,会一直等xtrabackup备份完innodb文件,方式就是等待xtrabackup_suspended_2被创建出

  2. xtrabackup备份完innodb数据后,就在指定目录下创建出xtrabackup_suspended_2,然后等到这个文件被innobackupex删除,

  3. innobackupex 检测到文件 xtrabackup_suspended_2 被创建出来后,就继续往下走;

  4. innobackupex 在备份完非 InnoDB 表后,删除 xtrabackup_suspended_2 这个文件,这样就通知 xtrabackup 可以继续了,然后等 xtrabackup_log_copied 被创建;

  5. xtrabackup 检测到 xtrabackup_suspended_2 文件删除后,就可以继续往下了。

未分类

备份过程图

未分类

说明:

  1. innobackupex 在启动后,会先 fork 一个进程,启动 xtrabackup进程,然后就等待 xtrabackup 备份完 ibd 数据文件;

  2. xtrabackup 在备份 InnoDB 相关数据时,是有2种线程的,1种是 redo 拷贝线程,负责拷贝 redo 文件,1种是 ibd 拷贝线程,负责拷贝 ibd 文件;redo 拷贝线程只有一个,在 ibd 拷贝线程之前启动,在 ibd 线程结束后结束。xtrabackup 进程开始执行后,先启动 redo 拷贝线程,从最新的 checkpoint 点开始顺序拷贝 redo 日志;然后再启动 ibd 数据拷贝线程,在 xtrabackup 拷贝 ibd 过程中,innobackupex 进程一直处于等待状态(等待文件被创建)。

  3. xtrabackup 拷贝完成idb后,通知 innobackupex(通过创建文件),同时自己进入等待(redo 线程仍然继续拷贝);

  4. innobackupex 收到 xtrabackup 通知后,执行FLUSH TABLES WITH READ LOCK (FTWRL),取得一致性位点,然后开始备份非 InnoDB 文件(包括 frm、MYD、MYI、CSV、opt、par等)。拷贝非 InnoDB 文件过程中,因为数据库处于全局只读状态,如果在业务的主库备份的话,要特别小心,非 InnoDB 表(主要是MyISAM)比较多的话整库只读时间就会比较长,这个影响一定要评估到。

  5. 当 innobackupex 拷贝完所有非 InnoDB 表文件后,通知 xtrabackup(通过删文件) ,同时自己进入等待(等待另一个文件被创建);

  6. xtrabackup 收到 innobackupex 备份完非 InnoDB 通知后,就停止 redo 拷贝线程,然后通知 innobackupex redo log 拷贝完成(通过创建文件);

  7. innobackupex 收到 redo 备份完成通知后,就开始解锁,执行 UNLOCK TABLES;

  8. 最后 innobackupex 和 xtrabackup 进程各自完成收尾工作,如资源的释放、写备份元数据信息等,innobackupex 等待 xtrabackup 子进程结束后退出。

在备份进程中都是直接通过操作系统读取数据文件的,只在执行SQL命令时和数据库有交互,基本不会影响数据库的运行,在备份非innodb时会有一段时间只读,对备份innodb表时完全没有影响。

备份innodb文件和非innodb都是通过拷贝文件,但实现的方式不一样,innodb是以page粒度(xtrabackup),在读取每个page时会检验checksum值,保证数据块是一致的;非innodb是cp或者tar(innobackupex),由于对文件做了FTWRL,磁盘上的文件也是完整的,备份的数据也是完整的。

利用 xtrabackup 工具实现增量备份 mysql(附脚本)

1、安装 percona 源

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

2、安装 xtrabackup

yum install percona-xtrabackup-24 -y            #2.4 之前版本可能不支持 mysql5.7

3、创建备份文件夹

mkdir /data/backup/mysqlbak

4、编写备份脚本

vim mysqldump.sh
#!/bin/sh
base_dir="/data/backup/mysqlbak/"
log_file="/tmp/Backup.log"
increse_dir=
grep "Backup created in directory" $log_file | awk -F "'" {'print$2'}

dir_name=
grep "Backup created in directory" $log_file | awk -F "'" {'print$2'} | awk -F "/" {'print$5'}

increse_dir_path=
grep "Backup created in directory" $log_file | awk -F "'" {'print$2'} | awk -F '/' '{for(i=1;i<=4;i++)printf $i"/"; printf "n"}'

fullbackup_exist=
ls $base_dir | wc -l

if [$fullbackup_exist = 0 -a "$1" != "full_backup"];then
echo "you must make the fullbackup first! please usage: $0 full_backup"
exit 88;
fi
full_backup() {
innobackupex --user=root --password=password $base_dir
}
increase_backup() {
innobackupex --user=root --password=password --incremental-basedir=$increse_dir --incremental $base_dir
cd $increse_dir_path
tar -zcvf ${dir_name}.tar.gz $dir_name
mv $increse_dir /tmp/
}
case "$1" in
full_backup)
full_backup > $log_file 2>& 1
;;
increase_backup)
increase_backup > $log_file 2>& 1
;;
)
echo "usage: $0 {full_backup|increase_backup}"
;;
esac

5、执行第一次全量备份

./mysqldump.sh full_backup

6、创建计划任务,进行日常增量备份

crontab -e


01 00 sh /root/mysqldump.sh increase_backup

7、制作还原脚本

#!/bin/sh
base_dir="/data/backup/"
tar_files=
find $base_dir -name "*.tar.gz"

recover_mysql() {
for tar_file in $tar_files
do
cd $base_dir
tar -zxvf $tar_file
rm -f $tar_file
done
full_dir=
ls -lt $base_dir | tail -1 | awk {'print$9'}

increase_dirs=
ls -lrt $base_dir | grep "root" | awk {'print$9'}

innobackupex --apply-log --redo-only ${base_dir}${full_dir}
for increase_dir in $increase_dirs
do
if ["$increase_dir" != "$full_dir"];then
innobackupex --apply-log --redo-only --incremental ${base_dir}${full_dir} --incremental-dir=${base_dir}${increase_dir}
fi
done
innobackupex --copy-back ${base_dir}${full_dir}
}
recover_mysql > /tmp/recover_mysql.log 2>& 1

Xtrabackup实现Mysql的InnoDB引擎热备份

前面Zabbix使用的数据库是mysql,数据库备份不用多说,必须滴,由于使用的是innodb引擎,既然做,那就使用第三方强大的Xtrabackup工具来热备吧,Xtrabackup的说明,参见https://my.oschina.net/u/1171265/blog/200437

数据库备份

简单粗暴,下面给出mysql备份脚本:

#!/bin/bash
#mysql热备脚本,Version:1.0
#Author:jzd
#备份策略:每周一进行完整备份,以后每一天在前一天的基础上进行增量备份
#
#备份目录
back_dir="/back"

#备份数据库信息
host="127.0.0.1"
dbuser="dbuser"
dbpasswd="dbpasswd"

#日志文件
back_log="${back_dir}/mysql_back.log"

#week day
week_day=`date +%w`
#yesterday
yesterday=`date +%F -d "1 days ago"`

#日志记录函数
function log(){

  echo "`date` $1" | tee -a ${back_log}

}

#判断当前日期,是周一进行全备份,其他时间进行增量备份
if [ ${week_day} -eq 1 ]; then
#完整备份
  log "周${week_day}开始完全备份..."
  innobackupex --host=${host} --user=${dbuser} --password=${dbpasswd} ${back_dir} &>> ${back_log}
  if [ $? -eq 0 ]; then
    log "完全备份完毕."
    else
       log "完全备份出错,请检查."
       exit 1
  fi
  else
    let dir_num=`find ${back_dir} -type d -name "${yesterday}*" | wc -l`
    if [ ${dir_num} -ne 1 ]; then
      log "昨天增量目录未找到或昨天备份目录大于等于2个,请确认后再次备份."
      exit 1
    fi
    incremental_dir=`find ${back_dir} -type d -name "${yesterday}*"`
    log "周${week_day}开始增量备份..."
    #增量备份
    innobackupex --host=${host} --user=${dbuser} --password=${dbpasswd} --incremental ${back_dir} --incremental-basedir=${incremental_dir} &>> ${back_log}
    if [ $? -eq 0 ]; then
      log "增量备份成功."
      else
        log "备份失败,请检查日志..."
        exit 1
    fi
fi

exit $?

需修改的地方,也可以写成配置文件source进去,完全可以用在生产环境。

#备份目录

back_dir="/back"



#备份数据库信息

host="127.0.0.1"

dbuser="dbuser"

dbpasswd="dbpasswd"



#日志文件

back_log="${back_dir}/mysql_back.log"

数据恢复

话说备份容易,恢复不易啊,下面也给出恢复脚本,配合上面备份脚本使用,但是恢复完毕后,需手动恢复当日的二进制文件,恢复方法见开篇Xtrabackup介绍文章;

恢复脚本的星期和日期对应的转换,搞得头都大了,缠了两天,判断太多,导致太乱,于是多使用函数,发现自己对函数的使用加强了(哈哈,相对于以前,感觉自己有面向对象的思想了,但这是shell)

#!/bin/bash
#mysql数据恢复脚本
#Author:jzd
#Version:V1.0

#back dir
back_dir='/back'
#full back day
full_back_day=1
#today
today=`date +%F`
#week day
week_day=`date +%w`
#log file
recovery_log="${back_dir}/mysql_recovery.log"

#log
function log(){
  echo "`date` $1" | tee -a ${recovery_log}
}

#find back dir
function finddir(){
  if [ `find $back_dir -type d -name "$1*" | wc -l` -ne 1 ]; then
    log "发现备份目录$1为0个或多于一个,请检查..."
    exit 1
    else
      log "发现备份目录`find $back_dir -type d -name "$1*"`"
      find_dir="`find $back_dir -type d -name "$1*"`"
  fi
}

#all recovery
function allredo(){
 log "开始完整备份恢复准备..."
 innobackupex --apply-log --redo-only $1 &>> ${recovery_log}
 if [ $? -ne 0 ]; then
    log "完整恢复准备出错,请检查..."
    exit 1
 fi
 log "完整备份恢复准备完成"
}

#incremental recovery
function incredo(){
 log "开始增量数据恢复准备..."
 innobackupex --apply-log --redo-only $1 --incremental-dir=$2 &>> ${recovery_log}
 if [ $? -ne 0 ]; then
    log "增量数据恢复准备出错,请检查..."
    exit 1
  fi
  log "增量数据$2恢复准备完成"
}
#real recovery
function recovery(){
  log "备份数据准备完成,开始恢复数据..."
  innobackupex --copy-back $1 &>> ${recovery_log}
  if [ $? -ne 0 ]; then
    log "完整恢复准备出错,请检查..."
    exit 1
  fi
  log "恢复数据完成,请检查."
  log "请手动恢复二进制文件数据."
}

#判断今日是否是周一

if [ $week_day -eq ${full_back_day} ]; then
  finddir ${today}
  all_dir="${find_dir}"
  if [ ! -z "${all_dir}" ]; then
    allredo $all_dir
    recovery $all_dir
    else
      log "未发现今日备份,恢复上周数据."
      for i in "7 6 5 4 3 2 1"
        do
          back_date=`date +%F -d "${i} days ago"`
          if [ $i -eq 7 ]; then
            finddir ${back_date}
            all_dir="${find_dir}"
            allredo ${all_dir}
            else
              finddir ${back_date}
              dir_back=${find_dir}
              incredo ${all_dir} ${dir_back}
          fi
      done
      recovery ${all_dir}
  fi
  else
    back_date=`date +%F -d "$((${week_day}-${full_back_day})) days ago"`
    finddir ${back_date}
    all_dir="${find_dir}"
    allredo ${all_dir}
    let flag=$((${week_day}-1-${full_back_day}))
    while [ ${flag} -ge 0 ]
      do
        incr_date=`date +%F -d "${flag} days ago"`
        finddir ${incr_date}
        incr_dir="${find_dir}"
        incredo ${all_dir} ${incr_dir}
        let flag=`expr $flag - 1`
    done
    recovery ${all_dir}
fi

exit 0

Xtrabackup恢复时报错’Error: datadir must be specified’

通过xtrabackup进行恢复的时候报错

/opt/percona-xtrabackup-2.4.4-Linux-x86_64/bin/innobackupex –defaults-file=/data/opt/mysql02/db_bak/bak/2018-01-03_03-00-05/my.conf /data/opt/mysql02/db_bak/bak/2018-01-03_03-00-05/ –copy-back

xtrabackup Error: datadir must be specified

报错原因:

指定的参数文件和备份文件在相同的目录下面

解决方法:

将参数文件存放在备份文件之外的目录下面

/opt/percona-xtrabackup-2.4.4-Linux-x86_64/bin/innobackupex –defaults-file=/etc/my_01.cnf –apply-log /data/opt/mysql02/db_bak/bak/2018-01-03_03-00-05/

Xtrabackup 恢复Mariadb单个表

1、安装 mysql 备份工具 Percona XtraBackup

http://www.cndba.cn/leo1990/article/2488

2、恢复单个表说明

1). 针对InnoDB表恢复

2). 开启了参数innodb_file_per_table 此参数修改InnoDB为独立表空间模式,每个数据库的每个表都会生成一个数据空间

3、为备份建立一个只有备份权限的用户

MariaDB [(none)]> create user 'dbbackup'@'%' identified by '123456';
MariaDB [(none)]> grant reload,lock tables,replication client,create tablespace,process,super on *.* to dbbackup@'%' ;
MariaDB [(none)]> grant create,insert,select on percona_schema.* to dbbackup@'%' ;
MariaDB [(none)]> flush privileges;

4、创建一个测试,往里面插入数据后进行备份:

MariaDB [cndba]> create table test(id int);
Query OK, 0 rows affected (0.02 sec)

MariaDB [cndba]> insert into test values(10),(20),(30);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

MariaDB [cndba]> select * from tb1;
ERROR 1146 (42S02): Table 'cndba.tb1' doesn't exist
MariaDB [cndba]> select * from test;
+------+
| id   |
+------+
|   10 |
|   20 |
|   30 |
MariaDB [cndba]> show create table test/G
*************************** 1. row ***************************
       Table: test
Create Table: CREATE TABLE `test` (
  `id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.03 sec)

如果忘记表结构可以安装工具:mysql-utilities,其中mysqlfrm可以读取表结构。

进行mysql-utilities安装:

yum install mysql-utilities -y

查看表结构

[[email protected] yum.repos.d]# mysqlfrm --diagnostic /backup/2018-01-12_00-10-40/cndba/test.frm

5、xtrabackup备份数据库

[[email protected] yum.repos.d]# innobackupex --host=localhost --user=dbbackup --password=123456 /backup/

6、准备apply-log

[[email protected] backup]# innobackupex --apply-log --export /backup/2018-01-12_00-10-40/

7 、删除表

MariaDB [cndba]> drop table test;
Query OK, 0 rows affected (0.04 sec)

MariaDB [cndba]> show create table test/G
ERROR 1146 (42S02): Table 'cndba.test' doesn't exist

8、创建表

MariaDB [cndba]> CREATE TABLE `test` ( `id` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

9、丢弃表空间

MariaDB [cndba]> ALTER TABLE test DISCARD TABLESPACE;

10、拷贝备份目录中的ibd,cfg,exp 到mysql的datadir目录

[[email protected] cndba]# cp /backup/2018-01-12_00-10-40/cndba/test.{ibd,exp,cfg} /data//mysql/cndba/
赋值权限
[[email protected] cndba]# chown -R mysql.mysql /data/mysql/cndba/

11、导入表空间

MariaDB [cndba]> alter table test import tablespace;

12、表被还原

MariaDB [cndba]> select * from test;
+------+
| id   |
+------+
|   10 |
|   20 |
|   30 |
+------+