您的位置:首页 > 数据库 > MySQL

MySQL学习笔记之七:数据的备份和恢复

2016-03-21 17:31 791 查看
我们知道,数据是一个企业IT架构的核心,为了防止因某些意外原因造成数据遗失或其它一些特殊目的,在平时对数据做好备份尤其重要。

一、为什么要备份
1、灾难恢复:硬件故障、软件故障、自然灾害、黑客攻击、误操作等
2、审计:有时需要知道数据在过去某个时间点是什么样的
3、测试:一个最简单的其于实际数据来测试的方法是,定期用最新的生产环境数据更新测试服务器,只要把备份文件还原到测试服务器即可

二、备份和恢复需要注意的要点
1、可容忍丢失多少数据
2、恢复需要在多长时间内完成
3、需要恢复什么

三、备份类型:
1、完全备份和部分备份
部分备份:仅备份其中的一张表或多张表;
2、完全备份,增量备份,差异备份
增量备份:针对任意类型的上次备份后所有修改做的备份
差异备份:对上次完全备份后所有改变部分而做的备份
例如,每周日做一次完全备份,周一对自周日以来的所有改变做一次备份,在周二,就有两种选择:备份自周日以来的所有改变(差异),或只备份自周一后的所有改变(增量)。
3、热备份、温备份和冷备份
热备份:在线备份,读写操作不受影响;
温备份:在线备份,读操作可继续进行,但写操作不允许;
冷备份:离线备份,数据库服务器离线,备份期间不能为业务提供读写服务;
InnoDB支持热备,MyISAM只能支持到温备
4、物理备份逻辑备份
物理备份:直接复制原始文件的备份,其恢复速度比逻辑备份快很多
逻辑备份:从数据库中“导出”数据到MySQL能够解析的文件中,要么是sql文件,要么是以某个符号分隔的文本。
优点:
①与存储引擎无关,因为是从mysql服务器中提取数据而生成,所以消除了底层数据存储的不同
②可通过mysqldump实现灵活的备份定义
③可用文本处理工具(如sed,awk)对导出的文本文件进行二次加工;
④恢复过程简单,直接导入mysql程序即可
⑤可通过网络实现备份和恢复
缺点:备份文件可能比原文件大,压缩可解决此问题;无法保证恢复后的数据与原来完全相同;从逻辑备份中恢复需要mysql加载和解释语句,转化为存储格式,并重建索引,这些都需要消耗CPU,也较慢

四、规则备份时需要考虑的因素:
持锁的时长,备份过程时长,备份负载,恢复过程时长

五、备份什么
数据、额外的数据(二进制日志和InnoDB的事务日志)、代码(存储过程和存储函数、触发器、事件调度器等)、服务器配置文件

六、设计备份方案:完全备份+增量备份

七、备份方式及备份工具的选择
1、逻辑备份
⑴逻辑备份工具:mysqldump(常用), mydumper, phpMyAdmin
⑵常用备份方式:mysqldump+binlog
用mysqldump做完全备份,通过mysqlbinlog导出增加的二进制日志实现增量备份
例如:
mysqldump --lock-all-tables --all-dabases --flush logs -u bkpuser -h 192.168.30.10 > /backup/allbac-`date +%F`.sql #完全备份
mysqlbinlog /mydata/data/mysql-bin.000003 > /backup/incre-`date +%F`.sql #增量备份
mysqldump逻辑备份工具,适用于所有存储引擎,温备;完全备份,部分备份;对InnoDB存储引擎支持热备(利用MVCC机制实现),但不实用;
mysqldump将MySQL服务器中的数据库以标准的sql语言的方式导出,并保存到文件中。它是一个客户端工具,通过mysql协议连接至mysqld.
①三种用法: mysqldump [options] db_name [tbl_name ...]:备份单个库,或库中的一个或多个表 mysqldump [options] --databases db_name ...:备份一个或多个库 mysqldump [options] --all-databases:备份所有库 ②mysqldump db_name和mysqldump --databases db_name这两种用法的区别: 后者会在每个新数据库前的输出中插入CREATE DATABASE IF NOT EXISTS db_name和USE db_name,而前者不会,因此,如果是用前一种方式备份的,在恢复之前需要手动创建库 ③常用选项: -A, --all-databases:备份所有数据库(包括授权表) -B, --databases db_name1 db_name2 ...:备份指定的数据库 -x, --lock-all-tables:锁定所有表 -l, --lock-tables:当备份多个数据库时,--lock-tables分别为每个数据库锁定表。因此,该选项不能保证备份文件中的表在数据库之间的逻辑一致性。只建议在备份单张表时使用 --single-transaction:启动一个大的单一事务实现备份;要备份的表的存储引擎必须都是innodb,该选项才有效。热备,通过innodb的MVCC机制实现 --tables:覆盖---database或-B选项。选项后面的所有参量被看作表名 例:mysqldump --lock-all-tables --databases testdb --tables students -C, --compress:压缩传输,会增加CPU负载 --compact:去掉注释,适合调试输出 -u,--user:缺省为root -h, --host:缺省为localhost -p, --password ④其它选项: -F, --flush-logs:锁定表之后滚动日志,此选项要求RELOAD权限;建议使用该选项,方便做增量备份。 -E, --events:备份指定库的事件调度器; -R, --routines:备份存储过程和存储函数; --triggers:备份触发器 -d: 只备份库表结构,无数据 -t: 只备份数据,无库表结构
-T: 库表和数据分离,数据是文本形式
--master-data[=#]: 将备份那刻的二进制文件事件所处的位置记录于备份文件中 1:记录CHANGE MASTER TO语句;此语句未被注释; 2:记录为注释语句; ⑷SQL逻辑备份的缺点: Schema和数据存储一起、巨大的SQL语句、单个巨大的备份文件 ⑸逻辑备份的还原 与物理备份还原使用操作系统简单地复制文件到适当位置的方式不同,逻辑备份还原需要mysql服务器本身来加载
#先在数据库上创建一个专门用来备份的用户,并授予其相应权限,尽量遵从最小权限原则
MariaDB [(none)]> grant reload,lock tables,replication client on *.* to 'bkpuser'@'192.168.30.13' identified by 'secret';
Query OK, 0 rows affected (0.11 sec)

MariaDB [(none)]> show grants for 'bkpuser'@'192.168.30.13';
+------------------------------------------------------------------------------------------------------------------------------------------------------+
| Grants for bkpuser@192.168.30.13                                                                                                                     |
+------------------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'bkpuser'@'192.168.30.13' IDENTIFIED BY PASSWORD '*14E65567ABDB5135D0CFD9A70B3032C179A49EE7' |
+------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.07 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.10 sec)

MariaDB [(none)]> exit

#将二进制日志文件与数据分开,实际环境中在刚建立数据库服务器时就应如此
[root@node1 ~]# mkdir /mysql-binlog   #创建专门存放二进制日志文件的目录
[root@node1 ~]# chown mysql.mysql /mysql-binlog   #注意修改其属主属组和权限,否则服务进程无法写入
[root@node1 ~]# chmod --reference=/mydata/data /mysql-binlog
[root@node1 ~]# vim /etc/my.cnf
...
[mysqld]
...
log-bin = /mysql-binlog/mysql-bin   #在配置文件中修改二进制日志文件输出路径

[root@node1 ~]# service mysqld restart
Shutting down MySQL.. SUCCESS!
Starting MySQL. SUCCESS!
[root@node1 ~]# ls /mysql-binlog/   #可以看到,二进制日志已正常输出到新的目录下
mysql-bin.000001  mysql-bin.index
[root@node3 ~]# mkdir /backup   #在另一台主机上创建一个用于存放备份的目录
#连接远程主机执行完全备份
[root@node3 ~]# mysqldump --lock-all-tables --flush-logs --all-databases -u bkpuser -h 192.168.30.10 > /backup/allbac-`date +%F`.sql -p
Enter password:
[root@node3 ~]# ls /backup/
allbac-2016-02-24.sql
[root@node1 ~]# ls /mysql-binlog/
mysql-bin.000001  mysql-bin.000002  mysql-bin.index
#在数据库上做一些修改操作
MariaDB [(none)]> create database library;
Query OK, 1 row affected (0.06 sec)

MariaDB [(none)]> use library
Database changed

MariaDB [library]> create table book (CID tinyint unsigned not null auto_increment primary key,Category char(20) not null,Quantity int);
Query OK, 0 rows affected (0.19 sec)

MariaDB [library]> alter table book modify CID tinyint unsigned not null primary key;
ERROR 1068 (42000): Multiple primary key defined
MariaDB [library]> alter table book modify CID tinyint unsigned not null;
Query OK, 0 rows affected (0.21 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [library]> insert book value (1,'phplosophy',100);
Query OK, 1 row affected (0.02 sec)
#通过导出二进制日志做增量备份
[root@node3 ~]# mysql -e "flush logs" -u bkpuser -h 192.168.30.10 -p   #备份前滚动日志,方便以后再备份
Enter password:
[root@node3 ~]# mysqlbinlog -u bkpuser -h 192.168.30.10 --read-from-remote-server /mysql-binlog/mysql-bin.000002 > /backup/incre-`date +%F`.sql -p
Enter password:
ERROR: Could not find server version: Master reported unrecognized MySQL version '10.0.13-MariaDB-log'.
#错误提示:无法识别服务器端的MySQL版本。后确认为服务器端版本相较客户端上的mysql版本太新造成的;
于是更新了备份主机上的mysql版本
...
[root@node3 mysql]# mysqlbinlog -u bkpuser -h 192.168.30.10 --read-from-remote-server /mysql-binlog/mysql-bin.000002 > /backup/incre-`date +%F`.sql -p
Enter password:
ERROR: Got error reading packet from server: Access denied; you need (at least one of) the REPLICATION SLAVE privilege(s) for this operation
#又提示缺少 REPLICATION SLAVE 权限
#于是在数据库服务器上授予该权限
MariaDB [library]> grant replication slave on *.* to 'bkpuser'@'192.168.30.13' identified by 'secret';
Query OK, 0 rows affected (0.00 sec)

MariaDB [library]> flush privileges;
Query OK, 0 rows affected (0.00 sec)
[root@node3 mysql]# mysqlbinlog -u bkpuser -h 192.168.30.10 --read-from-remote-server /mysql-binlog/mysql-bin.000002 > /backup/incre-`date +%F`.sql -p
Enter password:
[root@node3 ~]# ls /backup   #备份成功
allbac-2016-02-24.sql  incre-2016-02-24.sql
MariaDB [(none)]> insert library.book value ('2','science',200);
Query OK, 1 row affected (0.48 sec)

MariaDB [(none)]> drop database hellodb;   #假设误删某个数据库
Query OK, 7 rows affected (0.25 sec)

#模拟还原
[root@node3 ~]# service mysqld stop   #立即停止数据库
[root@node3 ~]# vim /etc/my.cnf
[mysqld]
skip-networking   #限制网络访问

[root@node3 ~]# service mysqld start

MariaDB [(none)]> set global sql_log_bin = 'OFF';   #临时关闭二进制日志
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> \! scp root@192.168.30.13:/backup/* /tmp   #将备份主机上的备份复制过来
The authenticity of host '192.168.30.13 (192.168.30.13)' can't be established.
RSA key fingerprint is a3:d3:a0:9d:f0:3b:3e:53:4e:ee:61:87:b9:3a:1c:8c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.30.13' (RSA) to the list of known hosts.
root@192.168.30.13's password:
allbac-2016-02-24.sql                                 100% 1832     1.8KB/s   00:00
incre-2016-02-24.sql                                  100% 3108     3.0KB/s   00:00

MariaDB [(none)]> \! ls -l /tmp/*.sql   #确保mysql服务进程能够读取
-rw-r--r-- 1 root root 1832 Mar  5 00:39 /tmp/allbac-2016-02-24.sql
-rw-r--r-- 1 root root 3108 Mar  5 00:39 /tmp/incre-2016-02-24.sql

MariaDB [(none)]> \! mysqlbinlog /mysql-binlog/mysql-bin.000003 | less   #查看误操作的起始位置
...
# at 403
#160304 22:36:16 server id 1  end_log_pos 560   Query   thread_id=10    exec_time=0     error_code=0
SET TIMESTAMP=1457102176/*!*/;
SET @@session.pseudo_thread_id=10/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
...skipping...
drop database hellodb
...
MariaDB [(none)]> \! mysqlbinlog --stop-position=403 /mysql-binlog/mysql-bin.000003 > /tmp/change.sql  #只导出误操作之前的二进制日志

MariaDB [(none)]> source /tmp/allbac-2016-02-24.sql   #执行导入操作
...
MariaDB [(none)]> source /tmp/incre-2016-02-24.sql
...
MariaDB [(none)]> source /tmp/change.sql
...
MariaDB [(none)]> show databases;   #删除的数据库已恢复
+--------------------+
| Database           |
+--------------------+
| hellodb            |
| information_schema |
| library            |
| mysql              |
| performance_schema |
| test               |
| testdb             |
+--------------------+
7 rows in set (0.14 sec)

MariaDB [(none)]> set global sql_log_bin = 'ON';   #重开二进制日志
Query OK, 0 rows affected (0.00 sec)

[root@node3 ~]# vim /etc/my.cnf
[mysqld]
#skip-networking   删除该项,以正常模式重启

[root@node3 ~]# service mysqld restart
#恢复完毕后应立即做一次完全备份
[root@node3 ~]# mysqldump --lock-all-tables --flush-logs --all-databases -u bkpuser -h 192.168.30.10 > /backup/allbac-`date +%F-%R`.sql -p
Enter password:


2、物理备份
⑴mysqlhotcopy:使用lock tables、flush tables和cp或scp来快速备份数据库,是备份数据库或单个表最快的途径,属于物理备份;几乎冷备;仅适用于MyISAM存储引擎
xtrabackup:对InnoDB支持热备,完全备份和增量备份;对MyISAM引擎支持温备,完全备份。详见博客http://9124573.blog.51cto.com/9114573/1754925
使用cp, tar,rsync等文件系统工具直接复制文件:适用于所有存储引擎;冷备;完全备份,部分备份;
注意:用文件系统工具直接复制文件的方法做备份,为保证数据时间点的一致性,需要冷备,但是,实际环境中因业务访问的需要,可能不允许服务离线,这种情况下,可做主从,当需要备份时,让从服务器离线,备份从服务器上的数据,备份完毕后让其上线,从服务器会继续同步主服务器上的数据
对于部分备份和还原,如果是MyISAM表,直接复制对应的.frm、.MYI、MYD文件即可;如果是InnoDB表,使用这种方式备份有可能会出错,即使设置了innodb_file_per_table的特性。
lvm2快照几乎热备,借助于文件系统工具实现物理备份;前提是原始数据要位于逻辑卷上
完全备份:
①请求锁定所有表:
mysql> FLUSH TABLES WITH READ LOCK;
②记录二进制日志文件及事件位置或者滚动日志
mysql> SHOW MASTER STATUS;
或mysql -e 'show master status' > /backup/pos
或mysql > FLUSH LOGS;
③创建快照:
lvcreate -L SIZE -s -p r -n NAME /dev/VG_NAME/LV_NAME
-p, --permission: 给快照设置访问权限
④释放锁:
mysql> UNLOCK TABLES;
⑤挂载快照卷,复制数据进行备份;
cp, rsync, tar等命令复制数据
⑥备份完成之后删除快照卷
增量备份:使用mysqlbinlog导出增加的二进制日志
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.12 sec)

MariaDB [(none)]> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000005 |      365 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.03 sec)

MariaDB [(none)]> \! lvcreate -s -L 200M -n mydata_snap -p r /dev/myvg/mydata   #创建快照
File descriptor 3 (socket:[520415]) leaked on lvcreate invocation. Parent PID 28368: mysql
Logical volume "mydata_snap" created
MariaDB [(none)]> unlock tables;   #解锁
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> exit
Bye
[root@node1 ~]# mount /dev/myvg/mydata_snap /mnt   #挂载快照
mount: block device /dev/mapper/myvg-mydata_snap is write-protected, mounting read-only
[root@node1 ~]# ls /mnt
data  lost+found
[root@node1 ~]# ls /mnt/data
aria_log.00000001  hellodb  ib_logfile0  library            mysql             mysql-bin.000002  mysql-bin.state  node1.pid       performance_schema  testdb
aria_log_control   ibdata1  ib_logfile1  multi-master.info  mysql-bin.000001  mysql-bin.index   node1.err        node1-slow.log  test
[root@node1 ~]# rsync -a /mnt/data/ root@192.168.30.13:/backup/mysqlbac-`date +%F`   #将数据同步到存放备份的主机上
root@192.168.30.13's password:
[root@node3 ~]# ls /backup   #备份成功
mysqlbac-2016-03-05 ...
增量备份同上,这里不再赘示

#还原物理备份
[root@node1 ~]# rm -rf /mydata/data/*   #模拟数据丢失
[root@node1 ~]# killall -9 mysqld    #关闭服务进程
[root@node1 ~]# service mysqld status
ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists
[root@node1 ~]# rsync -a root@192.168.30.13:/backup/mysqlbac-2016-03-05/ /mydata/data   #将数据恢复至数据目录
root@192.168.30.13's password:
[root@node1 ~]# ls /mydata/data
aria_log.00000001  hellodb  ib_logfile0  library            mysql             mysql-bin.000002  mysql-bin.state  node1.pid       performance_schema  testdb
aria_log_control   ibdata1  ib_logfile1  multi-master.info  mysql-bin.000001  mysql-bin.index   node1.err        node1-slow.log  test
[root@node1 ~]# ll /mydata/data
total 110680
-rw-rw---- 1 mysql mysql    16384 Mar  4 18:03 aria_log.00000001
-rw-rw---- 1 mysql mysql       52 Mar  4 18:03 aria_log_control
drwx------ 2 mysql mysql     4096 Mar  5 00:45 hellodb
-rw-rw---- 1 mysql mysql 12582912 Mar  4 23:29 ibdata1
-rw-rw---- 1 mysql mysql 50331648 Mar  4 23:29 ib_logfile0
-rw-rw---- 1 mysql mysql 50331648 Feb 28 01:42 ib_logfile1
...
[root@node1 ~]# service mysqld start   #启动服务
Starting MySQL........ SUCCESS!
[root@node1 ~]# mysqlcheck --all-databases   #检查修复所有表
library.book                                       OK
mysql.column_stats                                 OK
mysql.columns_priv                                 OK
mysql.db                                           OK
mysql.event                                        OK
mysql.func                                         OK
...


八、注意事项
将数据和二进制文件放置于不同的设备(至少要位于不同的磁盘);二进制日志也应该周期性地备份
将数据和备份分开存放,建议不在同一设备、同一主机、同一机房、同一地域;
每次灾难恢复后都应该立即做一次完全备份
⑷备份后的数据应该周期性地做还原测试;
⑸备份脚本化

九、从备份中恢复应该遵循的步骤
①停止MySQL服务器;
②记录服务器配置和文件权限;
③将备份恢复到MySQL数据目录;此步骤依赖具体的备份工具;
④确保恢复的文件在正确的归属和权限;
⑤以限制访问模式启动MySQL服务器:比如通过网络访问;
[mysqld]
skip-networking
socket=/tmp/mysql-recovery.sock
⑥载入额外的逻辑备份;检查和重放二进制日志;
注意:还原逻辑备份(包括重放二进制日志)是需要mysql服务器本身来加载数据到表中,会产生重复的二进制日志,因此,在这个过程中禁掉二进制日志是个不错的主意,还原完毕后再打开即可
例如:mysql > SET session sql_log_bin = 0;
mysql > SOURCE backup.sql;
mysql > SET session sql_log_bin = 1;
检查已经还原的数据(mysqlcheck);
⑧以完全访问模式重启服务器;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mysqldump