一、为什么要用到备份和恢复?
1.灾难恢复;
2.审计;
3.测试;
备份:目的用于恢复;对备份数据做恢复测试,备份出来的数据不一定能够恢复;所以测试是很有必要做;另外还需要根据实际情况制定最优的备份和恢复策略
那么MySQL备份需要备份那些数据呢?
主要包括:数据、配置文件、二进制日志、事务日志
二、备份的类型
2.1 按备份时服务器是否继续提供服务(数据库服务是否在线)区分:
热备份(cold backup):备份时读写都不受影响
温备份(warm backup):备份时仅可进行读操作
冷备份(cold backup):也叫离线备份,读写操作均中止
不同的存储引擎对备份的支持也是不一样的,MyISAM存储引擎可以使用LVM快照功能配合实现热备份,如果没有LVM,则只能实现温备份,而InnoDB则可以完全支持热备,可使用的热备工具有:xtrabackup, mysqldump等
从数据的安全角度来说,离线备份(冷备份)是最安全的,且是最快速的.但离线备份需要停止服务,对业务带来影响.
如果MySQL服务器存在主从服务器,则可以使用将从服务器停机进行冷备份,即保证服务,又保障数据数据安全
2.2 根据备份时的接口(直接备份数据文件还是通过mysql服务器导出数据):
物理备份(physical backup):直接复制(归档)数据文件的备份方式;特点:速度快
逻辑备份(logical backup):把数据从库中提出出来保存为文本文件;特点:速度慢、丢失浮点数精度;方便使用文本处理工具直接对其处理、可移植能力强
2.3 根据备份的数据集:
完全备份(full backup)
部分备份(partial backup)
2.4 按是否备份全部还是只备份数据部分数据区别:
完全备份(full backup):备份全部需要备份的数据
增量备份(increment backup):仅备份上次完全备份或增量备份以后变化的数据
差异备份(differential backup):仅备份上次完全备份依赖变化的数据
一般情况下,根据备份策略组合使用:完全+增量;完全+差异
三、备份恢复策略及备份对象:
策略:
选择备份方式///选择备份时间///考虑到恢复成本///恢复时长///备份成本///锁时间///备份时长///备份负载
对象:
数据///配置文件///代码(存储过程,存储函数,触发器)///OS相关的配置文件(如crontab配置计划及相关的脚本)
四、备份工具介绍:
4.1 mysql备份工具:
mysqldump: 逻辑备份工具、MyISAM(温)、InnoDB(热备份)、Aria(温备)
mysqldumper: 多线程的mysqldump
mysqlhotcopy:物理备份工具、温备份
上述工具备份和恢复过程较慢、很难实现增量或差异备份
4.2 文件系统备工具:
cp/tar:物理备份
lvm-snapshot:接近于热备的工具:因为要先请求全局锁,而后创建快照,并在创建快照完成后释放全局锁;如:
上述工具备份和恢复速度较快;但是很难实现增量备份,并且请求全局需要等待一段时间,在繁忙的服务器上尤其如此;
4.3 SQL 语法备份
SELECT clause INTO OUTFILE '/path/to/somefile'
LOAD DATA INFILE '/path/from/somefile'
部分备份工具, 不会备份关系定义,仅备份表中的数据;
逻辑备份工具,略快于mysqldump.
4.4 第三方备份工具:
Innobase: 商业备份工具, innobackup
Xtrabackup: 由Percona提供的开源备份工具
对于InnoDB热备,增量备份;MyISAM温备,不支持增量;物理备份,速度快.
五、使用mysqldump对MySQL进行备份:
5.1 基本语法:
备份单个数据或单个数据中的指定表:
mysqldump [OPTIONS] database [tb1][tb2]… |
备份多个数据库:
mysqldump [OPTIONS] --databases[OPTIONS] DB1 [DB2 DB3...] |
备份所有数据库:
mysqldump [OPTIONS] --all-databases[OPTIONS] |
5.2 选项[OPTIONS]说明:
--all-databases | 导出全部数据库。 |
--all-tablespaces | 导出全部表空间。 |
--no-tablespaces | 不导出任何表空间信息。 |
--add-drop-database | 每个数据库创建之前添加drop数据库语句。 |
--add-drop-table | 每个数据表创建之前添加drop数据表语句。(默认为打开状态,使用--skip-add-drop-table取消选项) |
--add-locks |
在每个表导出之前增加LOCKTABLES并且之后UNLOCKTABLE。(默认为打开状态,使用--skip-add-locks取消选项) |
--allow-keywords | 允许创建是关键词的列名字。这由表名前缀于每个列名做到。 |
--apply-slave-statements | 在'CHANGEMASTER'前添加'STOPSLAVE',并且在导出的最后添加'STARTSLAVE'。 |
--character-sets-dir | 字符集文件的目录 |
--comments | 附加注释信息。默认为打开,可以用--skip-comments取消 |
--compatible | 导出的数据将和其它数据库或旧版本的MySQL相兼容。值可以为ansi、mysql323、mysql40、postgresql、oracle、mssql、db2、maxdb、no_key_options、no_tables_options、no_field_options等,要使用几个值,用逗号将它们隔开。它并不保证能完全兼容,而是尽量兼容。 |
--compact | 导出更少的输出信息(用于调试)。去掉注释和头尾等结构。可以使用选项:--skip-add-drop-table--skip-add-locks --skip-comments --skip-disable-keys |
--complete-insert | 使用完整的insert语句(包含列名称)。这么做能提高插入效率,但是可能会受到max_allowed_packet参数的影响而导致插入失败。 |
--compress | 在客户端和服务器之间启用压缩传递所有信息 |
--create-options | 在CREATETABLE语句中包括所有MySQL特性选项。(默认为打开状态) |
--databases | 导出几个数据库。参数后面所有名字参量都被看作数据库名。 |
--debug | 输出debug信息,用于调试。默认值为:d:t:o,/tmp/mysqldump.trace |
--debug-check | 检查内存和打开文件使用说明并退出。 |
--debug-info | 输出调试信息并退出 |
--default-character-set | 设置默认字符集,默认值为utf8 |
--delayed-insert | 采用延时插入方式(INSERTDELAYED)导出数据 |
--delete-master-logs | master备份后删除日志. 这个参数将自动激活--master-data。 |
--disable-keys | 对于每个表,用/*!40000ALTER TABLE tbl_name DISABLE KEYS */;和/*!40000 ALTER TABLE tbl_name ENABLEKEYS */;语句引用INSERT语句。这样可以更快地导入dump出来的文件,因为它是在插入所有行后创建索引的。该选项只适合MyISAM表,默认为打开状态。 |
--dump-slave | 该选项将导致主的binlog位置和文件名追加到导出数据的文件中。设置为1时,将会以CHANGEMASTER命令输出到数据文件;设置为2时,在命令前增加说明信息。该选项将会打开--lock-all-tables,除非--single-transaction被指定。该选项会自动关闭--lock-tables选项。默认值为0。 |
--events | 导出事件。 |
--extended-insert | 使用具有多个VALUES列的INSERT语法。这样使导出文件更小,并加速导入时的速度。默认为打开状态,使用--skip-extended-insert取消选项。 |
--fields-terminated-by | 导出文件中忽略给定字段。与--tab选项一起使用,不能用于--databases和--all-databases选项 |
--fields-enclosed-by | 输出文件中的各个字段用给定字符包裹。与--tab选项一起使用,不能用于--databases和--all-databases选项 |
--fields-optionally-enclosed-by | 输出文件中的各个字段用给定字符选择性包裹。与--tab选项一起使用,不能用于--databases和--all-databases选项 |
--fields-escaped-by | 输出文件中的各个字段忽略给定字符。与--tab选项一起使用,不能用于--databases和--all-databases选项。 |
--flush-logs | 开始导出之前刷新日志。 请注意:假如一次导出多个数据库(使用选项--databases或者--all-databases),将会逐个数据库刷新日志。除使用--lock-all-tables或者--master-data外。在这种情况下,日志将会被刷新一次,相应的所以表同时被锁定。因此,如果打算同时导出和刷新日志应该使用--lock-all-tables或者--master-data和--flush-logs。 |
--flush-privileges | 在导出mysql数据库之后,发出一条FLUSHPRIVILEGES 语句。为了正确恢复,该选项应该用于导出mysql数据库和依赖mysql数据库数据的任何时候 |
--force | 在导出过程中忽略出现的SQL错误。 |
--help | 显示帮助信息并退出。 |
--hex-blob | 使用十六进制格式导出二进制字符串字段。如果有二进制数据就必须使用该选项。影响到的字段类型有BINARY、VARBINARY、BLOB。 |
--host | 需要导出的主机信息 |
--ignore-table |
不导出指定表。指定忽略多个表时,需要重复多次,每次一个表。每个表必须同时指定数据库和表名。例如:--ignore-table=database.table1--ignore-table=database.table2... |
--include-master-host-port | 在--dump-slave产生的'CHANGEMASTER TO..'语句中增加'MASTER_HOST= |
--insert-ignore | 在插入行时使用INSERTIGNORE语句. |
--lines-terminated-by | 输出文件的每行用给定字符串划分。与--tab选项一起使用,不能用于--databases和--all-databases选项。 |
--lock-all-tables | 提交请求锁定所有数据库中的所有表,以保证数据的一致性。这是一个全局读锁,并且自动关闭--single-transaction和--lock-tables选项。 |
--lock-tables | 开始导出前,锁定所有表。用READLOCAL锁定表以允许MyISAM表并行插入。对于支持事务的表例如InnoDB和BDB,--single-transaction是一个更好的选择,因为它根本不需要锁定表。 请注意当导出多个数据库时,--lock-tables分别为每个数据库锁定表。因此,该选项不能保证导出文件中的表在数据库之间的逻辑一致性。不同数据库表的导出状态可以完全不同。 |
--log-error | 附加警告和错误信息到给定文件 |
--master-data | 该选项将binlog的位置和文件名追加到输出文件中。如果为1,将会输出CHANGEMASTER 命令;如果为2,输出的CHANGEMASTER命令前添加注释信息。该选项将打开--lock-all-tables选项,除非--single-transaction也被指定(在这种情况下,全局读锁在开始导出时获得很短的时间;其他内容参考下面的--single-transaction选项)。该选项自动关闭--lock-tables选项,0则为不记录 |
--max_allowed_packet | 服务器发送和接受的最大包长度。 |
--net_buffer_length | TCP/IP和socket连接的缓存大小。 |
--no-autocommit | 使用autocommit/commit语句包裹表。 |
--no-create-db | 只导出数据,而不添加CREAT DATABASE 语句。 |
--no-create-info | 只导出数据,而不添加CREAT TABLE 语句。 |
--no-data | 不导出任何数据,只导出数据库表结构。 |
--no-set-names | 等同于--skip-set-charset |
--opt | 等同于--add-drop-table,--add-locks, --create-options, --quick, --extended-insert, --lock-tables,--set-charset, --disable-keys 该选项默认开启, 可以用--skip-opt禁用. |
--order-by-primary | 如果存在主键,或者第一个唯一键,对每个表的记录进行排序。在导出MyISAM表到InnoDB表时有效,但会使得导出工作花费很长时间。 |
--order-by-primary |
如果存在主键,或者第一个唯一键,对每个表的记录进行排序。在导出MyISAM表到InnoDB表时有效,但会使得导出工作花费很长时间。 |
--password | 连接数据库密码,使用命名管道连接mysql |
--port | 连接数据库端口号 |
--protocol | 使用的连接协议,包括:tcp,socket, pipe, memory. |
--quick | 不缓冲查询,直接导出到标准输出。默认为打开状态,使用--skip-quick取消该选项。 |
--quote-names | 使用(`)引起表和列名。默认为打开状态,使用--skip-quote-names取消该选项。 |
--replace | 使用REPLACEINTO 取代INSERTINTO. |
--result-file | 直接输出到指定文件中。该选项应该用在使用回车换行对(\\r\\n)换行的系统上(例如:DOS,Windows)。该选项确保只有一行被使用。 |
--routines | 导出存储过程以及自定义函数。 |
--set-charset | 添加'SETNAMES default_character_set'到输出文件。默认为打开状态,使用--skip-set-charset关闭选项。 |
--single-transaction | 该选项在导出数据之前提交一个BEGINSQL语句,BEGIN不会阻塞任何应用程序且能保证导出时数据库的一致性状态。它只适用于InnoDB存储引擎。本选项和--lock-tables选项是互斥的,因为LOCKTABLES 会使任何挂起的事务隐含提交。要想导出大表的话,应结合使用--quick选项。 |
--dump-date | 将导出时间添加到输出文件中。默认为打开状态,使用--skip-dump-date关闭选项。 |
--skip-opt | 禁用–opt选项. |
--socket | 指定连接mysql的socket文件位置,默认路径/tmp/mysql.sock |
--tab | 为每个表在给定路径创建tab分割的文本文件。注意:仅仅用于mysqldump和mysqld服务器运行在相同机器上。 |
--tables | 覆盖--databases(-B)参数,指定需要导出的表名。 |
--triggers | 导出触发器。该选项默认启用,用--skip-triggers禁用它。 |
--tz-utc | 在导出顶部设置时区TIME_ZONE='+00:00',以保证在不同时区导出的TIMESTAMP数据或者数据被移动其他时区时的正确性。 |
--user | 指定连接的用户名。 |
--verbose | 输出多种平台信息。 |
--version | 输出mysqldump版本信息并退出 |
--where | 只转储给定的WHERE条件选择的记录。请注意如果条件包含命令解释符专用空格或字符,一定要将条件引用起来。 |
--xml | 导出XML格式. |
--plugin_dir | 客户端插件的目录,用于兼容不同的插件版本。 |
--default_auth | 客户端插件默认使用权限。 |
以上部分选项来自于Internet! |
ok!在对与mysqldump选项整理完后通过实例来看一下它是如何实现完成一个备份过程的;
六、示例
在开始之前需要说明一下:
示例过程中的系统为CentOS6.5_x86-64,mysql为10.0.10-MariaDB-log;
要想了解10.0.10-MariaDB请点击:"https://mariadb.com/kb/zh-cn/mariadb-mariadb-/"
1准备工作:
(1).将二进制日志文件与数据文件分离:
[root@MariaDB ~]# vim /etc/my.cnf #添加如下行: log-bin=/mydata/binlogs/maria-bin #二进制日志目录存放位置: [root@MariaDB ~]# mkdir /mydata/binlogs |
(2).将每个数据库的表空间独立出来:
#添加如下行: [root@MariaDB ~]# vim /etc/my.cnf innodb_file_per_table |
(3).创建一个专门存放示例过程当中的备份数据库目录:
[root@MariaDB ~]# mkdir /backups |
(4).首先导入一个底层存储引擎为Innodb的数据库作为示例使用:
#用的是刚安装好的MariaDB [root@MariaDB ~]# service mysqld start Starting MySQL.. [ OK ][root@MariaDB ~]# mysql < hellodb.sql |
(5).验证导入成功与否
[root@MariaDB ~]# mysql -uroot -p MariaDB [(none)]> SHOW DATABASES; 5 rows in set (0.00 sec) |
2、使用mysqldump实现备份恢复操作
(1).备份恢复单个库(热备)
#备份操作: [root@MariaDB ~]# mysqldump -uroot -hlocalhost -p --database hellodb --single-transaction --flush-logs > /backups/abc.sql Enter password: #模拟hellodb被误删除: [root@MariaDB ~]# mysql -uroot -p ........ ........ MariaDB [(none)]> \q #恢复操作: [root@MariaDB ~]# mysql -uroot -hlocalhost -p < /backups/hello.sql ........ ........ MariaDB [(none)]> USE hellodb; #OK!单库备份恢复结束! |
(2).手动请求全局锁备份恢复:
#请求全局锁: MariaDB [(none)]> FLUSH TABLES WITH READ LOCK; Query OK, 0 rows affected (0.00 sec) #滚动日志 MariaDB [(none)]> FLUSH LOGS; Query OK, 0 rows affected (0.01 sec) #日志滚动完后需要看一下当前使用的是那一个二进制日志文件,以后在恢复时只需要用到maria-bin.000005文件的365这个位置以后的文件就可以了! MariaDB [(none)]> #备份操作 [root@MariaDB ~]# mysqldump --databases hellodb --master-data=2 > /backups/hello2.sql #释放锁: [root@MariaDB ~]# mysql -uroot -p Enter password: ........ ........ MariaDB [(none)]> UNLOCK TABLES; MariaDB [(none)]> #模拟数据库删除: [root@MariaDB ~]# mysql -uroot -p ........ ........ Query OK, 7 rows affected (0.08 sec) #恢复操作 [root@MariaDB ~]# mysql -uroot -hlocalhost -p < /backups/hello.sql ........ ........ MariaDB [(none)]> USE hellodb; |
(3).多个库或指定库备份与上面使用相同方法即可;在此不做演示!
--all-databases: 备份所有库 --databases db1 db2 ...: 备份指定的多个库 |
(4).即时点备份还原
#来一次完整备份: [root@MariaDB ~]# mysqldump --databases hellodb --single-transaction --flush-logs --master-data=2 > /backups/hello3.sql #对hellodb进行操作: MariaDB [(none)]> USE hellodb; Database changed MariaDB [hellodb]> #模拟数据库删除: MariaDB [hellodb]> DROP DATABASE hellodb; #在备份的时候加入了--master-data=2这个选项,所以它能够在备份数据文件/backups/hello3.sql中查看备份出来的数据文件可以看到这样一行信息: -- CHANGE MASTER TO MASTER_LOG_FILE='maria-bin.000006', MASTER_LOG_POS=365; 这行信息记录了标记着我备份的那一刻是记录到哪个二进制文件的哪个位置,可是我的修改数据库操作是在这个点以后的,于是我们找到这个二进制文件并指定这个起始位置就可以恢复数据库误删之前的记录了: [root@MariaDB binlogs]# mysqlbinlog maria-bin.000006 | tail -15 #注意,在这个二进制文件的最后几行信息: #140401 13:10:35 server id 1 end_log_pos 655 Xid = 1617 # at 693 [root@MariaDB binlogs]# #恢复操作: [root@MariaDB binlogs]# mysqlbinlog --start-position=365 --stop-position=655 maria-bin.000006 > /backups/hello4.increment.sql #进入mysql,关闭二进制日志 [root@MariaDB binlogs]# mysql -uroot -p ........ ........ MariaDB [(none)]> SET SESSION sql_log_bin=0; //恢复过程中无需开启二进制文件; #导入数据: #先导入完整备份: MariaDB [(none)]> source /back/hello3.sql MariaDB [hellodb]> SHOW DATABASES; #此时新建的那张表还没有恢复回来 #导入增量备份: MariaDB [(hellodb)]> source /backups/hello4.increment.sql MariaDB [hellodb]> SHOW TABLES; 2 rows in set (0.00 sec) MariaDB [hellodb]> SET SESSION sql_log_bin=1; |
OK!至此mysqldump备份恢复实验完成!
小结:
(1)在真实环境下应当关闭其它用户的连接;在磁盘有足够容量的情况下尽量保存二进制文件;
(2)在备份恢复时对于数据库底层不同的存储引擎需使用正确的方式进行操作
备份策略:基于mysqldump
备份:mysqldump+二进制日志文件;
周日做一次完全备份:备份的同时滚动日志
周一至周六:备份二进制日志;
恢复:
完全备份+各二进制日志文件中至此刻的事件
对MySQL配置文件,以及与MySQL相关的OS配置文件在每次修改后都应该直接进行备份;
lvm-snapshot:基于LVM快照的备份
说明:
1.事务日志跟数据文件必须在同一个卷上;如下:
/dev/mapper/myvg-mylv1 on /mydata type ext4 (rw) /dev/mapper/myvg-mylv1 ext4 9.9G 325M 9.1G 4% /mydata [root@MariaDB ~]# ls /mydata/ binlogs data [root@MariaDB ~]# |
2.创建快照卷之前,要请求MySQL的全局锁;在快照创建完成之后释放锁;
3.请求全局锁完成之后,做一次日志滚动;做二进制日志文件及位置标记(手动进行);
备份恢复步骤:
1.请求全局锁,并滚动日志
[root@MariaDB ~]# mysql MariaDB [(none)]> FLUSH TABLES WITH READ LOCK; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> FLUSH LOGS; Query OK, 0 rows affected (0.05 sec) MariaDB [(none)]> |
2.做二进制日志文件及位置标记(手动进行);
[root@MariaDB ~]# mysql -e 'SHOW MASTER STATUS' > /backups/bininfo.txt |
3.创建快照卷
[root@MariaDB ~]# lvcreate -L 500M -s -n mydata-snap -p r /dev/myvg/mylv1 Logical volume "mydata-snap" created [root@MariaDB ~]# lvs | grep mylv1 mydata-snap myvg sri-a-s--- 500.00m mylv1 0.00 mylv1 myvg owi-aos--- 10.00g [root@MariaDB ~]# |
4.释放全局锁
MariaDB [(none)]> UNLOCK TABLES; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> |
5、挂载快照卷并备份
[root@MariaDB ~]# mount /dev/myvg/mydata-snap /mnt/ -o ro [root@MariaDB mnt]# cp -a data /backups/Backupdata-2014-04-01-14:53:16 |
6、备份完成之后,删除快照卷
[root@MariaDB ~]# umount /mnt/ [root@MariaDB ~]# lvremove /dev/myvg/mydata-snap Do you really want to remove active logical volume mydata-snap? [y/n]: y Logical volume "mydata-snap" successfully removed [root@MariaDB ~]# |
7.备份完成并解锁后创建数据库,创建表
[root@MariaDB mnt]# mysql MariaDB [(none)]> CREATE DATABASE db1; Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> USE db1; Database changed MariaDB [db1]> CREATE TABLE db_table1 (ID INT); Query OK, 0 rows affected (0.30 sec) MariaDB [db1]> INSERT INTO db_table1 VALUES (10),(20); Query OK, 2 rows affected (0.05 sec) Records: 2 Duplicates: 0 Warnings: 0 MariaDB [db1]> select * from db_table1; +------+ | ID | +------+ | 10 | | 20 | +------+ 2 rows in set (0.00 sec) MariaDB [db1]> |
8.模拟数据目录误删除
[root@MariaDB ~]# service mysqld stop Shutting down MySQL.. [ OK ] [root@MariaDB ~]# cd /mydata/data/ [root@MariaDB data]# rm -rf * [root@MariaDB data]# ls [root@MariaDB data]# |
9.恢复在第6步操作之前的数据
[root@MariaDB data]# cp -a /backups/Backupdata-2014-04-01-14\:53\:16/* ./ #此时二进制文件还存在的! |
10.查看在误删除数据目录内的文件之前的数据是否已经恢复
[root@MariaDB ~]# mysql -e 'SHOW DATABASES;' +--------------------+ | Database | +--------------------+ | hellodb | | information_schema | | mysql | | performance_schema | | test | +--------------------+ [root@MariaDB ~]# #新建的数据库"db1"不存在;于是只能依靠二进制文件进行恢复 |
11.依靠二进制日志文件进行恢复
[root@MariaDB ~]# cat /backups/bininfo.txt FilePosition Binlog_Do_DB Binlog_Ignore_DB maria-bin.000010 365 //在做备份时记录二进制日志文件及位置标记 [root@MariaDB ~]# mysqlbinlog --start-position=365 /mydata/binlogs/maria-bin.000010 | mysql [root@MariaDB ~]# |
12.验证恢复效果
[root@MariaDB ~]# mysql -e 'SHOW DATABASES;' +--------------------+ | Database | +--------------------+ | db1 | | hellodb | | information_schema | | mysql | | performance_schema | | test | +--------------------+ |
小结:
1.在备份时需将二进制日志保存好;
2.恢复数据时,如果备份文件中文件权限有改变则需修改权限及属主属组等
3.在任何备份恢复过后第一件事情就是做一次完整备份!