MySQL中,一条update更新语句是如何执行的?详解MySQL日志——redolog(重做日志) 和 binlog(归档日志)是什么、有什么用,MySQL如何做到如何恢复数据、主从同步、动态扩容

你可能听 DBA说过,他可以将数据库的数据库恢复到之前的任意时间点。你是否好奇他是怎样做到的呢?

总览

MySQL中,一条update更新语句是如何执行的?详解MySQL日志——redolog(重做日志) 和 binlog(归档日志)是什么、有什么用,MySQL如何做到如何恢复数据、主从同步、动态扩容_第1张图片

回顾

一条更新语句的执行过程

与之前说过的查询语句类似,更新语句也要经过类似的过程。

  • 你真的了解MySQL吗?MySQL基础架构:一条MySQL查询语句时如何执行的(MySQL的连接器、分析器、优化器、连接器的作用)
mysql> update T set c=c+1 where ID=2;
  1. 建立连接:通过连接器简历客户端 MySQL 的连接
  2. 缓存失效:将查询缓存全部失效,避免查询的到脏数据(不建议开启查询缓存,会频繁失效)
  3. 词法、语法分析:经过分析器,分析出要对 T 表中 ID = 2 的数据进行更新,将 c + 1
  4. 执行计划优化:通过优化器,确认使用主键索引 ID
  5. 执行:执行器调用数据库引擎,进行执行
  6. 注意:与查询不同的是,更新操作还涉及到了对 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?它在硬盘中是以什么形式存储的呢?

MySQL中,一条update更新语句是如何执行的?详解MySQL日志——redolog(重做日志) 和 binlog(归档日志)是什么、有什么用,MySQL如何做到如何恢复数据、主从同步、动态扩容_第2张图片

有了 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 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

一次完整的更新过程

MySQL中,一条update更新语句是如何执行的?详解MySQL日志——redolog(重做日志) 和 binlog(归档日志)是什么、有什么用,MySQL如何做到如何恢复数据、主从同步、动态扩容_第3张图片

  1. 读取数据:执行器调用执行引擎接口查询 ID = 9 的数据;执行引擎在内存中找到数据页并返回,如果数据不存在则通过树搜索找到数据页,存入内存后返回。
  2. 操作数据:执行器拿到数据,对字段 c 进行加一操作;调用执行引擎接口,存入数据。
  3. 写入数据-1:执行引擎更新内存中的数据页,并将更新操作记录到 redo log(此时是 prepare 状态)。并告知执行器更新完成,可以提交事务
  4. 写入数据-2:执行器生成这个逻辑操作的 bin log,并写入到磁盘
  5. 写入数据-3:执行器调用引擎的提交事务接口,redo log 状态变为 commit.
  6. 两阶段提交:最后写入数据,将 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.
  • 临时库数据覆盖主库

 

你可能感兴趣的:(数据库)