MySQL备份与恢复

MySQL备份与恢复

备份恢复XBKmysqldump

欢迎来到 来到大浪涛天的博客

一、MySQL备份恢复

1. 备份策略的设计与规划

1-1. 在备份恢复中的职责

1-1-1. 备份策略的设计

  1. 备份类型:
  • 热备 : 对于业务影响最小 InnoDB
  • 温备 : 长时间锁表备份 MyISAM
  • 冷备 : 业务关闭情况下备份
  1. 备份周期:
  • 根据数据量.
  1. 备份工具:
    mysqldump (MDP) , XBK (PBK) percona Xtrabackup , MEB(MySQL Enterprise BACKUP MEB) ,mysqlbinlog
  2. 备份方式:
  • 逻辑,文本方式备份,压缩比很大,比较省空间:
    全备 mysqldump
    增量 binlog (flush logs ,cp)
  • 物理备份:
    全备 : XBK
    增量 : XBK

1-1-2. 检查备份可用性

每天上班检查前一天晚上备份的文件是否正常,这个至关重要,防止某天备份出错,备份不成功,运维人员却对此完全不知情。

crontab -l ----->
备份脚本   ----->
备份路径  ----->
看备份日志,检查备份文件(大小,内容)

1-1-3. 定期的恢复演练

  1. 定期恢复演练可以确认备份的可用性
  2. 可以增加运维人员对故障恢复的成熟程度,因为一般情况下都不用进行数据恢复,但是特殊情况下如设备硬盘损坏,又需要快速恢复数据
  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恢复数据库

背景环境:

  1. 正在运行的网站系统,mysql-5.7.20 数据库,数据量50G,日业务增量1-5M。
  2. 备份策略:
    每天23:00点,计划任务调用mysqldump执行全备脚本
  3. 故障时间点:
    年底故障演练:模拟周三上午10点误删除数据库.

处理思路:

  1. 停业务,挂维护页,避免数据的二次伤害
  2. 找一个临时库,恢复周二23:00全备
  3. 截取周二23:00 --- 周三10点误删除之间的binlog,恢复到临时库
  4. 测试可用性和完整性
  5. 处理方法
  • 方法一:直接使用临时库顶替原生产库,前端应用割接到新库
  • 方法二:将误删除的表用mysqldump导出,再source到原生产库
  1. 开启业务
  • 处理结果:经过20分钟的处理,最终业务恢复正常

故障模拟演练

  1. 准备数据
create database backup;
use backup
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
rm -rf /backup/*
  1. 周二 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
  1. 模拟周二 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;
  1. 模拟故障,删除表(只是模拟,不代表生产操作)
drop database backup;
  1. 恢复过程
  • 准备临时数据库(多实例3308)
systemctl start mysqld3307
  1. 准备备份
  • 准备全备:
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
  1. 恢复备份到临时库
mysql -S /data/3307/mysql.sock
set sql_log_bin=0;
source /backup/full_2019-07-15.sql
source /backup/bin.sql
  1. 将故障表导出并恢复到生产
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 增量备份模拟

  1. 模拟数据
create database test1 charset utf8mb4;
use test1;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
  1. 进行周日的全备
[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要指定
  1. 模拟周一的数据变化
create database inc1 charset utf8mb4;
use inc1;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
  1. 进行周一的增量备份
[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     增量备份的位置点
  1. 检查备份的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
  1. 模拟周二数据变化
create database inc2 charset utf8mb4;
use inc2;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
  1. 周二的增量
innobackupex   --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/backup/inc1 /backup/inc2 
  1. 周三的数据变化
create database inc3 charset utf8mb4;
use inc3;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
  1. 模拟上午10点数据库崩溃
pkill mysqld 
\rm -rf /data/mysql/data/*
  1. 恢复思路
1. 停业务,挂维护页
2. 查找可用备份并处理备份:full+inc1+inc2 
3. binlog: inc2 到 故障时间点的binlog
4. 恢复全备+增量+binlog
5. 验证数据
6. 起业务,撤维护页
  1. 恢复前的准备
(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
  1. 截取二进制日志
起点:
[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
  1. 恢复备份数据
[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
  1. 验证数据
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
上一篇:hj_三三对决分配对手


下一篇:最近编程中遇到的一些问题2021/9/8