数据库的备份与恢复也是系统运维工程师必备的技能之一,下面介绍几种mysql数据库备份工具及其实现。
一、mysqldump备份恢复实例
二、为数据文件所在逻辑卷创建快照卷的方式进行备份恢复实例
三、使用Xtrabackup进行增量备份和恢复实例
mysqldump:
可以把整个数据库装载到一个单独的文本文件中。这个文件包含有所有重建您的数据库所需要的SQL命令。这个命令取得所有的模式,并且将其转换成DDL语法(CREATE语句,即数据库定义语句),取得所有的数据,并且从这些数据中创建INSERT语句。这个工具将您的数据库中所有的设计倒转。因为所有的东西都被包含到了一个文本文件中。这个文本文件可以用一个简单的批处理和一个合适SQL语句导回到MySQL中。可以备份整个服务器、单个或部分数据库,单个或部分表,以及表中的部分行;存储过程、存储函数、触发器等,可以自动记录备份时的二进制日志文件以及相应的position;d于Innodb可以基于单事务模式进行热备。
常用选项:
-A --all-databases 备份整个服务器
--add-drop-database 添加drop,防止报错。
-C --compress,实现压缩,用于网络传输
-E --events ;备份时间调度器;
-R --routines;备份存储过程和存储函数;
-d --no-data;只备份表结构,不备份数据;
-B --databases ;指定单个或多个数据库,以空格隔开;不指定默认备份整个数据库服务器,不加此选项跟一个数据库,则不会有创建此数据库的语句,恢复时需自行创建;
备份之前先要请求读锁,可以使用选项:
-x, --lock-all-tables
如果只备份单张表,可以使用:
-l, --lock-tables
能够记录在备份时,记录二进制日志文件所处的位置;
--master-data=2
-- CHANGE MASTER TOMASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=1755;
在mysql中请求数据库的读锁;
mysql> FLUSH TABLES WITH READ LOCK;
备份完成后,撤销读锁:
mysql> UNLOCKTABLES;
对于InnoDB数据库文件,还要注意观察将buffer pool中的数据完全同步到数据库中;(建议使用--single-transaction选项);
mysql> SHOW ENGINE InnoDB STATUS\G
在生产环境中注意观察bufferpool和FILE I/O是否还有数据;
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated137363456; in additional pool allocated 0
Dictionary memoryallocated 62417
Buffer pool size 8191
Free buffers 7990
Database pages 200
Old database pages 0
Modified db pages 0
Pending reads 0
Pending writes: LRU 0,flush list 0, single page 0
Pages made young 0, notyoung 0
0.00 youngs/s, 0.00non-youngs/s
Pages read 154, created46, written 276
0.00 reads/s, 0.00creates/s, 0.00 writes/s
No buffer pool pagegets since the last printout
Pages read ahead0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 200, unzip_LRUlen: 0
I/O sum[0]:cur[0],unzip sum[0]:cur[0]
--------
FILE I/O
--------
I/O thread 0 state:waiting for i/o request (insert buffer thread)
I/O thread 1 state:waiting for i/o request (log thread)
I/O thread 2 state:waiting for i/o request (read thread)
I/O thread 3 state:waiting for i/o request (read thread)
I/O thread 4 state:waiting for i/o request (read thread)
I/O thread 5 state:waiting for i/o request (read thread)
I/O thread 6 state:waiting for i/o request (write thread)
I/O thread 7 state:waiting for i/o request (write thread)
I/O thread 8 state:waiting for i/o request (write thread)
I/O thread 9 state:waiting for i/o request (write thread)
Pending normal aioreads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync)log: 0; buffer pool: 0
296 OS file reads, 395OS file writes, 258 OS fsyncs
0.00 reads/s, 0 avgbytes/read, 0.00 writes/s, 0.00 fsyncs/s
--single-transaction
创建一个单一的应用于整个数据库的事务,为每一个Innodb的表创建一个快照,基于此快照来进行热备份,不需要同时使用--lock-all-tables
开始备份:
# mysqldump -uroot -B db1 db2 -x > /backup/db1_db2_full-`date +%F`.sql
采用完全备份+增量备份的方式进行:
1、完全备份:
[root@localhost~]# mysqldump -uroot -p--single-transaction --events --master-data=2 --all-databases >/backup/alldb_full-`date +%F`.sql
[root@localhost ~]# ls/backup/
alldb_full-2013-09-07.sql
2、添加一些数据进行增量备份:
mysql> createdatabase db3;
ERROR 1223 (HY000):Can't execute the query because you have a conflicting read lock
mysql> unlocktables;
Query OK, 0 rowsaffected (0.00 sec)
mysql> create tablet1 (id int);
mysql> insert intot1 values (1),(2),(3);
查看二进制日志中记录的位置:
mysql> show masterstatus;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB |Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000004| 1993 | | |
+------------------+----------+--------------+------------------+
在alldb_full-2013-09-07.sql找到上次二进制日志的最后的位置
-- CHANGE MASTER TOMASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=1826;
[root@localhost ~]# mysqlbinlog--start-position=1826 --stop-position=1993 /mydata/data/mysql-bin.000004 >alldb_incre_`date +%F`.sql
在增加一些记录:
mysql> create tabletb2 (identifier int);
Query OK, 0 rowsaffected (0.34 sec)
mysql> insert intotb2 values (1),(3),(5);
Query OK, 3 rowsaffected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
模拟数据库出现故障,db3不小心被删除
mysql> drop databasedb3;
Query OK, 2 rowsaffected (0.31 sec)
此时,该如何恢复:
1、恢复完全备份
2、恢复增量备份
3、将二进制日志导出并恢复;
首先将二进制日志导出
#找到删除db3之前的位置:
[root@localhost ~]#mysqlbinlog /mydata/data/mysql-bin.000004
#130907 21:45:27 serverid 1 end_log_pos 2467 Xid = 3930
COMMIT/*!*/;
# at 2467
#130907 21:45:27 serverid 1 end_log_pos 2546 Query thread_id=8 exec_time=1 error_code=0
SETTIMESTAMP=1378561527/*!*/;
drop database db3
/*!*/;
DELIMITER ;
# End of log file
# 把从上次增量备份之后到db3删除之前的二进制日志导出到文件中;
[root@localhost ~]#mysqlbinlog --start-position=1993 --stop-position=2467 /mydata/data/mysql-bin.000004 > /tmp/recovery.sql
# 设置sql_log_bin=0,不记录恢复的二进制日志,滚动一下日志;
mysql> SET sql_log_bin=0;
mysql> FLUSH LOGS;
# 导入备份文件,完全备份---> 增量备份---->最近的二进制日志:
[root@localhost ~]#mysql -uroot -p < /backup/alldb_full-2013-09-07.sql
Enter password:
[root@localhost ~]#mysql -uroot -p < /backup/alldb_incre_2013-09-07.sql
Enter password:
[root@localhost ~]#mysql -uroot -p < /tmp/recovery.sql
Enter password:
最后SHOWDATABASES;查看恢复情况
恢复完成后,滚动一下日志,并开启二进制日志
# FLUSHLOGS;
# mysql> SET sql_log_bin=1;
二、LVM快照卷备份:
1、准备工作,创建LVM用以存储数据库数据,编译安装时指定datadir为/mydata/data
[root@localhost ~]#pvcreate /dev/sda3
Physical volume "/dev/sda3"successfully created
[root@localhost ~]#pvcreate /dev/sda5
Physical volume "/dev/sda5"successfully created
[root@localhost ~]#vgcreate myvg /dev/sda{3,5}
Volume group "myvg" successfullycreated
[root@localhost ~]#lvcreate -L 10G -n mylv -p rw myvg
Logical volume "mylv" created
[root@localhost ~]# lvs
LV VG Attr LSize Pool Origin Data% Move LogCpy%Sync Convert
mylv myvg -wi-a---- 10.00g
root vg0 -wi-ao--- 20.00g
swap vg0 -wi-ao--- 2.00g
usr vg0 -wi-ao--- 10.00g
var vg0 -wi-ao--- 20.00g
[root@localhost ~]#mke2fs -t ext4 -L MYDATA /dev/myvg/mylv
mke2fs 1.41.12(17-May-2010)
Filesystem label=MYDATA
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096(log=2)
Stride=0 blocks, Stripewidth=0 blocks
655360 inodes, 2621440blocks
131072 blocks (5.00%)reserved for the super user
First data block=0
Maximum filesystemblocks=2684354560
80 block groups
32768 blocks per group,32768 fragments per group
8192 inodes per group
Superblock backupsstored on blocks:
32768, 98304, 163840, 229376, 294912,819200, 884736, 1605632
Writing inode tables:done
Creating journal (32768blocks): done
Writing superblocks andfilesystem accounting information: done
This filesystem will beautomatically checked every 22 mounts or
180 days, whichevercomes first. Use tune2fs -c or -i tooverride.
[root@localhost ~]#mkdir /mydata/data -pv
mkdir: createddirectory `/mydata'
mkdir: createddirectory `/mydata/data'
[root@localhost ~]#mount /dev/myvg/mylv /mydata/data/
[root@localhost ~]# ls/mydata/data/
lost+found
使用Innodb引擎时,建议将每个数据库的文件单独存在,不要将所有数据存在一个表空间内,可以调整参数
innodb_file_per_table=1,将此参数保存在/etc/my.cnf里面的[mysqld]下面;
使用LVM snapshot备份的前提:事务日志必须跟数据文件在同一个LV上;
开始备份:
请求读锁,并滚动日志;
mysql> FLUSH TABLESWITH READ LOCK;
mysql> FLUSH LOGS;
记录当前状态
mysql> SHOW MASTERSTATUS;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB |Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000006| 107 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
为数据所在的卷创建快照:
[root@localhost data]#lvcreate -L 200M -n mysql-snap -s -p r /dev/myvg/mylv
挂载快照卷,并将快照卷上的数据拷出;
[root@localhost data]#mount /dev/myvg/mysql-snap /mnt
mount: block device/dev/mapper/myvg-mysql--snap is write-protected, mounting read-only
[root@localhost data]#mkdir /backup
[root@localhost ~]# cp-Rp /mnt/* /backup/
拷贝完成之后,卸载并删除快照卷
[root@localhost ~]#umount /mnt
[root@localhost ~]#lvremove /dev/myvg/my
解除读锁
mysql> UNLOCK TABLES;
数据库又进行了一些操作,此时进行增量备份;
[root@localhost ~]#mysqlbinlog --start-position=107 /mydata/data/mysql-bin.000006 > /tmp/mysql\ >-snap.incremental1.sql;
过了一段时间后,模拟数据库出现故障:
[root@localhost ~]#service mysqld stop
Shutting downMySQL....[ OK ]
[root@localhost ~]# rm-rf /mydata/*
[root@localhost ~]# cp-pR /backup/* /mydata/
[root@localhost ~]#service mysqld start
Starting MySQL[ OK ]
查看数据库中的数据,只是完全备份后的状态,此时再将二进制文件导入,即可恢复上次增量备份时的数据,如果像刚才一样把数据库的所有内容,包括二进制日志都删除,那么也只能恢复到上次增量备份时;所以二进制日志对数据恢复非常重要,一定要妥善管理;
# mysql -uroot -p < /tmp/mysql-snap.incremental1.sql
数据恢复完成。
Xtrabackup 简介
Xtrabackup是由percona提供的mysql数据库备份工具,据官方介绍,这也是世界上惟一一款开源的能够对innodb和xtradb数据库进行热备的工具。特点:
(1)备份过程快速、可靠;
(2)备份过程不会打断正在执行的事务;
(3)能够基于压缩等功能节约磁盘空间和流量;
(4)自动实现备份检验;
(5)还原速度快;
获取软件:http://www.percona.com/software/percona-xtrabackup/
Xtrabackup备份基于LSN (日志序列号),在备份时,既包含事务日志,有包含数据文件,由于是热备,有的事务还没有提交,数据还没有完全同步到磁盘上,xtrabackup恢复数据之前会做预处理,把事务日志中已提交的事务同步至数据文件,未提交事务要rollback,但是在恢复时,先不要回滚。
软件安装
# yum localinstall percona-xtrabackup-2.1.4-656.rhel6.x86_64.rpm
开始备份
1、完全备份:
# mkdir/backup/fullbackup -pv
# innobackupex --no-timestamp /backup/fullback-`date +%F`
--no-timestamp表示不使用自动生成的以日期为目录名的目录
最后出现complete OK!表示成功;
innobackupex: Backupcreated in directory '/backup/fullback-2013-09-09'
innobackupex: MySQLbinlog position: filename 'mysql-bin.000001', position 107
130909 01:51:36 innobackupex: Connection to database serverclosed
130909 01:51:36 innobackupex: completed OK!
2、恢复数据前的准备:
“准备”的主要作用正是通过回滚未提交的事务及同步已经提交的事务至数据文件也使得数据文件处于一致性状态。
# innobackupex--apply-log /backup/fullback-2013-09-09/
130909 01:34:55 innobackupex: completed OK!
3、从一个完全备份中恢复:
首先模拟数据库损坏
# servicemysqld stop
# rm -rf/mydata/data/*
# innobackupex--copy-back /backup/fullback-2013-09-09/
130909 01:54:28 innobackupex: completed OK!
恢复完成后启动数据库,注意:修改此时数据目录的权限:
# chown -R mysql.mysql/mydata/data/
# service mysqld start
完全备份并恢复完成!
Xtrabackup在进行增量备份和恢复时,其思路不同于其他备份工具
在每一次完全备份恢复之后,立即再做一次完全备份;
# innobackupex--no-timestamp /backup/fullback-`date +%F`
修改数据库内容后,进行增量备份,使用--incremental选项,同时增量备份针对的对象要指明;
# innobackupex --incremental --no-timestamp /backup/first.incremental-`date +%F`--incremental-basedir=/backup/fullback-2013-09-09/
innobackupex: Backupcreated in directory '/backup/first.incremental-2013-09-09'
innobackupex: MySQLbinlog position: filename 'mysql-bin.000001', position 391
130909 02:08:02 innobackupex: Connection to database serverclosed
130909 02:08:02 innobackupex: completed OK!
第二次增量备份:
# innobackupex--incremental --no-timestamp /backup/second.incremental-`date +%F`--incremental-basedir=/backup/first.incremental-2013-09-09/
innobackupex: Backupcreated in directory '/backup/second.incremental-2013-09-09'
innobackupex: MySQLbinlog position: filename 'mysql-bin.000001', position 848
130909 02:13:06 innobackupex: Connection to database serverclosed
130909 02:13:06 innobackupex: completed OK!
随后又进行了一些操作后,数据库发生故障,那么下一步开始恢复数据库
1、准备完全备份:
# innobackupex--apply-log --redo-only /backup/fullback-2013-09-09/
xtrabackup: startingshutdown with innodb_fast_shutdown = 1
130909 2:19:57 InnoDB: Starting shutdown...
130909 2:19:57 InnoDB: Shutdown completed; log sequence number 1621004
130909 02:19:57 innobackupex: completed OK!
2、准备第一个增量备份:
# innobackupex--apply-log --redo-only /backup/fullback-2013-09-09/--incremental-dir=/backup/first.incremental-2013-09-09/
innobackupex: Copying'/backup/first.incremental-2013-09-09/performance_schema/events_waits_summary_global_by_event_name.frm'to'/backup/fullback-2013-09-09/performance_schema/events_waits_summary_global_by_event_name.frm'
130909 02:22:25 innobackupex: completed OK!
3、准备第二个增量备份:
# innobackupex--apply-log --redo-only /backup/fullback-2013-09-09/--incremental-dir=/backup/second.incremental-2013-09-09/
innobackupex: Copying'/backup/second.incremental-2013-09-09/performance_schema/events_waits_summary_global_by_event_name.frm'to'/backup/fullback-2013-09-09/performance_schema/events_waits_summary_global_by_event_name.frm'
130909 02:23:33 innobackupex: completed OK!
4、恢复完全备份,此时的完全备份文件已经将后面的两次增量进行了“prepared”,所以只恢复完全备份即可
# innobackupex--copy-back /backup/fullback-2013-09-09/
innobackupex: Startingto copy InnoDB log files
innobackupex: in'/backup/fullback-2013-09-09'
innobackupex: back tooriginal InnoDB log directory '/mydata/data'
innobackupex: Finishedcopying back files.
130909 02:27:30 innobackupex: completed OK!
5、数据文件权限:
# chown-R mysql.mysql /mydata/data/*
6、最后利用二进制日志恢复最后的内容:
找到备份文件中最后的二进制日志位置
# cat/backup/fullback-2013-09-09/xtrabackup_binlog_info
mysql-bin.000001 848
# mysqlbinlog--start-position=848 /backup/mysql-bin.000001 > last.sql
先把二进制日志关掉,然后再把日志导入,随后再开启日志;
# SET SESSION SQL_LOG_BIN=0;
# mysql < last.sql
# SET SESSION SQL_LOG_BIN=1;
增量备份恢复最终完成,