MySQL备份与恢复
备份恢复XBKmysqldump欢迎来到 来到大浪涛天的博客 !
一、MySQL备份恢复
1. 备份策略的设计与规划
1-1. 在备份恢复中的职责
1-1-1. 备份策略的设计
- 备份类型:
- 热备 : 对于业务影响最小 InnoDB
- 温备 : 长时间锁表备份 MyISAM
- 冷备 : 业务关闭情况下备份
- 备份周期:
- 根据数据量.
- 备份工具:
mysqldump (MDP) , XBK (PBK) percona Xtrabackup , MEB(MySQL Enterprise BACKUP MEB) ,mysqlbinlog - 备份方式:
- 逻辑,文本方式备份,压缩比很大,比较省空间:
全备 mysqldump
增量 binlog (flush logs ,cp) - 物理备份:
全备 : XBK
增量 : XBK
1-1-2. 检查备份可用性
每天上班检查前一天晚上备份的文件是否正常,这个至关重要,防止某天备份出错,备份不成功,运维人员却对此完全不知情。
crontab -l ----->
备份脚本 ----->
备份路径 ----->
看备份日志,检查备份文件(大小,内容)
1-1-3. 定期的恢复演练
- 定期恢复演练可以确认备份的可用性
- 可以增加运维人员对故障恢复的成熟程度,因为一般情况下都不用进行数据恢复,但是特殊情况下如设备硬盘损坏,又需要快速恢复数据
- 进行多种故障场景进去模拟,尽可能的形成一个体系
1-1-4. 数据恢复
需要确认好mysqldump定期备份的完整日志,然后确认好当天的二进制日志的结束点的位置,利用完整备份日志及二进制日志迅速恢复到故障之前的时间点。
1-1-5. 数据迁移
操作系统不同的迁移
mysql -> mysql
其他 -> mysql
mysql -> 其他
2. mysqldump 工具的使用
2-1. mysql连接数据库的参数
-u 用户名
-p 密码
-S 套接字
-h 主机名
-P 端口号
基础备份参数
-A 全备份
[root@db01 backup]# mysqldump -uroot -p123 -A >/backup/full.sql
-B 针对某个或者某些库备份
[root@db01 backup]# mysqldump -uroot -p123 -B world oldguo wordpress >/backup/db.sql
库 表 前面接一个库名,后面都是接的是该库的表名,代表备份该库的表
[root@db01 backup]# mysqldump -uroot -p123 world city country > /backup/tab.sql
2-2. MySQL的特殊备份参数
如果加上如下参数,备份的时候自动会把存储过程和函数,及事件和触发器都一起备份,因此一定要加
-R 存储过程和函数
-E 事件
--triggers 触发器
--master-data=2
(1) 记录备份时刻的binlog信息
(2) 自动锁表
不加--single-transaction ,温备份
加了--single-transaction,对于InnoDB表不锁表备份(快照备份)
--single-transaction
对于InnoDB的表,进行一致性快照备份,不锁表.
因此完整的备份命令如下
mysqldump -uroot -p123 -A -R -E --triggers --master-data=2 --single-transaction >/backup/full.sql
2-3. MySQL扩展参数
在构建主从时,使用AUTO/ON
--set-gtid-purged=AUTO/ON
仅是做普通的本机备份恢复时,可以添加
--set-gtid-purged=OFF
SET @@GLOBAL.GTID_PURGED='aa648280-a6a6-11e9-949f-000c294a1b3b:1-11';
--max_allowed_packet=128M 控制的是备份时传输数据包的大小.
mysqldump -uroot -p123 -A -R --max_allowed_packet=128M --triggers --set-gtid-purged=OFF --master-data=2 --single-transaction|gzip > /backup/full_$(date +%F).sql.gz
2-4. MySQL恢复案例
2-4-1. 网站系统故障演练删除数据库,利用binlog恢复数据库
背景环境:
- 正在运行的网站系统,mysql-5.7.20 数据库,数据量50G,日业务增量1-5M。
- 备份策略:
每天23:00点,计划任务调用mysqldump执行全备脚本 - 故障时间点:
年底故障演练:模拟周三上午10点误删除数据库.
处理思路:
- 停业务,挂维护页,避免数据的二次伤害
- 找一个临时库,恢复周二23:00全备
- 截取周二23:00 --- 周三10点误删除之间的binlog,恢复到临时库
- 测试可用性和完整性
- 处理方法
- 方法一:直接使用临时库顶替原生产库,前端应用割接到新库
- 方法二:将误删除的表用mysqldump导出,再source到原生产库
- 开启业务
- 处理结果:经过20分钟的处理,最终业务恢复正常
故障模拟演练
- 准备数据
create database backup;
use backup
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
rm -rf /backup/*
- 周二 23:00全备
mysqldump -uroot -padmin123 -A -R --triggers --set-gtid-purged=OFF --master-data=2 --single-transaction|gzip > /backup/full_$(date +%F).sql.gz
注意:
--master-data=2
(1) 以注释的形式记录二进制日志信息
(2) 自动开启锁表的功能
--single-transaction
针对InnoDB进行快照备份
-R
-E
--triggers
--set-gtid-purged=AUTO/ON/OFF
默认是auto
主从复制,忽略此参数
普通备份,可以OFF
- 模拟周二 23:00到周三 10点之间数据变化
use backup
insert into t1 values(11),(22),(33);
commit;
create table t2 (id int);
insert into t2 values(11),(22),(33);
commit;
- 模拟故障,删除表(只是模拟,不代表生产操作)
drop database backup;
- 恢复过程
- 准备临时数据库(多实例3308)
systemctl start mysqld3307
- 准备备份
- 准备全备:
cd /backup
gunzip full_2018-10-14.sql.gz
- 截取二进制日志
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=753;
753
1519
mysqlbinlog --skip-gtids --start-position=753 --stop-position=1519 /data/binlog/mysql-bin.000002 >/backup/bin.sql
- 恢复备份到临时库
mysql -S /data/3307/mysql.sock
set sql_log_bin=0;
source /backup/full_2019-07-15.sql
source /backup/bin.sql
- 将故障表导出并恢复到生产
mysqldump -S /data/3307/mysql.sock -B backup >/backup/bak.sql
mysql -uroot -p123
set sql_log_bin=0
source /backup/bak.sql;
2-5. 故障演练误删除表数据,利用gtids恢复故障表
故障模拟如下:
1、创建一个数据库 gtid
2、在gtid下创建一张表t1
3、插入5行任意数据
4、全备
5、插入两行数据,任意修改3行数据,删除1行数据
6、删除所有数据
7、再t1中又插入5行新数据,修改3行数据
需求,跳过第六步恢复表数据
1. 按要求模拟数据
create database gtid charset utf8mb4;
commit;
use gtid;
create table t1(id int);
commit;
insert into t1 values(1),(2),(3),(4),(5);
commit;
2. 全备数据库
[root@test02 ~]# mysqldump -uroot -padmin123 -S /data/3307/mysql.sock -A --master-data=2 --single-transaction -R -E --triggers >/backup/1full.sql
3. 继续模拟数据
insert into t1 values(6),(7);
update t1 set id=10 where id>4;
delete from t1 where id=2;
commit;
delete from t1;
commit;
insert into t1 values(11),(12),(13),(14),(15);
update t1 set id=30 where id >12;
commit;
4. 根据备份的结束点和events确定起点和终点,截取二进制日志
SET @@GLOBAL.GTID_PURGED='9f5d3fcf-e215-11ea-9d2c-001c42063d8f:1-14';
知道第6步的gtids号是17,而我们需要恢复的是15-19然后排除17
[root@test02 ~]# mysqlbinlog --skip-gtids --include-gtids='9f5d3fcf-e215-11ea-9d2c-001c42063d8f:15-19' --exclude-gtids='9f5d3fcf-e215-11ea-9d2c-001c42063d8f:17' mysql-bin.000004 >/backup/1bin.sql;
5. 打开测试库,并恢复全备库和截取的二进制日志
set sql_log_bin=0;
source /backup/1full.sql;
source /backup/1bin.sql;
set sql_log_bin=1;
6. 将测试库的gtids库的t1表导出来
mysqldump -uroot -padmin123 -S /data/3307/mysql.sock gtids t1 >/backup/gtid.sql
7. 进入生产库,将数据导入到生产库中
set sql_log_bin=0;
use gtid;
source /backup/gtid.sql
set sql_log_bin=1;
8. 确认数据是否都恢复正常
3. 物理备份-XBK
3-1. 安装XBK软件
1. 安装依赖包:
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum -y install perl perl-devel libaio libaio-devel perl-Time-HiRes perl-DBD-MySQL libev
2. 下载软件并安装
wget https://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.4.12/binary/redhat/7/x86_64/percona-xtrabackup-24-2.4.12-1.el7.x86_64.rpm
3. yum -y install percona-xtrabackup-24-2.4.4-1.el7.x86_64.rpm
3-2. innobackupex 使用
3-2-1. 备份核心理念
1. 针对非InnoDB,进行锁表备份,copy所有的非innoDB表文件
2. 针对InnoDB表,立即触发CKPT,copy所有InnoDB表相关的文件(ibdata1,ibd,frm).
并且将备份过程中产生,新的数据变化的部分redo一起备份走
3. 在恢复时,xbk会调用InnoDB引擎的CSR过程,将数据和redo的LSN追平,然后进行一致性恢复.
3-2-2. 基础备份过程
(1) 全备
[root@db01 backup]# innobackupex --user=root --password=123 --no-timestamp /backup/full
(2)增量备份
innobackupex --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/backup/full /backup/inc1
说明:
--incremental 开关
--incremental-basedir=/backup/full 基于哪个备份进行增量
/backup/inc1 增量备份的位置点
(3) 利用全备进行恢复
1.
[root@db01 ~]# pkill mysqld
2.
[root@db01 ~]# \rm -rf /data/mysql/data/*
3. *****
[root@db01 ~]# innobackupex --apply-log /backup/full/
4.
[root@db01 full]# cp -a /backup/full/* /data/mysql/data/
5.
[root@db01 full]# chown -R mysql.mysql /data/mysql/data/*
6.
[root@db01 full]# /etc/init.d/mysqld start
3-2-3. 备份产生的文件介绍
(1) xtrabackup_binlog_info
记录备份时刻的二进制日志信息. 可以作为binlog截取的起点.
(2) xtrabackup_checkpoints
from : 备份中包含的LSN号的起点,全备:0,增量:上次备份的结束位置
to : ckpt 时的LSN
last-9 : 备份结束时的LSN.下次增量备份的起始位置.
3-2-4. XBK 增量备份模拟
- 模拟数据
create database test1 charset utf8mb4;
use test1;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
- 进行周日的全备
[root@test02 inc1]# innobackupex --user=root --password=admin123 --port=3307 --datadir=/data/3307/data --socket=/data/3307/mysql.sock --no-timestamp /backup/3307/full
注意,因为是多实例安装的mysql,所以路径和端口和socket要指定
- 模拟周一的数据变化
create database inc1 charset utf8mb4;
use inc1;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
- 进行周一的增量备份
[root@test02 inc1]# innobackupex --user=root --password=admin123 --port=3307 --datadir=/data/3307/data --socket=/data/3307/mysql.sock --no-timestamp --incremental --incremental-basedir=/backup/3307/full /backup/3307/inc1
说明:
--incremental 开关
--incremental-basedir=/backup/full 基于哪个备份进行增量
/backup/inc1 增量备份的位置点
- 检查备份的LSN
[root@test02 3307]# cat full/xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 168705090
last_lsn = 168705099
compact = 0
recover_binlog_info = 0
[root@test02 3307]# cat inc1/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 168705090
to_lsn = 168711026
last_lsn = 168711035
compact = 0
recover_binlog_info = 0
- 模拟周二数据变化
create database inc2 charset utf8mb4;
use inc2;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
- 周二的增量
innobackupex --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/backup/inc1 /backup/inc2
- 周三的数据变化
create database inc3 charset utf8mb4;
use inc3;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
- 模拟上午10点数据库崩溃
pkill mysqld
\rm -rf /data/mysql/data/*
- 恢复思路
1. 停业务,挂维护页
2. 查找可用备份并处理备份:full+inc1+inc2
3. binlog: inc2 到 故障时间点的binlog
4. 恢复全备+增量+binlog
5. 验证数据
6. 起业务,撤维护页
- 恢复前的准备
(1) 整理full
innobackupex --user=root --password=admin123 --port=3307 --datadir=/data/3307/data --socket=/data/3307/mysql.sock --no-timestamp --apply-log --redo-only /backup/3307/full
(2) 合并inc1到full,并整理备份
innobackupex --user=root --password=admin123 --port=3307 --datadir=/data/3307/data --socket=/data/3307/mysql.sock --no-timestamp --apply-log --redo-only --incremental-dir=/backup/3307/inc1 /backup/3307/full
(3) 合并inc2到full,并整理备份
innobackupex --user=root --password=admin123 --port=3307 --datadir=/data/3307/data --socket=/data/3307/mysql.sock --no-timestamp --apply-log --incremental-dir=/backup/3307/inc2 /backup/3307/full
(4) 最后一次整理full
innobackupex --user=root --password=admin123 --port=3307 --datadir=/data/3307/data --socket=/data/3307/mysql.sock --no-timestamp --apply-log /backup/3307/full
- 截取二进制日志
起点:
[root@test02 inc2]# cat xtrabackup_binlog_info
mysql-bin.000005 3938 9f5d3fcf-e215-11ea-9d2c-001c42063d8f:1-42
终点:
SET @@SESSION.GTID_NEXT= '9f5d3fcf-e215-11ea-9d2c-001c42063d8f:45'/*!*/;
[root@test02 binlog]# mysqlbinlog --skip-gtids --include-gtids='9f5d3fcf-e215-11ea-9d2c-001c42063d8f:43-45' mysql-bin.000005 >/backup/3307/bin.sql
- 恢复备份数据
[root@db01 /]# cp -a /backup/full/* /data/mysql/data/
[root@db01 /]# chown -R mysql. /data/
[root@db01 /]# /etc/init.d/mysqld start
mysql> set sql_log_bin=0;
mysql> source /backup/binlog.sql
- 验证数据
mysql> select * from full.t1;
mysql> select * from inc1.t1;
mysql> select * from inc2.t1;
mysql> select * from inc3.t1;
3-3. 如果误删除的表只有10M,而备份有500G,该如何快速恢复误删除表?
1. 在旧的数据库中找到t100w的建表语句
mysql> show create table t100w;
2. 在新的的MySQL创建一个库以及原来相同的结构的表
mysql> CREATE TABLE `t100w` (... ...)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
3. 将空表中的ibd文件删除
mysql> alter table t100w discard tablespace;
4. 将原表的ibd文件拷贝过来,并注意权限
[root@test02 test01]# cp -a /data/3307/data/test01/t100w.ibd .
5. 将原表的ibd文件进行导入
mysql> alter table t100w import tablespace;
Query OK, 0 rows affected, 1 warning (0.72 sec)
mysql> select count(*) from t100w;
+----------+
| count(*) |
+----------+
| 1030345 |
+----------+
3-4. 从mysqldump 全备中获取库和表的备份
1、获得表结构
# sed -e'/./{H;$!d;}' -e 'x;/CREATE TABLE `city`/!d;q' full.sql>createtable.sql
2、获得INSERT INTO 语句,用于数据的恢复
# grep -i 'INSERT INTO `city`' full.sqll >data.sql &
3.获取单库的备份
# sed -n '/^-- Current Database: `world`/,/^-- Current Database: `/p' all.sql >world.sql