一、认识数据库备份
1、MySQL备份原理详解
- 备份是数据安全的最后一道防线,对于任何数据丢失的场景,备份虽然不一定能恢复百分之百的数据(取决于备份周期),但至少能将损失降到最低。
- 衡量备份恢复有两个重要的指标:恢复点目标(RPO)和恢复时间目标(RTO),前者重点关注能恢复到什么程度,而后者则重点关注恢复需要多长时间。
2、常见的备份方式 ---- 冷备份
- 最简单的备份方式就是,关闭MySQL服务器,然后将data目录下面的所有文件进行拷贝保存,需要恢复时,则将目录拷贝到需要恢复的机器即可。
- 这种方式确实方便,但是在生产环境中基本没什么作用。因为所有的机器都是要提供服务的,即使是Slave有时候也需要提供只读服务,所以关闭MySQL停服备份是不现实的。
- 与冷备份相对应的一个概念是热备份,所谓热备份是在不影响MySQL对外服务的情况下,进行备份,热备份是我们讨论的重点。
3、常见的备份方式 ---- 热备份
3.1、快照备份
- 首先要介绍的热备份是快照备份,快照备份是指通过文件系统支持的快照功能对数据库进行备份。
- 备份的原理是将所有的数据库文件放在同一分区中,然后对该分区执行快照工作,对于Linux而言,需要通过LVM(Logical Volumn Manager)来实现。
- LVM使用写时复制(copy-on-write)技术来创建快照,例如,对整个卷的某个瞬间的逻辑副本,类似于数据库中的innodb存储引擎的MVCC,只不过LVM的快照在文件系统层面,而MVCC在数据库层面,而且仅支持innodb存储引擎。
- LVM有一个快照预留区域,如果原始卷数据有变化时,LVM保证在任何变更写入之前,会复制受影响块到快照预留区域。简单来说,快照区域内保留了快照点开始时的一致的所有old数据。
- 对于更新很少的数据库,快照也会非常小。
- 对于MySQL而言,为了使用快照备份,需要将数据文件,日志文件都放在一个逻辑卷中,然后对该卷快照备份即可。
- 由于快照备份,只能本地,因此,如果本地的磁盘损坏,则快照也就损坏了。
- 快照备份更偏向于对误操作防范,可以将数据库迅速恢复到快照产生的时间点,然后结合二进制日志可以恢复到指定的时间点。
基本原理如下图:
3.2、逻辑备份
- 冷备份和快照备份由于其弊端在生产环境中很少使用,使用更多是MySQL自带的逻辑备份和物理备份工具,这节主要讲逻辑备份
- MySQL官方提供了Mysqldump逻辑备份工具,虽然已经足够好,但存在单线程备份慢的问题。
- 在社区提供了更优秀的逻辑备份工具mydumper,它的优势主要体现在多线程备份,备份速度更快。
3.2.1、Mysqldump
-
Mysqldump用于备份,不得不提两个关键的参数:
--single-transaction
:在开始备份前,执行start transaction
命令,以此来获取一致性备份,该参数仅对innodb
存储引擎有效。--master-data=2
:主要用于记录一致性备份的位点。
-
理解Mysqldump工作原理
- 一定要将事务表(innodb)和非事务表(比如myisam)区别对待,因为备份的流程与此息息相关。
- 而且,到目前为止,我们也无法规避myisam表,即使我们的所有业务表都是innodb,因为mysql库中系统表仍然采用的myisam表。
- 备份的基本流程如下:
1、调用FTWRL(flush tables with read lock),全局禁止读写
2、开启快照读,获取此时的快照(仅对innodb表起作用)
3、备份非innodb表数据(.frm,.myi,*.myd等)
4、非innodb表备份完毕后,释放FTWRL锁
5 、逐一备份innodb表数据
6、备份完成。
整个过程,可以参考下面一张图,但这张图只考虑innodb表的备份情况,实际上在unlock tables执行完毕之前,非innodb表已经备份完毕,后面的t1,t2和t3实质都是innodb表,而且5.6的mysqldump利用保存点机制,每备份完一个表就将一个表上的MDL锁释放,避免对一张表锁更长的时间。这里可以参考:FLUSH TABLE WITH READ LOCK
说明:
大家可能有一个疑问,为啥备份innodb表之前,就已经将锁释放掉了,这实际上是利用了innodb引擎的MVCC机制,开启快照读后(set transaction isolation level repeatable read
),就能获取那个时间的一致的数据,无论需要备份多长时间,直到整个事务结束(commit
)为止。当然,这个RR级别的快照,对表的元数据也有要求,因为逻辑备份表是一个个进行的,如果在备份某个表之前,这个表做了DDL操作(此时备份事务暂时还没有加MDL
锁),后续再备份这个表时,就会因为表定义不一致而报错(Table definition has changed, please retry transaction
)。所以总地来说,通过保存点机制,可以有效减少DDL
操作的限制,但是也不能完全消除由于DDL操作导致的备份失败问题。
3.2.2、Mydumper
- Mydumper原理与Mysqldump原理类似,最大的区别是引入了多线程备份,每个备份线程备份一部分表,当然并发粒度可以到行级,达到多线程备份的目的。
- 这里要解决最大一个问题是,如何保证备份的一致性,其实关键还是在于FTWRL。
- 对于非innodb表,在释放锁之前,需要将表备份完成。对于innodb表,需要确保多个线程都能拿到一致性位点,这个动作同样要在持有全局锁期间完成,因为此时数据库没有读写,可以保证位点一致。
所以基本流程如下:
3.2.3、物理备份(Xtrabackup)
- 相对于逻辑备份利用查询提取数据中的所有记录,物理备份更直接,拷贝数据库文件和日志来完成备份,因此速度会更快。
- 当然,无论是开源的Mydumper还是官方最新的备份工具(5.7.11的mysqlpump)都支持了多线程备份,所以速度差异可能会进一步缩小,至少从目前生产环境来看,物理备份使用还是比较多的。
- 由于Xtrabackup支持备份innodb表,实际生产环境中我们使用的工具是innobackupex,它是对xtrabackup的一层封装。innobackupex 脚本用来备份非 InnoDB 表,同时会调用 xtrabackup 命令来备份 InnoDB 表
- innobackupex的基本流程如下:
1、开启redo日志拷贝线程,从最新的检查点开始顺序拷贝redo日志;
2、开启idb文件拷贝线程,拷贝innodb表的数据
3、idb文件拷贝结束,通知调用FTWRL,获取一致性位点
4、备份非innodb表(系统表)和frm文件
5、由于此时没有新事务提交,等待redo日志拷贝完成
6、最新的redo日志拷贝完成后,相当于此时的innodb表和非innodb表数据都是最新的
7、获取binlog位点,此时数据库的状态是一致的。
8、释放锁,备份结束。
完整备份过程如图::
** 说明 :**
我们知道MySQL里面有个double-write
为了防止写的时候页断裂,那么备份读的时候,有没有可能也只一半的page呢?这个其实是有可能的,因此,我们在拷贝page
的时候,需要对page
算checksum
,如果checksum
不符合预期,我们认为拷贝的页面不完整(这种情况可能发生在你在读页面,而后台线程正在刷脏),需要重试。所以,最终也能保证数据的一致性。
1、Xtrabackup的改进
- 无论是mysqldump,还是innobackupex备份工具,为了获取一致性位点,都强依赖于FTWRL。
- FTWRL这个锁杀伤力非常大,因为持有锁的这段时间,整个数据库实质上不能对外提供写服务的。
- 此外,由于FTWRL需要关闭表,如有大查询,会导致FTWRL等待,进而导致DML堵塞的时间变长。即使是备库,也有SQL线程在复制来源于主库的更新,上全局锁时,会导致主备库延迟。
- 从前面的分析来看,FTWRL这把锁持有的时间主要与非innodb表的数据量有关,如果非innodb表数据量很大,备份很慢,那么持有锁的时间就会很长。即使全部是innodb表,也会因为有mysql库系统表存在,导致会锁一定的时间。
- 为了解决这个问题,Percona公司对Mysql的Server层做了改进,引入了BACKUP LOCK。
- 具体而言,通过
”LOCK TABLES FOR BACKUP”
命令来备份非innodb表数据;通过”LOCK BINLOG FOR BACKUP”
来获取一致性位点,尽量减少因为数据库备份带来的服务受损。
我们看看采用这两个锁与FTWRL的区别:
- LOCK TABLES FOR BACKUP :
- 作用:备份数据
- 1.禁止非innodb表更新
- 2.禁止所有表的ddl
- 优化点:
- 1.不会被大查询堵塞(关闭表)
- 2.不会堵塞innodb表的读取和更新,这点非常重要,对于业务表全部是innodb的情况,则备份过程中DML完全不受损
UNLOCK TABLES
- 作用:备份数据
- LOCK BINLOG FOR BACKUP :
- 作用:获取一致性位点。
- 1.禁止对位点更新的操作
- 优化点:
- 1.允许DDl和更新,直到写binlog为止。
UNLOCK BINLOG
- 1.允许DDl和更新,直到写binlog为止。
- 作用:获取一致性位点。
2、准备和恢复数据阶段
过程如图:
- 首先应用xtrabackup日志提交事务应用到InnoDB,然后回滚未提交事务。
3、增量备份过程
- 对于增量备份只对InnoDB,MyISAM和其它引擎仍然是完整备份的方式,增量备份主要是处理InnoDB中有变更的页(页的LSN).LSN信息在
xtrabackup_checkpoints
中。
4、增量应用
5、恢复过程
6、流备份过程图
7、InnoDB表空间的结构
二、Xtrabackup安装配置
1、简单介绍Xtrabackup
- Xtrabackup是一个对InnoDB做物理数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品。
- Xtrabackup有两个主要的工具:xtrabackup、innobackupex
- (1)xtrabackup只能备份InnoDB和XtraDB两种数据表,而不能备份MyISAM数据表。
- (2)innobackupex是用来备份非InnoDB表的,同时会调用xtrabackup命令来备份InnoDB表,还会和mysql server发送命令进行交会,如加读锁、获取位点等。简单来说,innobackupex在xtrabackup之上做了一层封装。
一般情况下,我们是希望能备份MyISAM表的,虽然我们可能自己不用MyISAM表,但是mysql库下的系统表示MyISAM的,因此备份基本都通过innobackupex命令进行;另外一个原因是我们可能需要保存位点信息。
1.1、XtraBackup备份原理
- XtraBackup基于InnoDB的crash-recovery功能,它会复制InnoDB的data file,由于不锁表,复制出来的数据是不一致的,在恢复的时候使用crash-recovery,使得数据恢复一致。
- InnoDB维护了一个redo log,又称为transaction log(事务日志),它包含了InnoDB数据的所有改动情况。当InnoDB启动的时候,它会先去检查data file和transaction log,并且会做两步操作:
- XtraBackup在备份的时候,一页一页的复制InnoDB的数据,而且不锁定表,与此同时,XtraBackup还有另外一个线程监视着transaction log,一旦log发生变化,就把变化过的log pages复制走。为什么要着急复制走呢?因为transaction log文件大小有限,写满之后,就会从头再开始写,所以新数据可能会覆盖到旧的数据。
- 在prepare过程中,XtraBackup使用复制到的transaction log对备份出来的InnoDB data file进行crash recovery。
1.2、XtraBackup备份特点
(1) 备份过程快速、可靠
(2) 备份过程不会打断正在执行的事务
(3) 能够基于压缩等功能节约磁盘空间和流量
(4) 自动实现备份检验
(5) 还原速度快
2、 XtraBackup安装
官网yum源安装方法说明:https://www.percona.com/doc/percona-xtrabackup/LATEST/installation/yum_repo.html
2.1、yum安装
- 两种方式:
- 方式一:先安装yum源,再进行安装
- 方式二:直接本地安装rpm
# 安装yum源
yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
percona-release enable-only tools release
yum install -y percona-xtrabackup-24
xtrabackup -version
# 直接本地安装rpm包
yum localinstall percona-xtrabackup-24-2.4.11-1.el7.x86_64.rpm -y
xtrabackup -version
2.2、XtraBackup常用参数
参数 | 含义 |
---|---|
–user=USER | 指定备份用户,不指定的话为当前系统用户 |
–password=PASSWD | 指定备份用户密码 |
–port=PORT | 指定数据库端口 |
–defaults-group=GROUP-NAME | 在多实例的时候使用 |
–host=HOST | 指定备份的主机,可以为远程数据库服务器 |
–apply-log | 应用 BACKUP-DIR 中的 xtrabackup_logfile 事务日志文件。一般情况下,在备份完成后,数据尚且不能用于恢复操作,因为备份的数据中可能会包含尚未提交的事务或已经提交但尚未同步至数据文件中的事务。因此,此时数据文件仍处于不一致状态。“准备”的主要作用正是通过回滚未提交的事务及同步已经提交的事务至数据文件使得数据文件处于一致性状态。 |
–apply-log-only | 这个选项使在准备备份(prepare)时,只执行重做(redo)阶段,这对于增量备份非常重要。 |
–database | 指定需要备份的数据库,多个数据库之间以空格分开 |
–defaults-file | 指定mysql的配置文件 |
–copy-back | 将备份数据复制回原始位置 |
–incremental | 增量备份,后面跟要增量备份的路径 |
–incremental-basedir=DIRECTORY | 增量备份时使用指向上一次的增量备份所在的目录 |
–incremental-dir=DIRECTORY | 增量备份还原的时候用来合并增量备份到全量,用来指定全备路径 |
–redo-only | 对增量备份进行合并 |
–rsync | 加快本地文件传输,适用于non-InnoDB数据库引擎。不与–stream共用 |
–safe-slave-backup | 备份时检测从库是否有打开的临时表,如果没有就stop SQL thread开始备份,备份完后start SQL thread;如果有打开的临时表就等,直到–safe-slave-backup-timeout超时。–safe-slave-backup-timeout默认300s,每3s进行一次重试检查,共重试100次。这个参数和–slave-info经常一起使用,为了保证数据的一致性。 |
–slave-info | 在从库进行备份时,该参数会在备份目录下生成xtrabackup_slave_info文件,文件记录主库的binlog日志位置点。在进行数据库恢复,搭建多从库时都需要这个文件。如果在主库进行备份(在主库备份的情况很少,把主库惹怒了只能跑路了),该参数就不起作用了,主库的备份目录下始终会生成文件xtrabackup_binlog_info 记录binlog日志位置点。 |
–no-timestamp | 生成的备份文件不以时间戳为目录. |
2.3、使用XtraBackup
- 由于innobackupex命令既可以备份innodb又可以备份myisam表,因此主要介绍此工具的用法
备份slave库上的数据。加上此参数会输出master库上的binlog信息
--slave-info
2.3.1、 全备备份
- 全备份数据存放在
/data/20181129/
下面,若不加--no-timestamp
参数,innobackupex会自动创建一个文件夹+以当前系统时间命名的文件夹,我们的示例中就自定义目录了,当然也可以使用自动生成的目录
1.全量备份
/usr/bin/innobackupex /data/backup/full \
--defaults-file=/etc/my.cnf \
--socket=/var/lib/mysql/mysql.sock \
--host=127.0.0.1 \
--user=root \
--password=mvtech123 \
--no-timestamp \
--slave-info \
--parallel=2 \
--throttle=800
2.恢复全量备份
- 步骤如下:
1 关闭mysql
2 重命名mysql的数据目录和日志目录
mv /data/mysql/data /opt/
mv /data/mysql/log /opt/
3 应用日志
innobackupex --apply-log --use-memory=200G /data/20181129/
4 恢复 注:恢复有两种方式--move-back 和--copy-back,move-back速度快,但备份文件被move后就不存在,请根据实际情况进行选择
innobackupex --defaults-file=/etc/my.cnf --move-back /data/20181129/
5 修改权限
chown -R mysql:mysql /data/mysql
6 启动mysql
service mysqld start
2.3.2、增量备份
- 增量备份是在全量备份的基础上进行
流程如下:
- 增量备份
innobackupex --defaults-file=/etc/my.cnf --host=127.0.0.1 --user=root --password=mvtech123 --parallel=4 --throttle=400 --incremental-basedir=/data/20181129 --no-timestamp --slave-info --incremental /data/20181130
- 恢复
1 关闭mysql
2 重命名mysql的数据目录和日志目录
mv /data/mysql/data /data/mysql/data_20181129
mv /data/mysql/log /data/mysql/log_20181129
3 对全量备份做prepare
innobackupex --apply-log --redo-only /data/20181129
4 对增量备份做prepare
--redo-only:若只有一个增量备份或是最后那个增量备份文件,那么不需要这个选项,原因同上。也就是说这个选项不能用于最后一个增量备份进行prepare。
--incremental-dir=:此选项对应的目录为增量备份文件的目录
innobackupex --apply-log [--redo-only] /data/20181129 --incremental-dir=/data/20181130
5 查看prepare情况 查看全量备份文件中的xtrabackup_checkpoints
发现last_lsn = 508150192已经和最后一次备份一致
6 恢复 注:恢复有两种方式--move-back 和--copy-back,move-back速度快,但备份文件被move后就不存在,请根据实际情况进行选择
innobackupex --defaults-file=/etc/my.cnf --move-back /data/20181129/
7 修改权限
chown -R mysql:mysql /data/mysql
8 启动mysql
service mysqld start
2.4、生产全备示例脚本
#!/bin/bash
#This script is xtrabackup full backup mysql
#The Author is mvtech by 2018
#格式化日期
today=$(date +%Y%m%d)
deleteDay=`date -d "-1 days" +%Y%m%d`
echo "--------------------------------------------------------"
echo "-------------------Today is $today----------------------"
echo "--------------------Start backup------------------------"
echo "--------------------------------------------------------"
#定义变量
blxxDir="/data/xtrabackup/$today"
delDir="/data/xtrabackup/$deleteDay"
#创建备份文件夹
mkdir -p $blxxDir
#全量备份
/usr/bin/innobackupex --defaults-file=/etc/my.cnf --socket=/data/mysql/mysql.sock --host=10.99.0.81 --user=weihu --password=Mvtech123!@ $blxxDir --slave-info --no-timestamp --parallel=8 --throttle=800
#删除2天以前的备份
rm -rf $delDir
2.5、备份文件夹里文件说明
文件名称 | 文件用途 |
---|---|
ibdata1 | 备份的表空间文件 |
backup-my.cnf | 备份命令用到的配置选项信息; |
xtrabackup_binary | 备份中用到的xtrabackup的可执行文件; |
xtrabackup_binlog_info | 记录导出mysql的binlog信息; mysql服务器当前正在使用的二进制日志文件及至备份这一刻为止二进制日志事件的位置 |
xtrabackup_checkpoints | 记录备份方式:备份类型(如完全或增量)、备份状态(如是否已经为prepared状态)和LSN(日志序列号)范围信息; |
xtrabackup_info | 记录此次备份的详细信息 |
xtrabackup_logfile | 备份的重做日志文件 |
xtrabackup_slave_info | 记录备份slave节点时主机上的binlog信息,需要添加--slave-info 参数 |
演示:
# cat /data/20181129/xtrabackup_checkpoints
backup_type = full-backuped #可以看出是全备份
from_lsn = 0 #记录了LSN,日志偏移量
to_lsn = 8096126
last_lsn = 8096126
compact = 0
recover_binlog_info = 0