InnoDB 个性化备份

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 如果想知道如何使用xtrabackup,请翻阅之前的文章 xtrabackup核心文档 xtrabackup原理深入浅出 为什么要使用xtrabackup 常用的备份有哪些 性能对比 逻辑备份 vs 物理备份 逻辑备份优点: 占用空间小,安全 逻辑备份缺点: 恢复速度慢

如果想知道如何使用xtrabackup,请翻阅之前的文章 xtrabackup核心文档

xtrabackup原理深入浅出

为什么要使用xtrabackup

  • 常用的备份有哪些

back_type

  • 性能对比

back_time

  • 逻辑备份 vs 物理备份

    逻辑备份优点: 占用空间小,安全
    逻辑备份缺点: 恢复速度慢
    物理备份优点: 备份,恢复速度快
    物理备份缺点: 占用空间大
    
  • 如何选择,全凭业务场景

      如果类似facebook这种量级(PB,EB),考虑成本,建议逻辑备份
      如果只是上T级别,建议物理备份
      本人用的是物理备份,还有一个原因就是: 逻辑备份会遭到DDL的破坏
      试想,晚上经常有DDL这样的操作,备份任务不可能随意调整,这样带来的运维成本很大
    
  • 物理备份:InnoDB vs Myisam

Myisam引擎,只需要flush tables后,就可以随意拷贝文件
InnoDB可通过xtrabackup来拷贝文件

在5.6之前,我比较喜欢用Myisam引擎来做备份,原因是就是备份和恢复的速度以及随意拷贝的便利性
在5.6之后,由于可传输表空间的出现,让恢复单表变得简单,我更加愿意用InnoDB备份。关于可传输表空间,可阅读[transportable tablespace详解](http://keithlan.github.io/2016/04/21/transportable/)
用Myisam的一个致命弱点是:如果要还原成innoDB表,需要转换表引擎,痛苦的开始
至于InnoDB和Myisam的选择,就不用纠结了,因为之后的MySQL会废弃掉Myisam

什么是一致性备份

简单来说,就是备份的数据都处在同一时间点

non_consis

consis

percona xtrabackup基本概念

innobackupex 是一个perl写的脚本,为了方便,封装了xtrabackup,所以一般备份都用innobackupex
xtrabackup 只备份innoDB表 ,其余的都交给innobackupex
新版本如:2.4,2.3.xx 已经将innodbex用c 重写了,然后链接到xtrabackup

xtrabackup for 5.6 备份原理

  1. innobackupex 调用 xtrabackup --suspend-at-end
  2. xtrabackup 开始拷贝 innodb 数据文件,共享表空间
  3. 当xtrabackup拷贝完innodb文件后,会创建 xtrabackup_suspended_2
  4. 当innobackupex看到xtrabackup_suspended_2文件被创建后,进行加锁

    1. FLUSH NO_WRITE_TO_BINLOG TABLES
    2. FLUSH TABLES WITH READ LOCK
  5. innobackupex开始检查db server支持的特性,如:gtid,backup locks,changed page bitmap等
  6. 然后开始拷贝非innodb文件,以及表结构frm
  7. 当所有的文件都备份完成后,结束redo 事务的拷贝。
  8. 接下来释放锁

    1. FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS
    2. UNLOCK TABLES
  9. 删除xtrabackup_suspended_2文件 , 并且退出

innobackup

从上述流程图可以看出,FLUSH TABLES WITH READ LOCK【FTWRL】 这个时间点,就是备份恢复的时间点,即一致性点
因为数据再拷贝的过程中是不一致的,MySQL利用其自身的crash recover机制,用redo来保证最终一致性

这里,假设一种场景,InnoDB是16k的刷新,当刷新到4k的时候,拷贝线程来讲这个页拷贝走,这样不就人为的造成了一次partial-write了吗?
对于partial-write的场景,由于redo日志是物理逻辑的,通过redo没有办法恢复,这可如何是好呢?

这里是核心:

  1. xtrabackup方式: xtrabackup里面做了很多事情,它在拷贝的过程中使用innodb的buf_page_is_corrupted()函数检查此页的数据是否正常,如果不正常,再重新拷贝,尝试N次重试之后还不行,就退出报错。
  2. flush-method=O_direct,会直接从innodb buffer 写入到 磁盘,这个操作可能就会发生partial-write了。一旦发生这样的事情,MySQL是无法恢复的,所以,我们的备份必须保证脏页全部刷新完,也就是在备份程序中 a)必须保证没有写了 b)必须验证和检测Modified db pages是否等于0。 如果以上都ok,那么这个页肯定是完整的。除此之外,我们还有一招,就是多次rsync,确保完整。
  3. flush-method=默认 , 默认的会先从innodb buffer 写入到 OS缓存,这个操作是原子的,由操作系统保证。

生产环境如何备份

备份的意图:备份master或者slave上的数据,然后传输到一个挂有大磁盘的服务器上,保留若干天

问题1,如何传输到其他服务器呢?

  1. 这个问题,xtrabackup也考虑到了,用xbstream + ssh 的方式,但是有一个致命的缺点,就是无法断点续传,如果网络断掉,那就悲剧
  2. 另外一个方式就是:先xtrabackup到本地一个目录,然后用rsync【支持断点续传】来传送到远端服务器。 这种方法的致命缺点是:本地磁盘需要浪费一半的空间,且copy了两遍备份数据

以上两种方式都存在缺陷,那么我们不得不思考第三种方式,是否可以直接copy到远端机器呢?

  • 如果是在master上备份,那么直接copy是不行的,因为redo一直再变且轮询

master

  • 如果是在slave上,或者etl&backup机器上呢? 不难发现,xtrabackup记录了redo的变化,如果我们人为的让redo不再增长,stop slave,这样的备份原理是否和xtrabackup一样呢?

slave

这样做的好处是,不用浪费一半的空间,也不需要传送2次

你所不知道的秘密

commit

通过以上流程图,可以发现一个重要的线索:我们的物理备份,是不会备份binlog的【重要】
所以,友谊的小船说翻就翻

commit_1

对于5.1 & 5.5,用xtrabackup for 5.1 or 5.5 ,如果innodb_flush_log_at_trx_commit=1 ,应该没问题

commit_2

对于5.6 , 用xtrabackup for 5.1 or 5.5 , 即便如果innodb_flush_log_at_trx_commit=1,有可能会丢失事务

commit_3

对于5.6 , 用xtrabackup for 5.6, 不会丢失事务

直接copy innoDB的方式备份

好了,现在进入正题,我们是否可以类似Myisam的方式随意拷贝呢?

答案:可以

  • 第一种方法: 保持和Myiam一致就可以。

Myisam之所以可以随意拷贝,那是因为通过flush tables后,所有文件都会fsync到磁盘,这时候拷贝肯定没有问题。
InnoDB则不是,通过flush tables根本没有办法控制redo的刷新,data page的刷新以及ibdata的刷新。
所以,这里我们只要解决这三个问题即可。
redo: 我们可以通过innodb_flush_log_at_trx_commit=1来保证。
data page: 通过自身的checkpoint可以保证。
ibdata里面包含了:innodb table的数据字典信息,change buffer,doublewrite ,undo logs,这些目前好像还没有什么可以强制全部刷新。

所以,我们可以通过stop slave的方式,至少可以保证数据不丢失。至于ibdata里面的文件不刷新,也没太大关系,通过自身的crash-recover机制,自动修复。
所以,我们通过stop slave后,直接copy文件恢复的时候,你可能会看到这样的信息:

2016-05-26 13:47:24 15818 [Note] InnoDB: The log sequence numbers 2446418 and 2446418 in ibdata files do not match the log sequence number 2446945 in the ib_logfiles!
2016-05-26 13:47:24 15818 [Note] InnoDB: Database was not shutdown normally!
2016-05-26 13:47:24 15818 [Note] InnoDB: Starting crash recovery.
2016-05-26 13:47:24 15818 [Note] InnoDB: Reading tablespace information from the .ibd files...
2016-05-26 13:47:24 15818 [Note] InnoDB: Restoring possible half-written data pages
2016-05-26 13:47:24 15818 [Note] InnoDB: from the doublewrite buffer...
InnoDB: Last MySQL binlog file position 0 506, file name tjtx-101-141.000018
2016-05-26 13:47:25 15818 [Note] InnoDB: 128 rollback segment(s) are active.
2016-05-26 13:47:25 15818 [Note] InnoDB: Waiting for purge to start
2016-05-26 13:47:26 15818 [Note] InnoDB: 5.6.27 started; log sequence number 2446945
2016-05-26 13:47:26 15818 [Note] Recovering after a crash using /data/mysql.bin/tjtx-101-141
2016-05-26 13:47:26 15818 [Note] Starting crash recovery...
2016-05-26 13:47:26 15818 [Note] Crash recovery finished.

当你看到Crash recovery finished完成后,基本也就ok了。

好了,这里还有一个疑问我不太清楚,就是到底有多少个LSN

Log sequence number 2446945  -- redo log buffer 中的lsn,内存中记录
Log flushed up to   2446945  -- redo log file 的lsn,redo的每个lock block都会记录
Pages flushed up to 2446945  -- flush list中最后一个指针对应的page's newest modification(lsn)【last checkpoint newest modification】, 每个page的头部都会记录
Last checkpoint at  2446945  -- flush list中最后一个指针对应的page's oldest modification(lsn)【last checkpoint oldest modification】, 第一个redo的头部固定位置,存在头部的两个地方

那么错误日志中的The log sequence numbers xx in ibdata files ,又是啥呢?

经过测试:kill -9 mysqld
得到的结论是: 只要是非正常关闭的MySQL,都会出现这样的报错,即便是没有任何数据的MySQL
所以,我猜测,ibdata files中记录的lsn,从MySQL一启动,里面的lsn就会比redo中的lsn小,是专用于检测是否正常关闭MySQL的吗?
anyway,这都不影响我们innoDB在线拷贝的大局了。

好了,通过以上测试,我们已经明白,stop slave后,等一会会,当脏页刷新完的时候,就可以认为数据全部刷新到磁盘了,这样就和Myisam没有任何区别

ok,这里又引入了一个值得思考的问题,那就是: 怎么判断脏页已经刷完了呢?

检查4个lsn,当四个lsn都相等的时候,肯定刷完了。

Log sequence number 2446945
Log flushed up to   2446945
Pages flushed up to 2446945
Last checkpoint at  2446945

没错,当4个lsn都相等的时候,的确可以表示脏页已经刷完。

但是,当4个lsn不完全相等的时候,也有可能表示脏页刷完了。比如:

Log sequence number 2446945
Log flushed up to   2446945
Pages flushed up to 2446945
Last checkpoint at  2446747 --不一样

我来解读一下:
Last checkpoint 指的是最后一个脏页的oldest modification
Pages flushed up to 指的是最后一个脏页的newest modification

当我们再刷最后一个脏页的时候,这个脏页被多次更新,那么就表示该脏页的newest modification > oldest modification .
所以就不相等了,但是的确脏页也都刷新完了。

检查Modified db pages的值,这个值就表示flush list中还有多少个page没有被刷新,如果全为0,表示flush list中脏页全部刷新。

假设一个实例有2个BUFFER POOL instance,那么就要检查两个Modified db pages 是否都为0

---BUFFER POOL 0
Buffer pool size   655359
Free buffers       1000
Database pages     636541
Old database pages 234953
Modified db pages  0  -- 表示这个buffer pool中的脏页已经刷新完
Pending reads 0

---BUFFER POOL 1
Buffer pool size   655359
Free buffers       1000
Database pages     636426
Old database pages 234910
Modified db pages  0 -- 表示这个buffer pool中的脏页已经刷新完
Pending reads 0

两个都刷新完,表示flush list中已经没有脏页了。
  • 第二种方式

stop slave后,如果脏页没有刷新完呢?不相等,我们还能拷贝吗?
答案是:当然可以。
lsn不相等,意味着,我们crash-recover的时候需要通过redo来恢复数据,稍微慢点而已,不影响大局。

重要

所以,不管以上两种方式的哪一种,如果你想通过stop slave的方式,直接拷贝文件的话,最好执行下

FLUSH NO_WRITE_TO_BINLOG TABLES
FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS

这样,就跟xtrabackup没什么区别了

最后的几个关键问题

  • Xtrabackup 在什么版本恢复的时候,可能会丢失最后一个事务
Xtrabackup 2.2.3版本修复了此问题

https://launchpad.net/percona-xtrabackup/2.2/2.2.3-ga

Bugs Fixed

Fixed the InnoDB redo log incompatibility with 5.1/5.5 server and compressed tables which was introduced by the upstream fix in MySQL 5.6.11 that could make InnoDB crash on recovery when replaying redo logs created on earlier versions. Bug fixed #1255476.

Percona XtraBackup did not flush the InnoDB REDO log buffer before finalizing the log copy. This would only become a problem when the binary log coordinates were used after restoring from a backup: the actual data files state after recovery could be inconsistent with the binary log coordinates. Bug fixed #1320685.

innobackupex now sets wsrep_causal_reads to 0 before executing FLUSH TABLES WITH READ LOCK if the server is a member of the Galera cluster. Bug fixed #1320441.

storage/innobase/xtrabackup/CMakeLists.txt now honors the XB_DISTRIBUTION environment variable when configuring innobackupex.pl to innobackupex. Bug fixed #1320856.

When backup locks are used, xtrabackup_slave_info should be written under BINLOG lock instead of TABLE lock. Bug fixed #1328532.

Other bugs fixed: #1318540.


  • innodb 文件 和 非innodb 文件的备份,都是通过拷贝文件的方式来做的,其中有什么不同吗?
InnoDB的文件,是以page为粒度做的,xtrabackup 在读取每个page时会校验 checksum 值,保证数据块是一致的
非InnoDB文件,是在cp MyISAM 文件时已经做了flush(FTWRL),磁盘上的文件也是完整和静止的,所以最终备份集里的数据文件都是写入完整的。
  • 数据恢复的原理的是什么
恢复的目的是把备份结果集 中的 数据恢复到一个一致性位点,所谓一致就是指原数据库某一时间点各引擎数据的状态
比如 MyISAM 中的数据对应的是 15:00 时间点的,InnoDB 中的数据对应的是 15:20 的,这种状态的数据就是不一致的。
PXB 备份集对应的一致点,就是备份时FTWRL的时间点,恢复出来的数据,就对应原数据库FTWRL时的状态。

因为备份时 FTWRL 后,数据库是处于只读的
非 InnoDB 数据是在持有全局读锁情况下拷贝的,所以非 InnoDB 数据本身就对应 FTWRL 时间点;
InnoDB 的 ibd 文件拷贝是在 FTWRL 前做的  , 拷贝出来的不同 ibd 文件最后更新时间点是不一样的,这种状态的 ibd 文件是不能直接用的
但是 redo log 是从备份开始一直持续拷贝的,最后的 redo 日志点是在持有 FTWRL 后取得的,所以最终通过 redo 应用后的 ibd 数据时间点也是和 FTWRL 一致的。

所以恢复过程只涉及 InnoDB 文件的恢复,非 InnoDB 数据是不动的。备份恢复完成后,就可以把数据文件拷贝到对应的目录,然后通过mysqld来启动了。

还原的流程:

* 准备(prepare)一个完全备份
innobackupex --apply-log /path/to/BACKUP-DIR : 将redo日志apply到数据文件,让数据恢复到FTWRL的时间点

* 从一个完全备份中恢复数据
innobackupex --copy-back/move-back /path/to/BACKUP-DIR : 拷贝数据文件到MySQL目录
  • xtrabackup的详细流程细化

1、先获取innodb最后一次checkpoint对应的redo log lsn;

2、xtrabackup主线程从checkpoint lsn开始将之后新产生的redo都拷贝到xtrabackup_logfile上;

3、只有拷完所有的redo日志后,才会开启redo拷贝线程和ibd拷贝线程。并行执行redo和ibd数据拷贝;

4、ibd拷贝线程完成所有数据拷贝;

5、xtrabackup执行flush table with read lock,拷贝MyISAM表等非事务表数据;

6、获取Binlog文件及偏移位置,获取gtid_executed等信息;

7、执行FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS;

8、等待redo拷贝进程退出;

9、执行unlock tables;

10、执行备份所需其他操作后退出;



相关参考

http://mysql.taobao.org/monthly/2016/03/07/
https://zhuanlan.zhihu.com/p/43913304
http://www.innomysql.com/xtrabackup%E5%A4%87%E4%BB%BD%E5%8E%9F%E7%90%86%E5%AE%9E%E7%8E%B0%E7%BB%86%E8%8A%82-%E5%AF%B9%E6%B7%98%E5%AE%9D%E6%95%B0%E6%8D%AE%E5%BA%93%E5%86%85%E6%A0%B8%E6%9C%88%E6%8A%A5%E8%A1%A5/
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
存储 网络协议 关系型数据库
MySQL8.4创建keyring给InnoDB表进行静态数据加密
MySQL8.4创建keyring给InnoDB表进行静态数据加密
104 1
|
3月前
|
SQL 缓存 关系型数据库
使用温InnoDB缓冲池启动MySQL测试
使用温InnoDB缓冲池启动MySQL测试
74 0
|
7月前
|
存储 缓存 关系型数据库
【MySQL进阶篇】存储引擎(MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案)
MySQL的存储引擎是其核心组件之一,负责数据的存储、索引和检索。不同的存储引擎具有不同的功能和特性,可以根据业务需求 选择合适的引擎。本文详细介绍了MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案。
1268 57
【MySQL进阶篇】存储引擎(MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案)
|
8月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
311 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
7月前
|
存储 关系型数据库 MySQL
MySQL存储引擎详述:InnoDB为何胜出?
MySQL 是最流行的开源关系型数据库之一,其存储引擎设计是其高效灵活的关键。InnoDB 作为默认存储引擎,支持事务、行级锁和外键约束,适用于高并发读写和数据完整性要求高的场景;而 MyISAM 不支持事务,适合读密集且对事务要求不高的应用。根据不同需求选择合适的存储引擎至关重要,官方推荐大多数场景使用 InnoDB。
170 7
|
7月前
|
存储 关系型数据库 MySQL
Mysql索引:深入理解InnoDb聚集索引与MyisAm非聚集索引
通过本文的介绍,希望您能深入理解InnoDB聚集索引与MyISAM非聚集索引的概念、结构和应用场景,从而在实际工作中灵活运用这些知识,优化数据库性能。
493 7
|
7月前
|
存储 关系型数据库 MySQL
MySQL引擎InnoDB和MyISAM的区别?
InnoDB是MySQL默认的事务型存储引擎,支持事务、行级锁、MVCC、在线热备份等特性,主索引为聚簇索引,适用于高并发、高可靠性的场景。MyISAM设计简单,支持压缩表、空间索引,但不支持事务和行级锁,适合读多写少、不要求事务的场景。
120 9
|
8月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的表空间
InnoDB是MySQL默认的存储引擎,主要由存储结构、内存结构和线程结构组成。其存储结构分为逻辑和物理两部分,逻辑存储结构包括表空间、段、区和页。表空间是InnoDB逻辑结构的最高层,所有数据都存放在其中。默认情况下,InnoDB有一个共享表空间ibdata1,用于存放撤销信息、系统事务信息等。启用参数`innodb_file_per_table`后,每张表的数据可以单独存放在一个表空间内,但撤销信息等仍存放在共享表空间中。
130 6