二、 数据库备份恢复原理
进行逻辑备份时会涉及很多库表,比如备份a表时花费10秒钟,而开始备份b表时已经是10秒钟以后的数据,会导致数据不一致。此类问题如何解决?
MySQL能够通过事务与各种日志保证数据一致性。
MySQL的主流引擎是InnoDB,是一个事务型引擎。事务的4个特性为原子性、一致性、隔离性与持久性,以上四个特性能够完整描述出事务的样子。事务有两个状态,分别为成功或失败,失败后可以回滚。事务与事务之间互相隔离,不同的隔离级别看到的数据会略有不同。事务提交后,不管发生宕机或其他事件,数据都需要能够保存在磁盘上。而一致性主要通过其他三种特性共同保证。
事务4个特性的实现主要依靠3个日志文件:
• Redo log:记录数据更新后的值。保证能够落盘,因此可以用来恢复未写入data file的已成功事务更新的数据。原先的存储大多使用随机IO,而Redo log使用顺序IO,速度可以得到大幅提升。同时,原先的存储数据分布非常零散,更新几个列值需要多次IO,而顺序IO的场景下能够大幅减少IO次数。综上,Redo log的目的主要有保证数据的持久性以及提升速度。
• Undo log:记录数据被更新前的镜像值,保证数据能够回滚。主要用于事务多版本并发控制以及原子性。
• Binlog:Binlog存在于 server 层,会记录所有提交的DML与DDL,用于做主从复制、数据恢复或同步。为了保证binlog数据的一致性,MySQL采用2阶段提交。
以下举例说明Redo与Undo之间的关系。假设a、b两个数据值都为500,a减100、b加100的事务行为如下:
首先,事务开始,记录a=500到Undo log。修改为a=400,并记录到Redo log。事务的写流程都为先写Undo log再写Redo log,因此后续流程为记录b=500到Undo log,记录b=600到Redo log,最终事务提交。LSN是日志序列号,用于记录数据库里面数据的一致性位置,主要存在于data buffer和redo buffer。
事务提交之后即落盘,但是在如果在提交过程中发生了crash,数据库会做recover,先前滚,再回滚,流程如下:
确定恢复起点checkpoint_LSN,然后对比LSN号,应用redo log中最新的日志文件数据,达到crash前一刻状态。最后对prepare状态事务进行回滚,数据状态恢复正常。这也是两阶段事务提交的具体逻辑。
上图右侧为MySQL内存与磁盘的结构。
逻辑备份是数据库层面对象级别的备份,主流工具有mysqldump、Mysqldumper(mysqldump的多线程版本)。
物理备份是文件系统层面,比如简单的cp、Rsync、XtraBackup、CDM。
快照备份是基于存储或文件系统,不同厂商会有很多类似的工具。
我们准备了两个数据库,分别是test2021与test2022,里面分别有两个表。对两个库进行逻辑备份。
上图为具体备份流程。首先会对结构进行备份,然后将数据转换成SQL的方式,执行SQL与DDL。
上图中32 Init DB test2022表示开始备份test2022库。首先,将t1表和test_user表上锁,不允许写。备份完成后,将两个表解锁,然后开始进行test2021库的备份。
上述流程存在两个问题:
• 首先,备份时不能写入。
• 其次,先对a库进行备份,完成后再对b库进行备份。假设a库备份花费10分钟,则b库的数据是 10 分钟之后的数据,会存在不一致的问题。
single-transaction参数解决了一致性问题与锁问题。
上图流程可见,首先设置了rr的隔离级别,能够解决换读问题。Start transaction 表示开启了一致性快照,通过事务方式读取数据,保证了数据的一致性。
上图可见,备份时并没有加锁,只是通过事务来保证一致性。
master-data主要用于获取Binlog位置,搭建主从关系时使用。
Flush tables with read lock表示对整个库加了只读锁,再设置为rr隔离级别,开启一致性读事务。做完show master status后,进行unlock,然后进行备份流程。
single-transaction利用事务机制保证一致性。而如果数据库里有非事务引擎表,我们提供了lock-all-tables参数用于锁定所有表,以保证一致性。该参数日常使用较少,因为会造成比较大的影响。因此,云上库不支持myisam 引擎表。运维或设计时,建议尽量使用事务性引擎表。
接下篇:https://developer.aliyun.com/article/1224054?spm=a2c6h.13148508.setting.19.7b3f4f0enhBQlF