目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

备份恢复与数据迁移

DBA在数据库备份恢复方面的职责

全备

增量

定期恢复演练

故障恢复

迁移(停机时间、回退方案)

备份类型

  • 热备:在数据库正常业务时,备份数据,并且能够一致性恢复(只能是innodb)
  • 稳备:锁表备份,只能查询修改,不能修改(myisam)
  • 冷备:关闭数据库业务,数据库没有任何变更的情况下,进行备份数据。

备份方式及工具

  • 逻辑备份:基于SQL语句进行备份

    mysqldump
    mysqlbinlog
    
  • 物理备份:基于磁盘数据文件备份

    xtrabackup(XBK):percona   第三方(推荐使用)
    Mysql Enterprise Backup (MEB)
    

逻辑备份VS物理备份

  • mysqldump(MDP)
    # 优点
    1.不需要下载安装
    2.备份出来的是SQL,文本格式,可读性高,便于备份处理
    3.压缩比较高,介绍备份的磁盘空间
    
    # 缺点
    1.依赖于数据库引擎,需要从磁盘把数据读出,然后转换成SQL进行存储,比较耗费资源,数据量大的话效率较低
    2.100G以内的数据量级,可以使用mysqldump,也可以使用xtrabackup
    3.超过TB以上,也可以选择mysqldump,配合分布式的系统
    
  • xtrabackup(XBK)
    # 优点
    1.类似于直接cp数据文件,不需要管理逻辑结构,相对来说性能较高
    
    # 缺点
    1.可读性差
    2.压缩比低,需要更多磁盘空间
    3.建议大于100G且小于1TB的时候使用
    
    

备份策略

全备:全库备份,备份所有数据。

增量:备份变化数据。

逻辑备份 = mysqldump(全备) + mysqlbinlog(增量)
物理备份 = xtrabackup_full + xtrabackup_incr + mysqlbinlog 或者 xtrabackup_full + mysqlbinlog

根据数据量设计备份周期,比如:周日全备,周1-周6增量。

逻辑备份工具-mysqldump

连接方式

# 本地备份的连接方式
mysqldump -uroot -pxxx -S /tmp/mysql.sock

# 远程备份的连接方式
mysqldump -uroot -pxxx -h 192.168.31.210 -P 3306

基本备份参数

-A	# 全库备份
-B	# 备份单个库或多个库
库名 表名

# 备份全库
mkdir -p /data/backup
mysqldump -uroot -p123 -A -S /tmp/mysql.sock > /data/backup/full.sql

# 备份oldboy和world库
mysqldump -uroot -p123 -B world oldboy -S /tmp/mysql.sock > /data/backup/db.sql

# 备份某个库下的一张或多张表:别分world数据库下的city和country表(恢复数据的时候需要提前建库并且use database,只会备份表)
mysqldump -uroot -p123 world city country -S /tmp/mysql.sock > /data/backup/tab.sql

备份必加参数

-R	# 在备份时,同时备份存储过程和函数,如果没有会自动忽略
-E	# 在备份时,同时备份event,如果没有会自动忽略
--triggers	# 在备份时,同时备份触发器,如果没有会自动忽略
--master-data=2	#记录备份时候记录当前position号,作为将来日志截取的起点,自动锁表,配合 --single-transaction,减少锁表(innodb引擎)
--single-transaction	# 对于innodb的表,实现快照备份,不锁表
--set-gtid-purged=auto	# 默认是auto,on
使用场景:
1. --set-gtid-purged=OFF,可以使用在日常备份参数中
mysqldump -uroot -p -A -R -E --triggers --master-data=2 --single-transaction --set-gtid-purged=OFF > /data/backup/full.sql
2.auto , on :在构建主从复制环境时需要的参数配置
mysqldump -uroot -p -A -R -E --triggers --master-data=2 --single-transaction --set-gtid-purged=ON > /data/backup/full.sql

--max-allowed-packet=128M  #避免由于备份大表产生的数据包报错问题

恢复思路

1.全备的时候自动记录日志当前的position号
2.全部的时候自动滚动生成新的bin_log日志

mysql> source  /data/backup/full.sql

备份恢复案例(mysqldump+binlog)

数据量80G,每日数据增长5-6M

备份策略:每天mysqldump全备 + binlog备份

故障描述:周三下午2点,数据路径由于某原因数据损坏

处理思路:

1.挂出维护页。

2.评估数据损坏状态(全部丢失【直接生产恢复】 or 部分丢失【从备份中导出单表数据,或者测试库进行全部恢复,再把单表导回生产库中】)

3.恢复全部,将数据追溯到周二晚上23:00状态,

4.截取并恢复从备份时刻到周三下午2点误删除之前binlog

5.校验数据的一致性(测试人员会校验)

6.撤除维护页,恢复生产


处理结果:经过30~40分钟处理,业务恢复,评估此次故障的处理的合理性和实用性。

案例模拟

1、进行周二晚上23:00的全备

[root@localhost backup]# mysqldump -uroot -p123 -A -R --triggers -E --master-data=2 --single-transaction > /data/backup/full.sql
[root@localhost backup]# ll -h
total 49M
-rw-r--r--. 1 root root 49M May  9 09:22 full.sql

# 记录备份时候记录当前position号,作为将来日志截取的起点,起点就是MASTER_LOG_POS=22108059;
[root@localhost backup]# vim full.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000007', MASTER_LOG_POS=22108059;

# 如果使用GTID来恢复,下面代表从285开始
[root@localhost backup]# vim full.sql
SET @@GLOBAL.GTID_PURGED='f98d1e0b-a7e4-11eb-8259-080027fb878b:1-284';

2、模拟周二晚上23:00之后到周三下午2点误删除之前的业务操作

mysql> create database mdp charset utf8mb4;
mysql> use mdp;
mysql> create table t1(id int);
mysql> insert into t1 values(1),(2),(3);
mysql> commit;
mysql> select * from t1;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+

3.模拟数据损坏(真刺激)

[root@localhost data]# pwd
/data/mysql/data
[root@localhost data]# /etc/init.d/mysqld stop
Shutting down MySQL.... SUCCESS!
[root@localhost data]# rm -rf *
[root@localhost data]# ll
total 0

4.初始化数据库

[root@localhost data]# mysqld --initialize-insecure --user=mysql --basedir=/application/mysql/ --datadir=/data/mysql/data
[root@localhost data]# ll
total 110636
-rw-r-----. 1 mysql mysql       56 May  9 09:44 auto.cnf
-rw-r-----. 1 mysql mysql      419 May  9 09:44 ib_buffer_pool
-rw-r-----. 1 mysql mysql 12582912 May  9 09:44 ibdata1
-rw-r-----. 1 mysql mysql 50331648 May  9 09:44 ib_logfile0
-rw-r-----. 1 mysql mysql 50331648 May  9 09:44 ib_logfile1
drwxr-x---. 2 mysql mysql     4096 May  9 09:44 mysql
-rw-r-----. 1 mysql mysql      975 May  9 09:44 mysql.log
drwxr-x---. 2 mysql mysql     8192 May  9 09:44 performance_schema
-rw-r-----. 1 mysql mysql      163 May  9 09:44 slow.log
drwxr-x---. 2 mysql mysql     8192 May  9 09:44 sys

# 启动数据库
[root@localhost data]# /etc/init.d/mysqld start
Starting MySQL. SUCCESS!

5.进行全备恢复(没有mdp库)

mysql> set sql_log_bin=0;
mysql> source /data/backup/full.sql
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| gg                 |
| mysql              |
| oldboy             |
| oldboy2            |
| performance_schema |
| school             |
| sys                |
| test               |
| world              |
| zrblog             |
+--------------------+
11 rows in set (0.00 sec)

mysql> flush privileges;

6.截取binlog日志,完成增量恢复,需要找起点和终点,终点不需要找,起点的话都可以position 活着 gtid都可以。

# 分析000007日志
mysql> show binlog events in 'mysql-bin.000007';
285~287

# 截取日志
[root@localhost ~]# mysqlbinlog --skip-gtids --include-gtids="f98d1e0b-a7e4-11eb-8259-080027fb878b:285-287" /data/binlog/mysql-bin.000007 > /data/backup/bin.sql

或者这里没有写--stop-position 就代表一直截取到最后
[root@localhost ~]# mysqlbinlog --skip-gtids --start-position=22108059 /data/binlog/mysql-bin.000007 > /data/backup/bin.sql


# 恢复数据
mysql> set sql_log_bin=0;
mysql> source /data/backup/bin.sql
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| gg                 |
| mdp                |
| mysql              |
| oldboy             |
| oldboy2            |
| performance_schema |
| school             |
| sys                |
| test               |
| world              |
| zrblog             |
+--------------------+

mysql> use mdp;
Database changed
mysql> select * from t1;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+

mysqldump备份命令

# 仿照如下命令编写备份脚本
mysql -uroot -p123 -A -R --triggers --master-data=2 max_allowed_packet=128M --single-transaction|gzip > /backup/full_$(date +%F).sql.gz

XBK

# 安装依赖包
yum install -y perl perl-devel libaio libaio-devel perl-Time-HiRes perl-DBD-MySQL libev

# 下载地址
wget https://downloads.percona.com/downloads/Percona-XtraBackup-2.4/Percona-XtraBackup-2.4.22/binary/redhat/7/x86_64/percona-xtrabackup-24-2.4.22-1.el7.x86_64.rpm

# 安装软件包
[root@localhost software]# yum -y install percona-xtrabackup-24-2.4.22-1.el7.x86_64.rpm
[root@localhost software]# innobackupex --version
xtrabackup: recognized server arguments: --datadir=/data/mysql/data --server-id=6 --log_bin=/data/binlog/mysql-bin --server-id=6
innobackupex version 2.4.22 Linux (x86_64) (revision id: c99a781)

备份命令介绍

xtrabackup
innobackupex  ******

备份方式:物理备份

1.对于非Innodb表,锁表cp数据文件,数据一种温备份。
2.对于Innodb的表(支持事务的),不锁表,拷贝数据页,最终于数据文件的方式保存下来,把一部分redo和undo一并备走,数据热备份方式。

XBK全备

# 新建备份目录
[root@localhost software]# mkdir -p /data/bak

# 修改配置文件,将[mysql]改为[client]
[root@localhost software]# cat  /etc/my.cnf
[mysqld]
user=mysql
basedir=/application/mysql
datadir=/data/mysql/data
socket=/tmp/mysql.sock
server_id=6
port=3306
log_error=/data/mysql/data/mysql.log
log_bin=/data/binlog/mysql-bin
server_id=6
secure-file-priv=/tmp
gtid-mode=on
enforce-gtid-consistency=true
slow_query_log=1        #开关
slow_query_log_file=/data/mysql/data/slow.log #位置
long_query_time=0.1     #设定慢查询时间
log_queries_not_using_indexes #没走索引的语句也记录
[client]	# innobackupex需要使用socket
socket=/tmp/mysql.sock

# 重启服务
[root@localhost software]# /etc/init.d/mysqld restart
Shutting down MySQL.... SUCCESS!
Starting MySQL. SUCCESS!

# 全备:备份工具依赖于/etc/my.cnf文件,会读取[mysqld][client]标签下的信息
[root@localhost software]# innobackupex --defaults-file=/etc/my.cnf --user=root --password=123 /data/bak
或者自主定制备份路径名(目录名)
[root@localhost software]# innobackupex --defaults-file=/etc/my.cnf --user=root --password=123 --no-timestamp /data/bak/full_$(date +%F)


# 以目录的形式保存
[root@localhost software]# ls /data/bak/
2021-05-09_11-10-54

xtrabackup_binlog_info:记录position和GTID

[root@localhost 2021-05-09_11-10-54]# cat xtrabackup_binlog_info
mysql-bin.000010        234     1839d529-b068-11eb-8f64-080027fb878b:1,
f98d1e0b-a7e4-11eb-8259-080027fb878b:1-287

xtrabackup_checkpoints:lsn号

[root@localhost 2021-05-09_11-10-54]# cat xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 105394732
last_lsn = 105394741
compact = 0
recover_binlog_info = 0
flushed_lsn = 105394741

xtrabackup_info:备份的总体信息

xtrabackup_logfile:备份过程中产生的新的数据变化

恢复数据

# 模拟数据丢失
[root@localhost 2021-05-09_11-10-54]# cd /data/mysql/data/
[root@localhost data]# ls
auto.cnf  ib_buffer_pool  ib_logfile0  mdp    mysql.log  oldboy2             school    sys   world
gg        ibdata1         ib_logfile1  mysql  oldboy     performance_schema  slow.log  test  zrblog
# 回复备份的前提是数据目录必须是空的,恢复的数据实例是关闭的
[root@localhost data]# rm -rf *
[root@localhost 2021-05-09_11-10-54]# /etc/init.d/mysqld stop
Shutting down MySQL.. SUCCESS!

# 准备恢复数据
[root@localhost data]# innobackupex --apply-log /data/bak/2021-05-09_11-10-54/
InnoDB: Shutdown completed; log sequence number 105395240
210509 11:36:49 completed OK!

# 恢复数据
[root@localhost data]# cd /data/bak/2021-05-09_11-10-54/
[root@localhost 2021-05-09_11-10-54]# cp -a /backup/bak/2021-05-09_11-10-54/* /data/mysql/data/
[root@localhost 2021-05-09_11-10-54]# cd /data/mysql/data/
[root@localhost data]# ll
total 196672
-rw-r-----. 1 root root      487 May  9 11:10 backup-my.cnf
drwxr-x---. 2 root root       48 May  9 11:10 gg
-rw-r-----. 1 root root    10254 May  9 11:10 ib_buffer_pool
-rw-r-----. 1 root root 79691776 May  9 11:36 ibdata1
-rw-r-----. 1 root root 50331648 May  9 11:36 ib_logfile0
-rw-r-----. 1 root root 50331648 May  9 11:36 ib_logfile1
-rw-r-----. 1 root root 12582912 May  9 11:36 ibtmp1
drwxr-x---. 2 root root       48 May  9 11:10 mdp
drwxr-x---. 2 root root     4096 May  9 11:10 mysql
drwxr-x---. 2 root root       54 May  9 11:10 oldboy
drwxr-x---. 2 root root       20 May  9 11:10 oldboy2
drwxr-x---. 2 root root     8192 May  9 11:10 performance_schema
drwxr-x---. 2 root root      160 May  9 11:10 school
drwxr-x---. 2 root root     8192 May  9 11:10 sys
drwxr-x---. 2 root root       48 May  9 11:10 test
drwxr-x---. 2 root root      174 May  9 11:10 world
-rw-r-----. 1 root root      104 May  9 11:10 xtrabackup_binlog_info
-rw-r-----. 1 root root      141 May  9 11:36 xtrabackup_checkpoints
-rw-r-----. 1 root root      607 May  9 11:10 xtrabackup_info
-rw-r-----. 1 root root  8388608 May  9 11:36 xtrabackup_logfile
-rw-r--r--. 1 root root        1 May  9 11:36 xtrabackup_master_key_id
drwxr-x---. 2 root root     4096 May  9 11:10 zrblog
[root@localhost data]# chown -R mysql.mysql *
[root@localhost data]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/data/mysql.log'.
 SUCCESS!

XBK增量备份

备份方式:基于上次的备份的增量

增量备份不能单独恢复,必须合并到全备中,一起恢复。

# 全备
[root@localhost bak]# innobackupex --defaults-file=/etc/my.cnf --user=root --password=123 --no-timestamp /data/bak/full_$(date +%F)
[root@localhost bak]# ll
total 4
drwxr-x---. 13 root root 4096 May  9 12:06 full_2021-05-09

# 模拟周一的数据变化
mysql> create database xbk charset utf8mb4;
mysql> use xbk;
mysql> create table t1(id int);
mysql> insert into t1 values(1),(2),(3);
mysql> commit;

# 周一晚上的增量备份
[root@localhost bak]# innobackupex --defaults-file=/etc/my.cnf --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/data/bak/full_2021-05-09 /data/bak/inc1_$(date +%F)

# 模拟周二的数据变化
mysql> use xbk;
mysql> create table t2(id int);
mysql> insert into t2 values(1),(2),(3);
mysql> commit;

# 周二晚上的增量备份
[root@localhost bak]# innobackupex --defaults-file=/etc/my.cnf --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/data/bak/inc1_2021-05-09 /data/bak/inc2_$(date +%F)

XBK增量恢复

1、合并所有增量到全备

2、每个XB备份都需要恢复准备(prepare)

--apply-log --redo-only

1.整理全备
innobackupex --apply-log --redo-only /data/bak/full_2021-05-09

2.整理并合并周一增量到全备
innobackupex --apply-log --redo-only --incremental-dir=/data/bak/inc1_2021-05-09  /data/bak/full_2021-05-09

3.整理并合并周二的增量到全备
innobackupex --apply-log --redo-only --incremental-dir=/data/bak/inc2_2021-05-09  /data/bak/full_2021-05-09

4.再次整理全备
innobackupex --apply-log /data/bak/full_2021-05-09

5.停止Mysql实例,并且删除数据目录下的所有文件
[root@localhost bak]# /etc/init.d/mysqld stop
[root@localhost bak]# rm -rf /data/mysql/data/*

6.恢复数据
[root@localhost bak]# innobackupex --copy-back /data/bak/full_2021-05-09
[root@localhost data]# chown -R mysql.mysql /data/mysql/data/*

7.验证数据完整性
[root@localhost data]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/data/mysql.log'.
 SUCCESS!
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| gg                 |
| mdp                |
| mysql              |
| oldboy             |
| oldboy2            |
| performance_schema |
| school             |
| sys                |
| test               |
| world              |
| xbk                |
| zrblog             |
+--------------------+
13 rows in set (0.01 sec)

mysql> use xbk;
mysql> show tables;
+---------------+
| Tables_in_xbk |
+---------------+
| t1            |
| t2            |
+---------------+

mysql> select * from t2;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

XBK full+inc+binlog 案例

某中型互联网公司,数据量级600G,每日数据量15-50M

备份策略:周日XBK全备 + 周一到周六inc增量备份+binlog备份。每天23:00进行。

故障描述:周三下午2点,数据由于某原因数据损坏。

处理思路:

1.整理合并所有备份 full + inc1 + inc2
2.截取周二晚上到周三下午故障之间的binlog日志
3.恢复全备,恢复binlog
4.验证数据完整性

处理结果:

经过70-80分钟处理,业务恢复

模拟环境:数据+故障

# 周日全备
[root@localhost bak]# innobackupex --defaults-file=/etc/my.cnf --user=root --password=123 --no-timestamp /data/bak/full

# 模拟周一的数据变化
mysql> create database oss charset utf8mb4;
mysql> use oss;
mysql> create table t1(id int);
mysql> insert into t1 values(1),(2),(3);
mysql> commit;

# 模拟周一晚上的增量备份
[root@localhost bak]# innobackupex --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/data/bak/full /data/bak/inc1

# 模拟周二的数据变化
mysql> insert into t1 values(11),(22),(33);
mysql> commit;

# 模拟周二晚上的增量备份
[root@localhost bak]# innobackupex --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/data/bak/inc1 /data/bak/inc2

# 模拟周三的数据变化
mysql> insert into t1 values(111),(222),(333);
mysql> commit;

# 有个员工把数据库data目录下的数据全部都给删掉了
[root@localhost bak]# /etc/init.d/mysqld stop
Shutting down MySQL.. SUCCESS!
[root@localhost data]# rm -rf /data/mysql/data/*

数据恢复

# 整理全备
[root@localhost data]# innobackupex --apply-log --redo-only /data/bak/full

# 合并inc1到full
[root@localhost data]# innobackupex --apply-log --redo-only --incremental-dir=/data/bak/inc1 /data/bak/full

# 合并inc2到full
[root@localhost data]# innobackupex --apply-log --redo-only --incremental-dir=/data/bak/inc2 /data/bak/full

# 整体整理
[root@localhost data]# innobackupex --apply-log /data/bak/full

# 恢复整理好的全备数据到数据库
[root@localhost bak]# innobackupex --copy-back /data/bak/full
[root@localhost bak]# chown -R mysql.mysql /data/mysql/data/*
[root@localhost bak]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/data/mysql.log'.
 SUCCESS!

# 查看inc2中的xtrabackup_binlog_info信息
[root@localhost bak]# cat /data/bak/inc2/xtrabackup_binlog_info
mysql-bin.000018        1288    1839d529-b068-11eb-8f64-080027fb878b:1,
42725169-b078-11eb-ba4c-080027fb878b:1-5,
49fa3c6a-b081-11eb-ab05-080027fb878b:1-5,
7a9f76ed-b08d-11eb-a5ac-080027fb878b:1-4, ******
a6927d77-b08a-11eb-b910-080027fb878b:1-5,
b9462caa-b08c-11eb-bbb4-080027fb878b:1-9,
d0b3b659-b088-11eb-9d15-080027fb878b:1-7,
f98d1e0b-a7e4-11eb-8259-080027fb878b:1-287

# 发现当前使用的是 7a9f76ed-b08d-11eb-a5ac-080027fb878b GTID
# 根据分析,7a9f76ed-b08d-11eb-a5ac-080027fb878b:1-4,已经包含 1-4,那么就从第五的事务开始截取到最后
mysql> show binlog events in 'mysql-bin.000018';
SET @@SESSION.GTID_NEXT= '7a9f76ed-b08d-11eb-a5ac-080027fb878b:5' 

# 截取日志
[root@localhost bak]# mysqlbinlog --skip-gtids --include-gtids='7a9f76ed-b08d-11eb-a5ac-080027fb878b:5' /data/binlog/mysql-bin.000018 >/data/bak/bin.sql

# 恢复数据
mysql> set sql_log_bin=0;
mysql> source /data/bak/bin.sql

# 验证数据一致性
mysql> select * from t1;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|   11 |
|   22 |
|   33 |
|  111 |
|  222 |
|  333 |
+------+
9 rows in set (0.00 sec)

远程推送备份

# 备份完并使用ssh推送到指定服务器的目录下命名为/data/full.tgz
innobackupex --user-root --password=123 --defaults-file=/etc/my.cnf --no-timestamp --stream=tar --use-memory=256M --parallel=8 /data/bak/full | gzip | ssh root@10.1.1.1" cat - > /data/full.tgz"

Mysql数据迁移

  • 换主机(性能更强的硬件主机):

    1.在线 MDP XBK 备份出来,scp到目标主机恢复
    2.追加所有备份后的日志
    3.申请停机5分钟
    4.剩余的binlog继续恢复(搭建主从的方式来代替)
    5.校验数据
    6.进行业务切换
    7.数据量大用主从架构
    
  • 换版本升级:

    # 方法一
    新机器安装5.7,5.6使用逻辑备份mysqldump按业务库做备份,排除掉information_schema,performance_schema,sys, 在5.7中恢复,之后升级数据字典。
    
    # 方法二
    主从进行过滤复制,排除掉information_schema,performance_schema,sys
    
  • 异构迁移(系统不一样):

    只能用逻辑备份 mysqldump
    
  • 异构迁移(数据库产品不同):

    Oracle -- OGG -- MYSQL
    MYSQL -- CSV(格式) -- MongoDB
    MYSQL8.0 -- JSON -- MongoDB
    

作者:Soulboy