MariaDB备份与恢复
[toc]
本文基于马哥的linux运维课程视频, 结合自己在实验的过程中归纳整理所著, 在此致谢马哥!
基础概念
注意点:
- (1) 做还原测试, 用于测试备份的可用性
- (2) 还原演练
备份类型: 完全备份, 部分备份
热备份, 温备份, 冷备份:
- 热备: 读写操作均可执行
- 温备: 可读不可写
- 冷备: 读写均不可
innodb支持热备, MyISAM支持温备, 不能热备
物理备份, 逻辑备份:
- 物理备份: 直接复制数据文件进行备份 (占用更多空间但速度快, 不需要专用工具)
- 逻辑备份: 从数据库中"导出"数据另存而进行的备份 (需要特定的客户端工具, 会丢失数据精度且可能更占用空间, 但与存储引擎无关)
备份时需要考虑的因素:
持锁多久
备份过程的时长
备份时是否会增加线上负载
恢复过程的时长
备份内容 (注意不要将备份内容和原始数据放在同一块硬盘中, 最好不同主机):
- 数据
- 二进制日志 (注意一定要记录正在使用的二进制日志的文件名及事件位置!), InnoDB的事务日志
- 服务器的配置文件
- 代码 (存储过程, 存储函数, 触发器, 事件调度器)
设计备份方案:
- 物理备份还是逻辑备份?
- 冷备还是热备?
- 完全备份还是增量备份? 一般使用"完全 + 增量"的方式进行
备份工具:
-
mysqldump
: 逻辑备份工具, 适用于所有存储引擎, 支持温备但不支持热备, 支持完全备份和部分备份, 对InnoDB存储引擎支持热备 -
cp, tar
等复制归档工具: 物理备份工具, 适用于所有存储引擎, 但只能进行冷备, 支持完全备份和部分备份 -
lvm
的快照: 几乎热备 (请求施加一个全局读锁, 待持锁成功后立即拍快照, 然后释放锁, 一般请求迅速时1s - 5s即可), 需要借助文件系统管理工具进行备份 -
mysqlhotcopy
: 几乎冷备, 仅适用于MyISAM存储引擎
备份工具的选择:
-
mysqldump + 复制binlog
- 先通过mysqldump做完全备份, 再复制binlog中指定时间范围的event (增量备份)
- 时间慢但可远程备份
-
lvm2快照 + 复制binlog
- 先使用cp或tar等做物理备份 (完全备份), 再复制binlog中指定时间范围的event (增量备份)
-
xtrabackup
- 开源, 由Percona提供的支持对InnoDB做热备(物理备份)的工具
- 支持完全备份和增量备份
备份和恢复
1. 逻辑备份工具: mysqldump, mydumper, phpMyAdmin
- 原理: 将Schema和和数据存储在一起, 导出一个巨大的SQL语句, 是一个巨大的备份文件, 这个文件比较小的时候可直接使用cat等命令查看
- mysqldump: 客户端命令, 通过mysql协议了解至mysqld服务器
mysqldump [options] [db_name [tbl_name ...]]
shell> mysqldump [options] db_name [tbl_name ...] # 不会自动创建database语句
shell> mysqldump [options] --databases db_name ... # 会自动创建database语句
shell> mysqldump [options] --all-databases # 会自动创建database语句
mysqldump -uroot --databases hellodb mydb > /tmp/alldb_bak.sql
# 特别注意!
# MyISAM: 支持温备, 因此需要先锁定备份库, 然后启动备份操作
# 锁定方法:
--lock-all-tables, -x # 备份前锁定所有数据库中所有表, 用于备份整个数据库, 使用此选项一定要慎重!
--lock-tables, -l # 备份前锁定要备份的那个库的所有表, 用于备份单个数据库
# 对InnoDB一样生效, 但只能实现温备
# InnoDB: 支持热备
--single-transaction # 启动一个巨大的事务
# 其它选项:
-E, --events # 备份与指定数据库相关的所有事件调度器
--routines, -R # 备份与指定数据库相关的所有存储过程或存储函数
--triggers # 备份与指定数据库相关的所有触发器, 默认启用
--master-data[=value] # 值可设定为0/1/2等, 记录正在使用的二进制日志的文件名及事件位置, 当值设为2时, 会保存一个已被注释的CHANGE MASTER TO语句, 此语句记录了开始被备份时事件处于哪个二进制文件的哪个position, 此position之前的内容会被备份
# 0: 不启用
# 1: 记录为CHANGE MASTER TO语句, 此语句不被注释
# 2: 记录为CHANGE MASTER TO语句, 此语句被注释
# -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=245;
--flush-logs # 锁定表完成后, 执行FLUSH LOGS命令, 对二进制日志进行日志滚动操作
1.1 mysql备份与结合二进制日志做时间点还原
注意还原时会产生大量的二进制日志, 而这些日志是我们不需要的, 此时最好关闭二进制日志的记录功能: SET sql_log_bin=OFF
或SET sql_log_bin=0
, 等待还原完成后再开启此功能: SET sql_log_bin=ON
需要的文件:
- 全量备份后的all.sql文件
- 所有的二进制日志文件
shell> mysqldump -uroot --master-data=2 --all-databases --lock-all-tables > all.sql # 再次强调, 使用--lock-all-tables选项一定要慎重!
shell > mysql -uroot -p # 先对数据库中某些表进行一些操作后, 假如此时服务器正好宕机, 接下来就需要恢复数据
shell> less all.sql # 查看日志文件从什么位置开始备份, 假如MASTER_LOG_POS=245, 也就是说245之前的内容已经被备份, 而245之后的数据只有二进制日志中有SQL记录, 而需要恢复成宕机前但数据已经过修改的样子, 就需要从二进制日志中导出备份后数据库执行的SQL语句
shell> mysqlbinlog --start-position=245 mysql-bin.000002 > incre.sql
shell> mysql -uroot -p < all.sql # 先还原备份时数据库的数据
shell> mysql -uroot -p < incre.sql # 在还原备份后数据库被修改的数据
生产环境中如果数据量不大, 可以使用mysqldump
每周做一次全量备份, 每半天(或者每一天)通过复制二进制文件做一次增量备份(先FLUSH LOGS
, 然后将中间的二进制日志文件复制出来), 之后如果数据库宕机, 恢复数据就可以先恢复全量数据, 然后再依次恢复每半天(或者每一天)的增量数据就可以了.
# 实例:
# 0. 连入数据库查看此时使用的二进制日志文件
SHOW BINARY LOGS;
SHOW MASTER STATUS; # 假如此时正在使用的二进制日志文件是mysql-bin.000005
# 1. 先做全量备份
mysqldump -uroot -predhat --master-data=2 --all-databases --lock-all-tables --flush-logs > all.sql
# 1.1 查看备份的起始position
less all.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000006', MASTER_LOG_POS=245;
# 1.2 连入数据库查看此时使用的二进制日志文件
SHOW MASTER LOGS; # 假如此时正在使用的二进制日志文件是mysql-bin.000006, 此文件恰好就是全量备份后数据库使用的二进制日志文件
# 2. 连入数据库做一些操作, 如插入一条数据, 然后再做增量备份
mysqldump -uroot -p
USE testdb;
INSERT INTO mytbl1 (name,gender) VALUES ('incre1','M');
FLUSH LOGS; # 特别注意一定要做滚动日志的操作!
SHOW MASTER STATUS; # 假如日志滚动后正在使用的二进制日志文件由mysql-bin.000006变为mysql-bin.000007, 说明mysql-bin.000006记录的就是第一次增量备份所需要使用的二进制日志文件
\q # 退出数据库并将mysql-bin.000006备份到其他磁盘
# 接下来还原数据
# 3. 还原全量数据
mysql -uroot -predhat < all.sql
# 4. 先将mysql-bin.000006中记录下的SQL语句导出(注意筛选出start-position为245之后的SQL), 然后再还原第一次增量数据
mysqlbinlog --start-position=245 mysql-bin.000006 > incre1.sql
mysql -uroot -predhat < incre1.sql
2. 基于lvm2备份和还原
2.1 备份
# 注意修改/etc/my.cnf的配置文件, 将mysql的datadir目录指向逻辑卷所在目录
# (1) 请求锁定所有表
mysql> FLUSH TABLES WITH READ LOCK; # 将内存中所有表的数据同步到磁盘, 然后施加读锁
# 此时数据库中有人正在执行大事务, 此事务无法被锁定, 需要等待事务执行完才能施加读锁
# (2) 记录二进制日志文件及事件位置
mysql> FLUSH LOGS;
mysql> SHOW MASTER LOGS;
# 也可以不登录数据库, 直接要把结果记录下来
mysql -e 'FLUSH LOGS'
mysql -e 'SHOW MASTER STATUS' > /PATH/TO/RECORD.FILE # 加入此时正在使用的二进制改为mysql-bin.000004
# (3) 逻辑卷创建快照
# 创建的快照大小根据实际的增量数据大小而定
lvcreate -L 1G --snap-shot -n lv1-snap -p r /dev/vg1/lv1
# 创建完快照后一定要挂载测试, 因为创建的快照可能有问题! 文件系统为xfs的快照在挂载时可能有问题!
mkdir /mnt/snap
mount /dev/vg1/lv1-snap /mnt/snap/
umount /mnt/snap/
# (4) 拍完快照后记得释放锁, 否则线上业务会受到很大影响!
mysql> UNLOCK TABLES;
# (5) 对数据库做一些操作
mysql> DROP DATABASE testdb;
# (6) 挂载快照并将快照中的数据复制到其他硬盘或其他主机中
mount -r /dev/vg1/lv1 /mnt/
scp /mnt/data 192.168.30.10:/bak_data/
# (7) 备份完成后删除快照
lvremove /dev/vg1/lv1-snap
# (8) 制定好策略, 通过原卷备份二进制日志
scp /var/log/mariadb/mysql-bin.* 192.168.30.10:/bak_data/
2.2 还原
# 1. 把数据文件和二进制文件分别放在my.cnf中二进制文件和数据文件指定的目录下, 注意修改至mysql:mysql权限, 否则mariadb服务无法读取文件中的内容
chown -R mysql:mysql /mnt/mysql
chown -R mysql:mysql /var/log/maraidb/
# 2. 接下来还原
mysqlbinlog mysql-bin.000004 > incre.sql
mysql -uroot < incre.sql
3. xtrabackup
- 通过mysql协议链接至mysql数据库, 因此必须online备份
- 仅对InnoDB存储引擎支持热备(完全备份和增量备份), 对MyISAM只支持温备而且不支持增量备份
- 使用xtrabackup之前必须先在/etc/my.cnf的[mysqld]或[mysqld_safe]配置段开启一个参数:
innodb_file_per_table=ON
, 如果此参数没有开启, 很多备份的高级功能将无法使用, 开启后可在数据库中查看:
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE 'innodb_file%';
+--------------------------+----------+
| Variable_name | Value |
+--------------------------+----------+
| innodb_file_format | Antelope |
| innodb_file_format_check | ON |
| innodb_file_format_max | Antelope |
| innodb_file_per_table | OFF | # 此项配置在服务启动前就应该开启!
+--------------------------+----------+
3.1 使用xtrabackup做完全备份与还原
# 1. 安装, 支持windows和linux等平台, 下面以redhat7为例
yum -y install percona-xtrabackup
# 2. 完全备份
innobackup /PATH/TO/BACKUP_DIR
# 3. 整理备份数据
innobackup --apply-log /PATH/TO/BACKUP_DIR
# --apply-log的作用在于回滚未提交的事务以及同步已提交的事务至数据文件中, 从而保持数据文件的一致性.
# 不过完全备份中有大事务未完成, 而增量备份中才完成这个大事务时, --apply-log参数不能加!
# 3. 还原
# 注意: 还原时不能启动mysql服务!
innobackup --copy-back /PATH/TO/BACKUP_DIR
chown -R mysql:mysql /PATH/TO/MYSQL_DATADIR
cat xtrabackup_checkpoints
backup_type = full-prepared # 说明是做全量备份
from_lsn = 0
to_lsn = 1597945
last_lsn = 1597945
compact = 0
recover_binlog_info = 0
3.2 使用xtrabackup做增量备份与还原
- 增量备份仅能用于InnoDB或XtraDB表, 对于MyISAM表而言, 增量备份其实是完全备份
- 增量备份要基于上一次的备份进行
innobackup --incremental /backup --increment-basedir=BASEDIR
cat xtrabackup_checkpoints
backup_type = incremental # 说明是增量备份
from_lsn = 1597945 # 上一次备份结束的日志序列号, 同时也是这一次开始增量备份的日志序列号
to_lsn = 1601588 # 本次结束的日志序列号
last_lsn = 1601588
compact = 0
recover_binlog_info = 0
# 1. 全量备份到/tmp/目录下
innobackup /tmp/ # 假设生成的全量备份目录名为/tmp/2019-11-12_21-56-49/
# 2. 基于全量备份进行第一次增量备份
innobackup --incremental /tmp/ --increment-basedir=/tmp/2019-11-12_21-56-49/ # 假设生成的第一次增量备份目录名为/tmp/2019-11-12_21-56-49/
# 增量备份的整理过程与全量备份的整理过程不同
# 3. 先基于全量备份做整理
innobackupex --apply-log --redo-only /tmp/2019-11-12_21-56-49/ --incremental-dir=/tmp/
# 4. 再基于第一次增量备份做整理
innobackupex --apply-log --redo-only /tmp/2019-11-12_21-56-49/ --incremental-dir=/tmp/2019-11-12_22-10-24/
# 可以看到整理后2019-11-12_21-56-49/xtrabackup_checkpoints文件中备份类型的值变为log-applied
cat 2019-11-12_21-56-49/xtrabackup_checkpoints
backup_type = log-applied
from_lsn = 0
to_lsn = 1601588
last_lsn = 1601588
compact = 0
recover_binlog_info = 0
# 5. 此时可以基于合并后的全量备份的进行还原
innobackup --copy-back /tmp/2019-11-12_21-56-49/
3.3 使用xtrabackup导入或导出单张表
前提条件:
- 需要"导出"表在创建之前, mysql服务器就启用了
innodb_file_per_table
选项- "导入"表的服务器同时启用了
innodb_file_per_table
和innodb_expand_import
选项
MySQL 5.6 Innodb新特性之export/import 表文件
选项innodb_expand_import
在某些新版的mysql中已改为innodb_import_table_from_xtrabackup
, 关于innodb_expand_import
以及导出单张表的percona官方详细说明: Expand Table Import
导入单张表的percona官方详细说明: Restoring Individual Tables
# 1. 先做完全备份, 需要确保这次完全备份没有apply-log过
innobackup /tmp/ # 假如生成的完全备份目录名为/tmp/2019-11-13_00-11-49/
# 2. 在完全备份的基础上apply-log并export出每个innodb表的数据文件
innobackup --apply-log --export /tmp/2019-11-13_00-11-49/
# 此时去查看完全备份的每个数据库目录下, 会发现多了以.exp和.cfg结尾的文件
ll /tmp/2019-11-13_00-11-49/hellodb/
total 132
-rw-r-----. 1 root root 65 Nov 13 00:11 db.opt
-rw-r--r--. 1 root root 396 Nov 13 00:29 test.cfg
-rw-r--r--. 1 root root 16384 Nov 13 00:29 test.exp
-rw-r-----. 1 root root 8586 Nov 13 00:11 test.frm
-rw-r-----. 1 root root 98304 Nov 13 00:11 test.ibd
# 3. 将.exp和.ibd结尾的文件拷贝到需要恢复的数据库服务器上, 创建与原表结构相同的新表
mysql> CREATE TABLE hellodb.test (...) ENGINE=InnoDB;
# 4. 将此表的表空间删除
mysql> ALTER TABLE hellodb.test DISCARD TABLESPACE;
# 5. 将对应表的.ibd和.exp文件复制到新服务器的数据目录(注意修改权限), 然后导入
mysql> ALTER TABLE hellodb.test IMPORT TABLESPACE;
导入时报错: "ERROR 1030 (HY000): Got error -1 from storage engine", 在xtrabackup的man帮助里有关于这个问题及解决方法的详细说明:
Importing the Table
On the destination server running Percona Server with XtraDB and
innodb_import_table_from_xtrabackup option enabled, or MySQL 5.6, create
a table with the same structure, and then perform the following steps:· Execute ALTER TABLE test.export_test DISCARD TABLESPACE;
· If you see the following message, then you must enable inn‐
odb_file_per_table and create the table again: ERROR 1030 (HY000):
Got error -1 from storage engine· Copy the exported files to the test/ subdirectory of the destination
server's data directory· Execute ALTER TABLE test.export_test IMPORT TABLESPACE;
The table should now be imported, and you should be able to SELECT from
it and see the imported data.
从man帮助中可以看出, 需要开启innodb_file_per_table
选项并重新创建表, 然后复制导出的文件到指定的数据文件目录中, 重新导入表空间, 实测确实有效!