跳转至

mysql数据备份

#mysql客户端
mysql
mysqladmin
mysqldump
备份的原因
1.备份就是为了恢复。
2.尽量减少数据的丢失(公司的损失)

备份的类型

1.冷备:停库,停服务,备份
2.热备:不停库,不停服务,备份
3.温备:不停服务,锁表(阻止数据写入),备份
#冷备份:
这些备份在用户不能访问数据时进行,因此无法读取或修改数据。这些脱机备份会阻止执行任何使用数据的活动。这些类型的备份不会干扰正常运行的系统的性能。但是,对于某些应用程序,会无法接受必须在一段较长的时间里锁定或完全阻止用户访问数据。
#温备份:
这些备份在读取数据时进行,但在多数情况下,在进行备份时不能修改数据本身。这种中途备份类型的优点是不必完全锁定最终用户。但是,其不足之处在于无法在进行备份时修改数据集,这可能使这种类型的备份不适用于某些应用程序。在备份过程中无法修改数据可能产生性能问题。
#热备份:
这些动态备份在读取或修改数据的过程中进行,很少中断或者不中断传输或处理数据的功能。使用热备份时,系统仍可供读取和修改数据的操作访问。

备份的策略

1.全备:全部数据备份
2.增备:针对于上一次备份,将新数据备份
3.差异备份:基于上一次全备进行新数据的备份

备份方式

- 逻辑备份
#基于SQL语句的备份
1.binlog
2.into outfile
    [root@db03 data]# vim /etc/my.cnf
    [mysqld]
    secure-file-priv=/tmp
    mysql> select * from world.city into outfile '/tmp/world_city.data';

3.mysqldump
4.replication
- 物理备份
#备份底层的数据文件
1.备份整个data数据目录
2.xtrabackup

mysqldump客户端

- 常用参数
1.不加参数:用于备份单个表
    1)备份库
    [root@db02 ~]# mysqldump ku > /tmp/ku.sql
    2)备份表
    [root@db02 ~]# mysqldump ku test > /tmp/ku.sql
    3)备份多个表
    [root@db02 ~]# mysqldump ku test test2 test3 > /tmp/ku.sql
    #注意:当不加参数时命令后面跟的是库名,库的后面全都是必须是库下面的表名

2.连接服务端参数(基本参数):-u -p -h -P -S

3.-A, --all-databases:全库备份

4.-B:指定库备份
[root@db01 ~]# mysqldump -uroot -p123 -B db1 > /backup/db1.sql
[root@db01 ~]# mysqldump -uroot -p123 -B db1 db2 > /backup/db1_db2.sql

5.-F:flush logs在备份时自动刷新binlog(不怎么常用)
[root@db01 backup]# mysqldump -uroot -p123 -A -F > /backup/full_2.sql

6.--master-data=2:备份时加入change master语句0没有1不注释2注释
    1)等于2:记录binlog信息,并注释(日常备份)
    2)等于1:记录binlog信息,不注释(扩展从库)
    0)等于0:不记录binlog信息
    [root@db01 backup]# mysqldump -uroot -p123 --master-data=2 >/backup/full.sql

7.--single-transaction:快照备份

8.-d:仅表结构
9.-t:仅数据

10.-R, --routines:备份存储过程和函数数据
11.--triggers:备份触发器数据
12.gzip:压缩备份
    #备份成压缩包
    [root@db01 ~]# mysqldump -uroot -p123 -A | gzip > /backup/full.sql.gz
    #恢复压缩包中的数据
    [root@db03 ~]# zcat /tmp/full.sql.gz | mysql -uroot -p123

#完整的备份命令:
mysqldump -uroot -p123 -A -R --triggers --master-data=2 –-single-transaction > /tmp/full.sql

- 注意:
1)mysqldump在备份和恢复时都需要MySQL实例启动为前提
2)一般数据量级100G以内,大约15-30分钟可以恢复
3)mysqldump是以覆盖的形式恢复数据的

- 思考
数据库或表被误删除的是很久之前创建的(一年前,100个binlog)
如果基于binlog全量恢复,成本很高
1.可以用备份恢复+短时间内二进制日志,恢复到故障之前
2.非官方方法,binlog2sql,binlog取反,类似于Oracle的flushback
3.延时从库 

如果同一时间内和故障库无关的数据库都有操作,在截取binlog时都会被截取到
其他过滤方案?
1.-d 参数接库名

企业案例

- 背景
1.正在运行的网站系统,MySQL数据库,数据量25G,日业务增量10-15M。
2.备份策略:每天23:00,计划任务调用mysqldump执行全备脚本
3.故障时间点:上午10点开发人员误删除一个核心业务表,如何恢复?

- 思路
1.停库,避免二次伤害
2.创建新库
3.倒入前一天的全备
4.通过binlog找到前一天23:00到第二天10点之间的数据
5.导入找到的新数据
6.恢复业务
    a.直接使用临时库顶替原生产库,前端应用割接到新库(数据量特别大的时候)
    b.将误删除的表单独导出,然后导入到原生产环境(数据量小的时候)

- 模拟案例
模拟生产数据
mysql> create database del;
Query OK, 1 row affected (0.00 sec)
{1}
mysql> use del
Database changed
mysql> create table del  select * from world.city;
Query OK, 4079 rows affected (0.04 sec)
Records: 4079  Duplicates: 0  Warnings: 0
{1}
mysql> select count(*) from del;
+----------+
| count(*) |
+----------+
|     4079 |
+----------+
1 row in set (0.00 sec)
{1}
mysql> insert del select * from del;
Query OK, 4079 rows affected (0.06 sec)
Records: 4079  Duplicates: 0  Warnings: 0
{1}
mysql> insert del select * from del;
Query OK, 8158 rows affected (0.05 sec)
Records: 8158  Duplicates: 0  Warnings: 0
{1}
mysql> insert del select * from del;
Query OK, 16316 rows affected (0.07 sec)
Records: 16316  Duplicates: 0  Warnings: 0
{1}
mysql> insert del select * from del;
Query OK, 32632 rows affected (0.12 sec)
Records: 32632  Duplicates: 0  Warnings: 0
{1}
mysql> select count(*) from del;
+----------+
| count(*) |
+----------+
|    65264 |
+----------+
1 row in set (0.01 sec)

- 模拟23:00全备
mysqldump -uroot -p1 -A -R --triggers --master-data=2 --single-transaction > /root/full.sql

- 模拟23:00到10:00的数据操作
mysql> use del
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> insert del select * from del;
Query OK, 65264 rows affected (0.33 sec)
Records: 65264  Duplicates: 0  Warnings: 0

mysql> 
mysql> insert del select * from del;
Query OK, 130528 rows affected (0.91 sec)
Records: 130528  Duplicates: 0  Warnings: 0

mysql> select count(*) from del;
+----------+
| count(*) |
+----------+
|   261056 |
+----------+
1 row in set (0.06 sec)

- 模拟删库
mysql> drop database del;
Query OK, 1 row affected (0.05 sec)

恢复数据

方案一
1)停库,避免二次伤害
systemctl stop mysqld.service
2)通过binlog找到前一天23:00到第二天10点之间的数据
# 起始位置:
head -22 full.sql | tail -1
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000015', MASTER_LOG_POS=1763;

#结束位置:
mysqlbinlog /usr/local/mysql/data/mysql-bin.000015 > 1.txt
tail 1.txt

# at 2179
#200722 23:24:50 server id 9  end_log_pos 2268 CRC32 0x3e598d51     Query   thread_id=8 exec_time=0 error_code=0
SET TIMESTAMP=1595431490/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
drop database del

mysqlbinlog -d del --start-position=4268431 --stop-position=17069047 /usr/local/mysql/data/mysql-bin.000005 > /root/new.sql
3)创建新数据库
4)将binlog与全备发往新数据库
scp /root/*.sql 172.16.1.53:/root/
root@172.16.1.53\'s password: 
full.sql                                            100% 3694KB  47.4MB/s   00:00    
new.sql                                             100% 2093   789.9KB/s   00:00 
5)将数据导入新库
mysql> source /root/full.sql;
mysql> source /root/new.sql;
6)确认数据
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| del                |
| dsb                |
| mysql              |
| performance_schema |
| sss                |
| test               |
| world              |
+--------------------+
8 rows in set (0.00 sec)

mysql> use del
Database changed
mysql> select count(*) from del;
+----------+
| count(*) |
+----------+
|   261056 |
+----------+
1 row in set (0.06 sec)
7)恢复业务
1.直接使用临时库顶替原生产库,前端应用割接到新库(数据量特别大的时候)
2.将误删除的表单独导出,然后导入到原生产环境(数据量小的时候)
    1)新库导出指定业务库
    [root@db02 ~]# mysqldump dump > /tmp/dump.sql
    2)新库将数据推送回老库
    [root@db02 ~]# scp /tmp/dump.sql 172.16.1.53:/tmp
    3)将恢复的数据导入老库
    mysql> create database dump;
    mysql> use dump;
    mysql> source /tmp/dump.sql

方案二:
1)停库,避免二次伤害
systemctl stop mysqld.service
2)通过binlog找到前一天23:00到第二天10点之间的数据
# 起始位置:
head -22 full.sql | tail -1
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000015', MASTER_LOG_POS=1763;

#结束位置:
mysqlbinlog /usr/local/mysql/data/mysql-bin.000015 > 1.txt
tail 1.txt

# at 2179
#200722 23:24:50 server id 9  end_log_pos 2268 CRC32 0x3e598d51     Query   thread_id=8 exec_time=0 error_code=0
SET TIMESTAMP=1595431490/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
drop database del

mysqlbinlog -d del --start-position=4268431 --stop-position=17069047 /usr/local/mysql/data/mysql-bin.000005 > /root/new.sql
3)创建新数据库
4)将binlog与全备发往新数据库
scp /root/*.sql 172.16.1.53:/root/
root@172.16.1.53\'s password: 
full.sql                                            100% 3694KB  47.4MB/s   00:00    
new.sql                                             100% 2093   789.9KB/s   00:00 
5)将数据导入新库
mysql> source /root/full.sql;
mysql> source /root/new.sql;
6)确认数据
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| del                |
| dsb                |
| mysql              |
| performance_schema |
| sss                |
| test               |
| world              |
+--------------------+
8 rows in set (0.00 sec)

mysql> use del
Database changed
mysql> select count(*) from del;
+----------+
| count(*) |
+----------+
|   261056 |
+----------+
1 row in set (0.06 sec)
7)导出del库并发回原数据库
mysqldump  -R --triggers --master-data=2 --single-transaction -B  del > del.sql

scp del.sql 172.16.1.54:/root/
root@172.16.1.54's password: 
del.sql                                             100%   11MB  76.6MB/s   00:00
8)导入原数据库
mysql> source /root/del.sql;

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| del                |
| dsb                |
| mysql              |
| performance_schema |
| sss                |
| test               |
| world              |
+--------------------+
8 rows in set (0.00 sec)

方案三:
1)停库,避免二次伤害
systemctl stop mysqld.service
2)通过binlog找到前一天23:00到第二天10点之间的数据
# 起始位置:
head -22 full.sql | tail -1
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000015', MASTER_LOG_POS=1763;

#结束位置:
mysqlbinlog /usr/local/mysql/data/mysql-bin.000015 > 1.txt
tail 1.txt

# at 2179
#200722 23:24:50 server id 9  end_log_pos 2268 CRC32 0x3e598d51     Query   thread_id=8 exec_time=0 error_code=0
SET TIMESTAMP=1595431490/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
drop database del

mysqlbinlog -d del --start-position=4268431 --stop-position=17069047 /usr/local/mysql/data/mysql-bin.000005 > /root/new.sql
3)干掉data目录并重新生成
cd /usr/local/mysql/data/
rm -rf *
cd ../scripts/
./mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
4)导入数据并查看
mysql> source /root/full.sql;
mysql> source /root/new.sql;

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| del                |
| dsb                |
| mysql              |
| performance_schema |
| sss                |
| test               |
| world              |
+--------------------+
8 rows in set (0.00 sec)

mysql> use del 
Database changed
mysql> select count(*) from del;
+----------+
| count(*) |
+----------+
|   261056 |
+----------+
1 row in set (0.05 sec)

物理备份Xtrabackup

安装
#上传文件包
rz percona-xtrabackup-24-2.4.4-1.el6.x86_64.rpm
#下载epel源
wget -O /etc/yum.repos.d/epel.repo  https://mirrors.aliyun.com/repo/epel-6.repo
#安装依赖
yum -y install perl perl-devel libaio libaio-devel perl-Time-HiRes perl-DBD-MySQL
#下载Xtrabackup
wget httpss://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.4.4/binary/redhat/6/x86_64/percona-xtrabackup-24-2.4.4-1.el6.x86_64.rpm
#安装
yum localinstall -y percona-xtrabackup-24-2.4.4-1.el6.x86_64.rpm
#安装好后的命令
xtrabackup
innobackupex

Xtrabackup备份

1)对于非innodb表(比如myisam)是直接锁表cp数据文件,属于一种温备。
2)对于innodb的表(支持事务),不锁表,cp数据页最终以数据文件方式保存下来,并且把redo和undo一并备走,属于热备方式。
3)备份时读取配置文件/etc/my.cnf(如果使用Xtrabackup备份,必须要配置datadir)
Xtrabackup全量备份
1)准备备份目录
    mkdir /backup
2)备份(全备)
innobackupex --user=root --password=123 /backup/full

#去掉时间戳进行备份
innobackupex --user=root --password=123 --no-timestamp /backup/full
3)查看全备内容
[root@db03 ~]# ll /backup/full/
总用量 129052
-rw-r----- 1 root root      434 7月  23 08:51 backup-my.cnf
drwxr-x--- 2 root root       68 7月  23 08:51 dump
-rw-r----- 1 root root 79691776 7月  23 08:51 ibdata1
-rw-r----- 1 root root 52428800 7月  23 08:51 ibdata2
drwxr-x--- 2 root root     4096 7月  23 08:51 mysql
drwxr-x--- 2 root root     4096 7月  23 08:51 performance_schema
drwxr-x--- 2 root root       68 7月  23 08:51 row
drwxr-x--- 2 root root       20 7月  23 08:51 test
-rw-r----- 1 root root       21 7月  23 08:51 xtrabackup_binlog_info         #记录binlog的信息
-rw-r----- 1 root root      113 7月  23 08:51 xtrabackup_checkpoints         
-rw-r----- 1 root root      483 7月  23 08:51 xtrabackup_info                #工具或数据的信息
-rw-r----- 1 root root     2560 7月  23 08:51 xtrabackup_logfile             #redo-log

[root@db03 full]# cat xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 8417759

- Xtrabackup全备恢复数据
1)删除所有数据库
drop database dump;

drop database performance_schema;

drop database row;

drop database test;
2)停止数据库
systemctl stop mysqld.service
3)手动模拟CSR的过程
#将redo进行重做,已提交的写到数据文件,未提交的使用undo回滚,模拟CSR的过程
innobackupex --user=root --password=123 --apply-log /backup/full
4)恢复数据
1>方法一:
#移走原数据目录
[root@db03 mysql]# mv data data.back

#将全备的数据目录迁移回来
[root@db03 mysql]# cp -r /backup/full ./data

[root@db03 mysql]# chown -R mysql.mysql data
2>方法二:
#使用innobackupex恢复数据
[root@db03 mysql]# innobackupex --copy-back /backup/full/
[root@db03 mysql]# chown -R mysql.mysql data
5)启动数据库查看数据
#启动数据库
[root@db03 data]# systemctl start mysqld

[root@db03 data]# mysql -uroot -p123
mysql> show databases;
Xtrabackup增量备份
1.基于上一次备份进行增量
2.增量备份无法单独恢复,必须基于全备进行恢复
3.所有增量必须要按顺序合并到全备当中
1)先全备
innobackupex --user=root --password=123 --no-timestamp /backup/full_$(date +%F)
2)写入新数据
[root@db03 ~]# mysql -uroot -p123
mysql> use dump
mysql> insert dump values(10000),(20000),(30000);
3)第一次增备
[root@db01 ~]# innobackupex --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/backup/full_2020-07-23 /backup/inc1

参数说明:
--incremental:开启增量备份功能
--incremental-basedir:上一次备份的路径

#验证
[root@db03 ~]# cat /backup/full/xtrabackup_checkpoints 
backup_type = full-prepared
from_lsn = 0
to_lsn = 8417759
[root@db03 ~]# cat /backup/inc1/xtrabackup_checkpoints 
backup_type = incremental
from_lsn = 8417759
to_lsn = 8419281
4)再次写入数据
[root@db03 ~]# mysql -uroot -p123
mysql> use dump
mysql> insert dump values(100000),(200000),(300000);
5)第二次增备
innobackupex --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/backup/inc1/ /backup/inc2

#验证
[root@db03 backup]# cat /backup/full_2020-07-23/xtrabackup_checkpoints 
backup_type = full-backuped
from_lsn = 0
to_lsn = 1636167

[root@db03 backup]# cat /backup/inc1/xtrabackup_checkpoints 
backup_type = incremental
from_lsn = 1636167
to_lsn = 1640828

[root@db03 backup]# cat /backup/inc2/xtrabackup_checkpoints 
backup_type = incremental
from_lsn = 1640828
to_lsn = 1645877
6)再次写入数据
7)第三次增量备份
innobackupex --user=root --no-timestamp --incremental --incremental-basedir=/backup/inc2 /backup/inc3
Xtrabackup增量恢复数据
1)将全备执行redo
innobackupex --apply-log --redo-only /backup/full_2020-07-23
2)将第一次增备只执行redo并合并到第一次全备
innobackupex --apply-log --redo-only --incremental-dir=/backup/inc1/ /backup/full_2020-07-23

#验证
[root@db03 backup]# cat /backup/full_2020-07-23/xtrabackup_checkpoints 
backup_type = log-applied
from_lsn = 0
to_lsn = 1640828            #该值本来是inc1的位置点
3)将第二次增备只执行redo并合并到第一次全备
innobackupex --apply-log --redo-only --incremental-dir=/backup/inc2/ /backup/full_2020-07-23

#验证
[root@db03 backup]# cat /backup/full_2020-07-23/xtrabackup_checkpoints 
backup_type = log-applied
from_lsn = 0
to_lsn = 1645877            #该值本来是inc2的位置点
4)将最后一次增备执行redo和undo并合并到第一次全备
innobackupex --apply-log --incremental-dir=/backup/inc3/ /backup/full_2020-07-23

#验证
[root@db03 backup]# 
[root@db03 backup]# cat /backup/full_2020-07-23/xtrabackup_checkpoints 
backup_type = full-prepared
from_lsn = 0
to_lsn = 1649869
5)将整体数据进行一次CSR(Control system recovery?)
innobackupex --apply-log /backup/full_2020-07-23/
6)恢复数据
[root@db03 mysql]# mv data data.bak
[root@db03 mysql]# innobackupex --copy-back /backup/full_2020-07-23/
[root@db03 mysql]# chown -R mysql.mysql data
[root@db03 mysql]# systemctl start mysqld
总结
1.增备:
    优点:占用磁盘空间小,没有重复数据
    缺点:恢复麻烦

2.全备:
    优点:恢复只需一次
    缺点:占用磁盘空间,每次全备都有重复数据
思考
企业级增量恢复实战

背景:
某大型网站,mysql数据库,数据量500G,每日更新量100M-200M

备份策略:
xtrabackup,每周六0:00进行全备,周一到周五及周日00:00进行增量备份。

故障场景:
周三下午2点出现数据库意外删除表操作。

1. xtrabackup恢复
2. binlog恢复