最近用innobackup进行备份测试,我们只备份一个innodb类型的库,数据大小大概50多G,用innobackupex大概用了5个多小时,但是mysqldump只用了大约2个小时,这让我很费解,有哪位知道的同志能够交流下?按理说innobackupex应该快的,还有就是大家在备份时不要放到高峰期,因为innobackupex备份时比较吃系统IO,下面就是我备份脚本,分为全备和增备,使用innobackupex需要安装依赖包:
yum install perl-DBD-MySQL*
一、全备
1、全备脚本
--全备到远程服务器
/data/mysql/bin/innobackupex --defaults-file=/etc/my.cnf --user=root --password="*******" --database=report --stream=tar /data/backup/fullbackup 2>/data/backup/fullbackup/bak.log |gzip| ssh [email protected] "cat - > /data/backup/fullbackup/`date +%F_%H-%M-%S`.tar.gz "
--全量备份到本地
/data/mysql/bin/innobackupex --defaults-file=/etc/my.cnf --user=root --password="******" --database=report --stream=tar /data/backup/fullbackup 2>/data/backup/fullbackup/bak.log | gzip > /data/backup/fullbackup/`date +%F_%H-%M-%S`.tar.gz
注意事项:1、--defaults-file参数需要放在第一个位置,否则报错提示,通过这个参数,将数据文件(由cnf里的变量datadir指定)拷贝至备份目录下。备份成功后,将在备份目录下创建一个时间戳目录,在该目录下存放备份文件。
2、--stream=tar表示通过流的方式将文件传送给tar进行归档。
3、还有其他的参数请参考官方文档。
2、全备恢复
--解压
tar -izxvf 2015-10-26_18-11-16.tar.gz -C 2015-10-26_18-11-16
注意事项:需要添加-i参数,否则解压出来的文件不全,通过-C指定目标目录
--全量恢复:假设恢复还原到3307端口的库中
恢复分为两步,第一步需要“prepare”,其实就是xtrabackup应用事务日志,对于已经commit的操作进行前滚,对于rollback的操作进行回滚,这个跟crash recovery类似。
--应用日志:
/data/mysql/bin/innobackupex --apply-log /data/backup/fullbackup/2015-10-26_18-11-16
注意:apply-log后备份目录会出现xtrabackup_binlog_pos_innodb,这个文件记录应用到binlog日志的文件和位置。有时可能会有xtrabackup_binlog_info文件,如果做从库,那么以哪个为准呢?
1 对于纯 InnoDB 操作,备份出来的数据中上述两个文件的内容是一致的
2 对于 InnoDB 和非事务存储引擎混合操作,xtrabackup_binlog_info 中所示的 position 应该会比 xtrabackup_pos_innodb 所示的数值大。此时应以 xtrabackup_binlog_info 为准;
--copy文件
#需先关闭mysql服务 /data/mysql/bin/mysqladmin -S /tmp/mysql3307.sock --user=root --password="*******" shutdown #删除数据库目录文件和日志 rm -rf /data/mysql/data2/report ib* #进行文件同步 rsync -avz report ib* /data/mysql/data2 #最后别忘了修改权限 chown -R mysql:mysql /data/mysql/data2/*
注意事项:使用--copy-back,要求data目录下面为空,如不为空,会报错如下Original data directory /data/mysql/data2 is not empty!这种适合备份实例下的所有数据库的情况,这时可以清空data目录。但是不适合只备份特定的某些库,由于我们是备份特定report库,所以这里直接用rsync来同步文件。下面的是官方的copy-back供参考:
/data/mysql/bin/innobackupex --defaults-file=/etc/my_3307.cnf --copy-back /data/backup/fullbackup/2015-10-26_18-11-16
到这里,数据库就恢复还原好了,可以重新启动mysql服务,登录mysql查看数据恢复情况。一般来说全备的恢复比较简单。但是每次备份的数据量比较大,时间也长,大家根据实际情况决定备份方式。
二、增备
增量备份:以某个特定的全备为基础,个人理解可以细分两种:一种是每天都以该全备为基础进行增备。另一种是以前一天的增量为基础进行增量。
/data/mysql/bin/innobackupex --user=root --password="*******" --database=report --incremental --incremental-basedir=/data/backup/fullbackup/2015-10-27_15-27-04 /data/backup/fullbackup
注意事项:--incremental参数指明用增量备份方式;--incremental-basedir参数指定以哪个全备为基础
对于第一种恢复方法:
/data/mysql/bin/innobackupex --apply-log --redo-only /data/backup/fullbackup/2015-10-27_15-27-04 /data/mysql/bin/innobackupex --apply-log /data/backup/fullbackup/2015-10-27_15-27-04 --incremental-dir=/data/backup/fullbackup/2015-10-27_16-28-40
对于第二种恢复方法:
/data/mysql/bin/innobackupex --apply-log --redo-only /data/backup/fullbackup/2015-10-27_14-20-35 /data/mysql/bin/innobackupex --apply-log --redo-only /data/backup/fullbackup/2015-10-27_14-20-37 ......redo每一天的增量 /data/mysql/bin/innobackupex --apply-log /data/backup/fullbackup/2015-10-27_14-20-35 --incremental-dir=/data/backup/fullbackup/2015-10-27_14-35-11
注意事项:
对于第一种方式:由于每次都是以全备为基础增量,所以只需恢复全备和最后一次的增量即可。
对于第二种方式:需要按顺序对全备,第一次增备...第N-1次增备进行应用事务日志文件,最后一次的增量不需要,最终日志都应用到全备中了,故最后只需要将全备文件夹中的文件copy到对应data目录即可。
三、从全备中恢复指定的表
其实,我们很多情况下并不需要恢复整个库,更多的是恢复指定的表,如果用mysqldump备份的就非常蛋疼了,我曾经从一个mysqldump备份的70G文件中抽取恢复一张有2000万记录的表,可想而知,这种方式效率有多低下吧,下面我介绍下应用innobackupex全备情况下,如何恢复还原指定表。
使用innobackupex恢复指定表前提条件:
- 源和目标数据库server需要使用独立表空间,即开启InnoDB_File_Per_Table = ON参数
- 目标数据库需要使用mysql5.6及以上版本或者xtradb引擎,源数据库不作限制
【恢复还原】
1、应用日志,这里需要加上--export参数:
/data/mysql/bin/innobackupex --apply-log --export /data/backup/test
打印应用日志过程如下:
这时,在全备目录下数据库目录中多生成了.cfg和.exp两个文件,如下:
root > ll -rw-r--r-- 1 root root 490 Nov 11 16:04 users_cdk.cfg -rw-r--r-- 1 root root 16384 Nov 11 16:04 users_cdk.exp -rw-rw---- 1 root root 8640 Jul 23 15:57 users_cdk.frm -rw-rw---- 1 root root 98304 Jul 24 16:07 users_cdk.ibd
2、还原指定的t_user_session表数据:
- 需要在目标库中手工建好与源数据库一致的表结构:(省)
- discard t_user_session表空间:
mysql> ALTER TABLE t_user_session DISCARD TABLESPACE; Query OK, 0 rows affected (0.01 sec)
- 从备份目录复制.cfg .ibd文件到目标服务器数据库目录
[[email protected]]# cp t_user_session.ibd t_user_session.cfg /data/mysql/data/test/ [[email protected]]#
- 进入到MySQL之后Import表空间
mysql> ALTER TABLE t_user_session import TABLESPACE; ERROR 1815 (HY000): Internal error: Cannot reset LSNs in table '"test"."t_user_session"' : Tablespace not found --该错误是由于数据文件所属权限问题,需要改为mysql用户,比如: -rw-r--r--1 root root 719 Nov 11 16:59 t_user_session.cfg -rw-rw----1 mysql mysql 8792 Nov 11 16:58 t_user_session.frm -rw-r-----1 root root 813694976 Nov 11 16:59 t_user_session.ibd --再次导入表空间 mysql> ALTER TABLE t_user_session import TABLESPACE; Query OK, 0 rows affected (1 min 22.51 sec)
这时数据就还原完成了,比mysqldump抽取大文件快多了吧。
mysql> select * from t_user_session limit 10; +------------------+----------+---------------------+---------------------+-------------+----------------------+ | user_session_idx | user_idx | login_time | logout_time | logout_type | client_ip | +------------------+----------+---------------------+---------------------+-------------+----------------------+ | 1 | 1 | 2015-07-24 16:25:13 | 2015-07-24 16:27:19 | LOGOUT | ******************* | | 2 | 2 | 2015-07-24 16:26:16 | 2015-07-24 16:27:51 | LOGOUT | ******************* | | 3 | 2 | 2015-07-24 16:30:15 | 2015-07-24 16:30:41 | LOGOUT | ******************* | | 4 | 2 | 2015-07-24 16:32:08 | 2015-07-24 16:33:49 | LOGOUT | ******************** | | 5 | 2 | 2015-07-24 16:33:56 | 2015-07-24 16:34:32 | LOGOUT | ******************** | | 6 | 2 | 2015-07-24 16:35:34 | 2015-07-24 16:37:16 | LOGOUT | ******************** | | 7 | 2 | 2015-07-24 16:37:29 | 2015-07-24 16:37:55 | LOGOUT | ******************** | | 8 | 2 | 2015-07-24 16:37:55 | 2015-07-24 16:38:41 | LOGOUT | ******************** | | 9 | 2 | 2015-07-24 16:38:48 | 2015-07-24 16:40:18 | LOGOUT | ******************** | | 10 | 2 | 2015-07-24 16:41:19 | 2015-07-24 16:42:25 | LOGOUT | ******************** | +------------------+----------+---------------------+---------------------+-------------+----------------------+ 10 rows in set (0.00 sec)
【注意点】:
- 在复制备份文件的时候一定要复制后缀cfg文件,否则在Import的时候就会报Warning.例如如下的信息:
+---------+------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1810 | InnoDB: IO Read error: (2, No such file or directory) Error opening './test/t.cfg', will attempt to import without schema verification |
+---------+------+-------------------------------------------------------------------------------------------------------------------------------------------+
cfg文件的用处主要是在MySQL5.6执行"Flush Table xxx Export;"之后使.ibd文件保持一致性,同时这个文件会生成一个.cfg文件,在做Import的时候会对导入过程进行校验,但是在 MySQL5.6.8版本之后也不是必须要有.cfg文件.如果真没有,在导入的时候有可能就会报出上面的错误,所以为了安全还是复制它.
- 如果表有外键在Discard的时候执行如下命令:set FOREIGN_KEY_CHECKS=0; 在Import表之后执行以下命令恢复外键检查:set FOREIGN_KEY_CHECKS=1;
- 从备份目录复制.cfg .ibd文件到目标服务器数据库目录后,别忘了查看文件所属权限,否则报如下错误:ERROR 1815 (HY000): Internal error: Cannot reset LSNs in table '"test"."t_user_session"' : Tablespace not found
四、相关备份脚本
下面提供两个shell写的备份脚本,是转网友的,个人觉得写的挺全的,给大家参考:
1、全备shell脚本
1 #!/bin/bash 2 user='root' 3 passwd='root' 4 database=test 5 my_config='/etc/my.cnf' 6 backup_dir='/data/backup/fullbackup' 7 log=$database-$(date +%Y%m%d%H%M).log 8 str=$database-$(date +%Y%m%d%H%M).tar.gz 9 10 echo "Start to backup at $(date +%Y%m%d%H%M)" >> /data/backup/fullbackup/$log 11 if [ ! -d "$backup_dir" ];then 12 mkdir -p $backup_dir 13 fi 14 /data/mysql/bin/innobackupex --defaults-file=$my_config --user=$user --password=$passwd --database=$database --stream=tar $backup_dir 2>$backup_dir/$log | gzip >$backup_dir/ 15 16 $str 17 if [ $? -eq 0 ];then 18 echo "Backup is finish! at $(date +%Y%m%d%H%M)" >> /data/backup/fullbackup/$log 19 exit 0 20 else 21 echo "Backup is Fail! at $(date +%Y%m%d%H%M)" >> /data/backup/fullbackup/$log 22 exit 1 23 fi
2、全备加增备
1 #!/bin/bash 2 CONFIG_FILE="/etc/my.cnf" 3 BACKUP_USER="backup" 4 BACKUP_PASSWD="123A456" 5 MYSQL_PORT="99523" 6 MYSQL_HOST="127.0.0.1" 7 BACKUP_BASE="/home/xtr_backup" 8 XTR_BACKUPLOG="/tmp/xtr_mysql_backup.log" 9 DATE_DIR=`date +%Y-%m-%d` 10 SUNDAY_DATE=`date -d "Last sunday" +%Y-%m-%d` 11 DATE_WEEK=`date +%w` 12 DATE_TIME=`date +%Y-%m-%d-%H-%M-%S` 13 14 15 #################################################### 16 #全量备份函数 17 #################################################### 18 function Xtr_full_backup () 19 { 20 if [ -d "${BACKUP_BASE}/full/${DATE_DIR}" ] 21 then 22 rm -rf "${BACKUP_BASE}/full/${DATE_DIR}" 23 fi 24 if [ ! -d "${BACKUP_BASE}/full" ] 25 then 26 mkdir -p "${BACKUP_BASE}/full" 27 fi 28 innobackupex --defaults-file=${CONFIG_FILE} --user=${BACKUP_USER} --password=${BACKUP_PASSWD} --port=${MYSQL_PORT} --host=${MYSQL_HOST} --no-lock --no-timestamp 29 30 "${BACKUP_BASE}/full/${DATE_DIR}" 2>"/tmp/$$full_backup.log" 31 STATS_FULL_LOG=`awk '/innobackupex: completed OK\!/ {print $NF}' "/tmp/$$full_backup.log"` 32 if [ "$STATS_FULL_LOG" != "OK!" ] 33 then 34 echo "行号LINENO; 脚本名称(basename $0); 函数名称FUNCNAME; 时间DATE_TIME; Innobackupex Full Backup Is Fail">>"$XTR_BACKUPLOG" 35 exit 1 36 else 37 echo "行号LINENO; 脚本名称(basename $0); 函数名称FUNCNAME; 时间DATE_TIME; Innobackupex Full Backup Is Ok">>"$XTR_BACKUPLOG" 38 rm -rf "/tmp/$$full_backup.log" 39 fi 40 } 41 42 43 #################################################### 44 #增量备份函数 45 #################################################### 46 function Xtr_inc_backup () 47 { 48 if [ -d "${BACKUP_BASE}/inc/${SUNDAY_DATE}/${DATE_DIR}" ] 49 then 50 rm -rf "${BACKUP_BASE}/inc/${SUNDAY_DATE}/${DATE_DIR}" 51 fi 52 if [ ! -d "${BACKUP_BASE}/inc/${SUNDAY_DATE}" ] 53 then 54 mkdir -p "${BACKUP_BASE}/inc/${SUNDAY_DATE}" 55 fi 56 if [ ! -d "${BACKUP_BASE}/full/${SUNDAY_DATE}" ] 57 then 58 echo "行号LINENO; 脚本名称(basename $0); 函数名称:$FUNCNAME; 时间:$DATE_TIME; Innobackupex Full Dir ${BACKUP_BASE}/full/$SUNDAY_DATE No 59 60 Exit">>"$XTR_BACKUPLOG" 61 exit 1 62 fi 63 innobackupex --defaults-file=${CONFIG_FILE} --user=${BACKUP_USER} --password=${BACKUP_PASSWD} --port=${MYSQL_PORT} --host=${MYSQL_HOST} --no-timestamp --parallel=8 64 65 --incremental --incremental-basedir="${BACKUP_BASE}/full/${SUNDAY_DATE}" "${BACKUP_BASE}/inc/${SUNDAY_DATE}/${DATE_DIR}" 2>"/tmp/$$inc_backup.log" 66 STATS_INC_LOG=`awk '/innobackupex: completed OK\!/ {print $NF}' "/tmp/$$inc_backup.log"` 67 if [ "$STATS_INC_LOG" != "OK!" ] 68 then 69 echo "行号:$LINENO; 脚本名称:$(basename $0); 函数名称:$FUNCNAME; 时间:$DATE_TIME; Innobackupex Inc Backup Is Fail">>"$XTR_BACKUPLOG" 70 exit 1 71 else 72 echo "行号:$LINENO; 脚本名称:$(basename $0); 函数名称:$FUNCNAME; 时间:$DATE_TIME; Innobackupex Inc Backup Is Ok">>"$XTR_BACKUPLOG" 73 rm -rf "/tmp/$$inc_backup.log" 74 fi 75 } 76 77 78 #################################################### 79 #主体备份函数 80 #################################################### 81 function Main () 82 { 83 if [ "${DATE_WEEK}" -eq 0 ] 84 then 85 Xtr_full_backup 86 else 87 Xtr_inc_backup 88 fi 89 exit 0 90 } 91 92 93 #################################################### 94 #开始备份 95 #################################################### 96 Main