你可能听 DBA说过,他可以将数据库的数据库恢复到之前的任意时间点。你是否好奇他是怎样做到的呢?
总览
回顾
一条更新语句的执行过程
与之前说过的查询语句类似,更新语句也要经过类似的过程。
你真的了解MySQL吗?MySQL基础架构:一条MySQL查询语句时如何执行的(MySQL的连接器、分析器、优化器、连接器的作用)
mysql> update T set c=c+1 where ID=2;
建立连接:通过连接器简历客户端 MySQL 的连接
缓存失效:将查询缓存全部失效,避免查询的到脏数据(不建议开启查询缓存,会频繁失效)
词法、语法分析:经过分析器,分析出要对 T 表中 ID = 2 的数据进行更新,将 c + 1
执行计划优化:通过优化器,确认使用主键索引 ID
执行:执行器调用数据库引擎,进行执行
注意:与查询不同的是,更新操作还涉及到了对 redo log(重做日志)、bin log(归档日志)的操作,下面会具体讲到。
日志模块
redo log(重做日志)
是什么
什么是 redo log?
redo log 记录了执行引擎的每一次更新操作
什么用
为什么多加一步 redo log?
一次数据更新可以抽象化为简单的两步:查找数据、进行更新。只要涉及到查找数据,就会增加一定的时间复杂度。
为了增加更新效率,MySQL 执行引擎将数据更新进行了简化。每次更新时,会先修改内存数据和写redo log,增加了性能。这其实就是我们常说的 WAL 技术,WAL 的全称是 Write-Ahead Logging。它的关键点就是先写日志,再写磁盘
一次数据更新流程
增加 redo log 后,一次数据更新流程变成了什么样呢?
当数据更新时,InnoDB 会先将数据写到内存和 redo log,这样一次更新就算完成了。
InnoDB 会在合适的时机,将 redo log 中的数据写入磁盘,更新具体的数据块
合适的时机:当 MySQL 空闲或 redo log 被写满时。
crash-safe
为什么 redo log 可以保证 crash-safe?它在硬盘中是以什么形式存储的呢?
有了 redo-log,InnoDB 可以保证当数据库异常重启后,之前提交的记录不会丢失,这就叫 crash-safe.
比如我们配置一组四个文件,每个文件 1 GB,那样 redo log 就可以存储 4GB 的数据
redo log 一共有两个指针组成,分别是 write-pos 和 check-point
write pos:记录当前写入的位置
check point:检查点,记录有哪些数据更新到了数据文件
当 write-pos 追上了 check-point 时,则需要阻塞更新操作,将操作更新到数据文件。
bin log(归档日志)
是什么
是 Server 层的实现,不依赖具体的存储引擎。
数据归档日志,记录了更新语句的原始逻辑
什么用
归档日志,没有提供 crash-safe 的能力
两者对比
区别
实现层面
bin log 是 Server 层的实现,不依赖于具体的存储引擎
redo log 由 InnoDB 实现,提供了 crash-safe 能力
日志作用
bin log 是逻辑日志,只是记录了具体的逻辑操作,例如「给 ID = 9 这一行的 c 字段加一」
redo log 是物理日志,记录了具体数据页的数据变更,例如「在某个数据页上进行了怎样的修改」
存储方式
bin log 是追加写,当一块文件写满后,会继续写另一块,不会清空。
redo log 是循环写,当写满后,会将数据更新到磁盘,然后继续写入
两阶段提交
简单说,redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。
一次完整的更新过程
读取数据:执行器调用执行引擎接口查询 ID = 9 的数据;执行引擎在内存中找到数据页并返回,如果数据不存在则通过树搜索找到数据页,存入内存后返回。
操作数据:执行器拿到数据,对字段 c 进行加一操作;调用执行引擎接口,存入数据。
写入数据-1:执行引擎更新内存中的数据页,并将更新操作记录到 redo log(此时是 prepare 状态)。并告知执行器更新完成,可以提交事务
写入数据-2:执行器生成这个逻辑操作的 bin log,并写入到磁盘
写入数据-3:执行器调用引擎的提交事务接口,redo log 状态变为 commit.
两阶段提交:最后写入数据,将 redo log 的写入分为了两步,prepare 和 commit。
一阶段提交带来的问题
为什么要用两阶段提交,一阶段提交不行吗?带着这个问题,一起来看下一阶段提交带来的问题
先写bin-log
情景:
写完 binlog 后,MySQL crash 掉,此时事务还没有提交,redo log 还没有写入
恢复:
使用 binlog 恢复,此时会多出一条数据
先写redo-log
情景:
写完 redo log 后,MySQL crash 掉,此时事务还没有提交,bin log 还没有写入
恢复:
因为 redo log 有 crash-safe,所以恢复后数据未丢失。
不一致
主从同步:使用 bin-log 做主从同步或数据恢复时,因为 bin-log 为写入,会导致主从不一致。
扩容:扩容时,会使用主库 和 bin-log 进行数据同步。
说会标题:如何恢复数据到某一时间点
场景:
将数据恢复到过去的某一时间点
原理:
bin log 记录了所有对数据库的逻辑操作,并且是使用「追加写」的形式。
数据库会定期进行全库备份(一天或一周)
过程
找到离待恢复时间点最近的「整库备份」
找到从整库备份时间点开始,到期望时间点结束的 bin log
新建临时库,恢复整库数据,回放 bin log.
临时库数据覆盖主库