MySQL/MariaDB的数据备份与恢复
1. 什么是数据备份与数据恢复?
1) 数据备份:已有数据的副本;
2) 数据恢复:将副本和二进制日志的内容重新应用到线上系统;
2. 为什么要进行数据备份与恢复?
主要用于防止灾害的发生,可进行灾难恢复,有多种灾难可能对数据造成破坏:如:自然灾害,
hacker attack,计算机本身硬件老化,软件故障(如:BUG,恶意代码等),操作人员误操作(如:误删除);
3. 备份有哪些类型?
按照是否备份整个数据集分类:
1)全局备份 :备份从起始到执行备份操作时的所有数据内容;
2)增量备份 :备份从上一次完全备份或增量备份以来变化的数据;
3)差异备份 :备份从上一次完全备份以来变化的数据;
按照备份的数据库对象分类:
1)物理备份 :通过复制数据文件进行数据备份;
2)逻辑备份 :在数据库的操作接口上利用SQL语句,脚本或应用程序将数据零存在一个或多个文件中;
按照备份时是否能够提供服务分类:
1)热备份 :在数据读写均可进行的状态下进行的备份操作;
2)温备份 :在数据可读不可写的状态下进行的备份操作;
3)冷备份 :在数据读写皆不可进行(服务离线)的状态下进行的操作;
4. MySQL/MariaDB提供的备份工具:
1)SELECT语句(导出数据)和LOAD DATA语句(导入数据);
2)mysqldump命令(mysql自带的备份工具); 注意:备份时,MySQL服务需在线;
3)cp/scp/dd/tar/cpio命令;
4)lvm2或Btrfs快照;
5)mysqlhotcopy命令(不常用,即将废弃);
6)Percona Xtrabackup工具;
1)利用SELECT语句和LOAD DATA语句导入导出数据:
SELECT语句语法:
SELECT [INTO OUTFILE 'file_name'[CHARACTER SET charset_name] export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]
LOAD DATA语句语法:
LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[CHARACTER SET charset_name]
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number {LINES | ROWS}]
[(col_name_or_user_var,...)]
[SET col_name = expr,...]
1. FIELDS [TERMINATED BY 'string']: 用于指定导入或导出时的字段分隔符;
2. FIELDS [[OPTIONALLY] ENCLOSED BY 'char']:用于指定导入或导出时的字段引用符号;
如果指定看OPTIONALLY,则只用在字符串和日期时间类型的数据字段上;默认未指定;
3. FILEDS [ESCAPED BY 'char']:指定转义字符;
4. LINES [STARTING BY 'string']:指定行的起始符号,默认未定义;
5. LINES [TERMINATED BY 'string']:指定行的结束分隔符,默认是“\n”;
注意:
‘char’表示只能使用一个字符,‘string’表示可指定多个字符;
一般情况下,SELECT语句和LOAD DATA语句是配套使用的,SELECT按照一定规则检索出数据至指定文件中,
LOAD DATA语句将SELECT导出的数据重新导入数据库:
前提:建议将二进制日志的功能开启
]# vim /etc/my.cnf
[mysqld]
log_bin=binlog
示例;
MariaDB [hellodb]> select * from hellodb.students into outfile "students.bak" lock in share mode;
将hellodb数据库中的students数据表导出到名为students.bak的文件中,导出过程中将表锁定;
锁定的目的是防止在导出表的过程中有其他会话对表进行修改,导致数据变化,前后数据不一致;
students.bak文件默认存储在数据目录(/var/lib/mysql)下;
MariaDB [(none)]> truncate hellodb.students; ... MariaDB [(none)]> select * from hellodb.students; Empty set (0.00 sec)
假如students数据表被误删除,检索发现为空表;
MariaDB [(none)]> load data infile "/var/lib/mysql/students.bak" into table hellodb.students; MariaDB [(none)]> use hellodb; MariaDB [hellodb]> select * from students; 。。。。 27 rows in set (0.00 sec)
将hellodb数据库中被误删除的students数据表重新导入hellodb数据库,完成后,检索存在;
这样就完成了一次数据的备份与恢复操作;
2)mysqldump命令:
用于导出数据库或数据库中的数据集,并可以在其它的非MySQL数据库中进行导入,因此,也可用来做数据迁移;
格式: mysqldump [options] [db_name [tbl_name ...]]
shell> mysqldump [options] db_name [tbl_name ...]
shell> mysqldump [options] --databases db_name ...
shell> mysqldump [options] --all-databases
常用选项:
连接选项: -u , -h ,-p ,-P , -S , --protocol ;
筛选选项:
--all-databases, -A
指定mysqldump备份所有的数据库;
--databases, -B
指定需要备份的数据库;一旦写上此选项,则该选项后面的所有内容都被当成数据库名称,
而且在输出的文件中,每个数据库前都会加上创建数据库和use语句;
--ignore-table=db_name.tbl_name
导出时忽略指定的数据库中的指定表,同时也可以用户忽略视图;每个此选项仅能带一个参数,
因此想要忽略多个表则需给出多个此选项;
--no-data, -d
在备份时不导出任何数据内容,仅导出表结构;
--routines, -R
导出存储函数和存储过程,但不会导出他们的属性值;
--events, -E
导出事件调度器
--triggers
导出触发器,默认开启,想要关闭可以使用--skip-triggers选项;
--tables
覆盖了--databases选项,使得其后面所有的参数都被当做表名处理;使用了此选项,
每次mysqldump仅能导出一个库中表的数据;
格式为:--tables db_name tbl_name1 tbl_name2......--where=′where_condition′, -w ′where_condition′
指定筛选条件并导出表中符合筛选条件的数据;
如:--where='Name=james'
DDL选项:
--add-drop-database
在导出的数据文件中的每一个create databases语句前加上drop database if exists的语句先删除指定的数据库;
--add-drop-table
在导出的数据文件中的每一个create tables语句前加上drop database if exists的语句先删除指定的表,
默认开启此功能;
--no-create-db, -n
在使用了--databases或--all-databases选项时,在导出的文件中加会加上创建数据库的语句;而一旦使用此选项,
前面两个选项功能会被抑制;
--no-create-info, -t
不会在导出的文件中添加创建表的语句;
--replace
所有向表中添加数据的操作语句均被替换成REPLACE语句,而不是INSERT语句;
字符集选项:
--default-character-set=charset_name
在导出数据的过程中,指定导出时使用的字符集;
此选项有时很重要,迁移数据的目标主机上和当前服务器的字符集如果不相同,可能会导致乱码,
默认为“utf8”;
--set-charset
在导出的数据结果中加上SET NAMES statement语句,默认此功能开启;关闭可使用的选项:
--skip-set-charset;
与主从复制相关的选项
--delete-master-logs
在执行了一次dump操作后,会向主服务器发送一个PURGE BINARY LOGS statement,
以删除其二进制日志;并会自动激活--master-data选项的功能;
--master-data[=value]
该选项主要用来建立一个复制操作;
值为1时,导出的数据文件中会记录CHANGE MASTER语句;
值为2时,导出的数据文件中会记录CHANGE MASTER语句;但该语句被注释;默认值无任何值,
意味着在导出的数据文件中不会记录CHANGE MASTER语句;
在使用此选项时,会自动忽略--lock-tables选项;
当使用了--single-tranaction选项时,也会自动激活--lock-all-tables;
格式化选项:
--compact
紧凑格式输出,即:简化输出的内容,几乎所有的注释类内容都不会被输出到文件中;
相当于: --skip-add-drop-table, --skip-add-locks, --skip-comments,--skip-disable-keys,
--skip-set-charset 选项的组合;
--complete-insert, -c
在INSERT语句中加入各个被操作的列的名称;
--tab=path, -T path
将每个表的结构定义用的SQL语句和表中存储的数据内容,分别导出到指定的目录中,
使用不同的文件进行保存;其中TBL_NAME.sql文件存放表的定义格式,
TBL_NAME.txt文件存放表中的数据;在导出数据内容的时候,相当于
使用了SELECT ... OUTFILE 'tbl_name.txt'语句,默认的字段分隔符就是“\t”;
使用此选项操作时,必须要有一个前提条件:client和server必须是同一台主机,
且mysql用户对指定的目录要有写权限,同时连接数据库的用户必须有FILE权限;
而且还要求不能和--databases或--all-databases选项一起使用;
--fields-terminated-by=..., --fields-enclosed-by=..., --fields-optionally-enclosed-by=..., --fields-escaped-by=...,
--lines-terminated-by=... 选项可以在此时应用,用于指定各种分隔符;
--quote-names, -Q
引用表名或列名时,使用任何引用符号,默认的引用符号为反向单引号,即`;
性能选项:
--delayed-insert
在非事务型存储引擎管理的表中,在INSERT操作时可支持DELAYED功能;在MySQL5.6.6开始被废弃;
--disable-keys, -K
在INSERT语句前后加上禁用和启用索引的语句;
在大量的数据插入时,此选项很有用,默认是开启的;
--insert-ignore
使用INSERT IGNORE语句代替INSERT语句;
--quick, -q
快速导出数据,在导出大表时非常有用;
默认导出数据时会一次性检索表中所有数据并加入到内存中,而使用该选项则是检索一行导出一行;
加锁和事务有关的选项:
--add-locks
在INSERT语句前后加上LOCK TABLES和UNLOCK TABLES语句,默认开启;
--flush-logs, -F
在开始导出数据前事先刷写二进制日志(二进制日志手动的滚动);
如果使用了--all-databases选项,则依次在各个数据库之前都会执行FLUSH LOGS;
如果使用 --lock-all-tables 或 --master-data选项,则刷写日志仅执行一次,等价于FLUSH TABLES WITH READ LOCK,
锁定所有表,保证数据一致性;
--flush-privileges
在导出所有数据库之后在数据文件的结尾加上FLUSH PRIVILEGES语句;
一般会在导出mysql库或者依赖于mysql库时都应该使用此选项;
--lock-all-tables,
为所有的表施加一个一直持续到数据导出结束的全局读锁。该选项仅在数据导出开始时施加一次读锁,
而该读锁锁定所有表,直到数据导出结束后才会释放;
该选项开启后会自动关闭--single-transaction and --lock-tables选项;
--lock-tables, -l
在导出每个数据库的数据之前依次对该数据库中所有表施加读锁(多次的锁施加的过程),
对于非事务型的存储引擎(如:MyISAM)的表可以进行并行锁操作;但对于事务型存储引擎
(如:InnoDB)的表来说,使用--single-tranaction选项更好, 因为InnoDB无需完全读锁;
--single-transaction
该选项在导出数据前将设置一个事务,且隔离级别为REPEATABLE-READ,
并且同时发送一个START TRANSACTION语句给服务器端;
该选项在导出InnoDB存储引擎的表时非常有用,一旦开启事务,则意味着数据库会有一致性和持久性的安全保护,
不会阻塞任何其它会话或线程的数据处理;
--no-autocommit
在INSERT语句前后加上SET @@autocommit=0及SET @@autocommit=1语句,
并且在需要提交事务时添加COMMIT语句;
--order-by-primary
如果被导出的表中存在主键索引或唯一键索引,则排序后按照顺序导出数据;
对于导出MyISAM表比导出InnoDB表更有用;
示例:
新建一个目录用于存放备份的数据:
[root@bogon ~]# mkdir /mysql-bak
对数据库hellodb进行备份:
[root@bogon ~]# mysqldump --single-transaction --flush-logs --master-data=2 --databases hellodb > /mysql-bak/hellodb1.sql [root@bogon ~]# mysqldump --single-transaction --flush-logs --master-data=1 --databases hellodb > /mysql-bak/hellodb2.sql [root@bogon ~]# mysqldump --single-transaction --flush-logs --master-data=0 --databases hellodb > /mysql-bak/hellodb3.sql
对三个文件进行对比:--master-data=0时没有下图语句;
[root@bogon ~]# vim /mysql-bak/hellodb1.sql
[root@bogon ~]# vim /mysql-bak/hellodb2.sql
如果hellodb数据库因某些因素遭到破坏:
MariaDB [hellodb]> drop databases hellodb;
恢复数据:
MariaDB [hellodb]> set @@sql_log_bin=0; MariaDB [hellodb]> \. /mysql-bak/hellodb1.sql MariaDB [hellodb]> set @@sql_log_bin=1;
检测是否恢复成功:
数据库恢复成功;
注意:使用mysqldump备份MyISAM表的时候,需要加上--lock-tables选项,以保证数据一致性;
如果使用--lock-all-tables,一次性锁定所有表,影响的范围比较大;
mysqldump使用的建议:
1.从性能考虑:
在需要导出大量数据的时候,建议使用--quick选项加速数据导出,但导入速度不变。
如果导入的是innodb存储引擎的表中的数据,加上--no-autocommit选项,可以极大的提高性能;
2.从数据一致性角度考虑:
对于innodb表,必选的选项是--single-transaction,对于MyISAM表,使用--lock-tables是必须的,
但有时使用--lock-all-tables速度更快;
既有MyISAM表又有InnoDB表时,可以分别导出;这样既能保证数据一致性,又可以保证数据导出的效率;
3.从方便管理和方便维护角度考虑:
在任何数据导出之前,FLUSH LOGS都非常有必要,需要加上--flush-logs选项;
同时会根据导出的数据表使用的存储引擎的不同,配合添加--lock-all-tables或--single-transaction选项;
如果有主从关系,主服务器上的数据导出是为了从服务器上数据快速同步,需要使用--master-data=2,
这样就可以方便地知道二进制日志中应用到了哪个二进制日志文件的哪个位置坐标,可以方便定位;
4.从字符集兼容角度考虑:
如果表中涉及到了中文字符,在导出日志时,一定要设置字符集与该表的字符集一样,
以避免mysqldump使用其默认的字符集, 使得数据恢复后出现乱码;
5.其它因素:
导出数据的过程中和恢复数据的过程中都会产生二进制日志,但现在这样的二进制日志是多余没必要的。
应该在操作之前,关闭二进制日志记录功能,完成之后再开启;
3)基于lvm2或btrfs的快照卷实现数据备份:
准备操作:给系统添加一块硬盘,并重读磁盘,让其生效:
[root@bogon ~]# echo '- - -' /sys/class/scsi_host/host0/scan
1. 创建一个目录/data/mydata用作MySQL的数据目录
并将源数据目录下的所有内容复制到该目录:
[root@bogon ~]# mkdir -pv /data/mydata [root@bogon ~]# chown -R mysql:mysql /data/mydata [root@bogon ~]# cp -a /var/lib/mysql/* /data/mydata [root@bogon ~]# systemctl stop mariadb.service [root@bogon ~]# vim /etc/my.cnf [mysqld] datadir=/data/mydata socket=/data/mydata/mysql.sock ... [root@bogon ~]# setenforce 0 [root@bogon ~]# systemctl start mariadb.service
2.创建物理卷,卷组及逻辑卷,并将逻辑卷格式化并挂载至/data/mydata:
[root@bogon ~]# pvcreate /dev/sdb [root@bogon ~]# vgcreate -s 20M myvg /dev/sdb [root@bogon ~]# lvcreate -L 10GiB -n mydata myvg [root@bogon ~]# mkfs -t ext4 /dev/myvg/mydata [root@bogon ~]# mount /dev/myvg/mydata /data/mydata
3. 施加全局读锁,保证数据一致性:
MariaDB [hellodb]> flush tables with read lock;
4. 记录二进制日志最后一个事件结束的位置标志并让日志滚动:
MariaDB [hellodb]> flush logs;
5.创建快照卷
[root@bogon ~]# lvcreate -L 200M -s -p r -n mydata_snapshot /dev/myvg/mydata
6.释放全局读锁:
MariaDB [hellodb]> unlock tables;
7. 创建挂载点,将快照挂载:
[root@bogon ~]# mkdir /mnt/mydata [root@bogon ~]# mount /dev/myvg/mydata_snapshot /mnt/mydata
8. 拷贝快照卷内容至指定目录并卸载逻辑卷:
[root@bogon mysql]# mkdir /ytc [root@bogon mysql]# cp -a /mnt/mydata/* /ytc/ [root@bogon mysql]# umount /mnt/mydata
9.暴力删除数据内容:
停止服务,摘除磁盘,卸载逻辑卷
[root@bogon mysql]# systemctl stop mariadb [root@bogon mysql]# umount /data/mydata
10.恢复数据,并启动服务:
[root@bogon mysql]# cp -a /ytc/* /data/mydata/ [root@bogon mysql]# chown -R mysql:mysql /data/mydata/ [root@bogon mysql]# systemctl start mariadb.service
4)使用XtraBackup工具完成数据的备份和恢复:
Xtrabackup备份的原理:
备份:backup,使用物理备份方式,复制文件系统中的与指定库或指定表相关的文件;
注意:xtrabackup在备份时,先备份InnoDB的表,再备份其他非InnoDB的表;
准备:prepare,由于备份的时候复制走的数据文件可能存在不一致数据,通过此阶段保证数据一致;
恢复:copy back,用备份的结果集和对应的二进制日志文件恢复被损坏或丢失的数据内容;
安装xtrabackup:
[root@bogon ~]# yum install percona-xtrabackup
使用xtrabackup工具进行数据备份和恢复:
innobackupex命令(xtrabackup)
用法:innobackupex | xtrabackup [--defaults-file=#] { --backup | --prepare | --copy-back } [Options] [Args]
常用选项:
连接选项:
--user=USERNAME
--host=HOSTNAME
--port=PORT
--password=PASSWORD
--socket=SOCKET_FILE_NAME
功能选项:
--backup:实施数据备份过程;
--prepare:实施准备过程;
--copy-back:实施数据恢复过程;
--apply-log:在准备过程中,用于应用redo log;
--redo-only:在准备过程中,仅应用redo log;
--incremental:在数据备份的过程中,实施增量备份;
--incremental-basedir:在实施增量备份时,用于指定增量备份的参考目录;
完全备份:
除了必须给定连接MySQL服务所需要的连接选项,通常只需要给定一个备份的目标目录即可;
语法:
innobackupex --user=USER --host=HOST --password=PASSWORD
--socket=PATH_TO_SOCK_FILE /PATH/TO/BACKUP_DESTINATION_DIR
示例:
创建一个目录/ytc1/backup用来做备份目录:
[root@bogon ~]# mkdir -pv /ytc1/backuo
备份:
[root@bogon ~]# innobackupex --socket=/var/lib/mysql/mysql.sock /ytc1/backup
查看:
恢复操作:
关闭服务后,将拷贝的数据拷贝回来即可,最后开启服务;