如何解决 bin log 与 redo log 的一致性问题

为什么说 redo log 具有崩溃恢复的能力

MySQL Server 层拥有的 bin log 只能用于归档,不足以实现崩溃恢复(crash-safe),需要借助 InnoDB 引擎的 redo log 才能拥有崩溃恢复的能力。所谓崩溃恢复就是:即使在数据库宕机的情况下,也不会出现操作一半的情况,至于为什么说 redo log 具有崩溃恢复的能力,而 bin log 没有,我们先来简单看一下这两种日志有哪些不同点:

1)适用对象不同

  • bin log 是 MySQL 的 Server 层实现的,所有引擎都可以使用
  • 而 redo log 是 InnoDB 引擎特有的

2)写入内容不同

  • bin log 是逻辑日志,记录的是这个语句的原始逻辑,比如 “给 id = 1 这一行的 age 字段加 1”
  • redo log 是物理日志,记录的是 “在某个数据页上做了什么修改”

3)写入方式不同

  • bin log 是可以追加写入的。“追加写” 是指 bin log 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志
  • redo log 是循环写的,空间固定会被用完

可以看到,redo log 和 bin log 的一个很大的区别就是,一个是循环写,一个是追加写。也就是说 redo log 只会记录未刷入磁盘的日志,已经刷入磁盘的数据都会从 redo log 这个有限大小的日志文件里删除。

而 bin log 是追加日志,保存的是全量的日志。这就会导致一个问题,那就是没有标志能让 InnoDB 从 bin log 中判断哪些数据已经刷入磁盘了,哪些数据还没有。

举个例子,bin log 记录了两条日志:

记录 1:给 id = 1 这一行的 age 字段加 1
记录 2:给 id = 1 这一行的 age 字段加 1

假设在记录 1 刷盘后,记录 2 未刷盘时,数据库崩溃。重启后,只通过 bin log 数据库是无法判断这两条记录哪条已经写入磁盘,哪条没有写入磁盘,不管是两条都恢复至内存,还是都不恢复,对 id = 1 这行数据来说,都是不对的。

但 redo log 不一样,只要刷入磁盘的数据,都会从 redo log 中被抹掉,数据库重启后,直接把 redo log 中的数据都恢复至内存就可以了。

这就是为什么说 redo log 具有崩溃恢复的能力,而 bin log 不具备。

redo log 两阶段提交

一条 SQL 查询语句的执行过程:

  1. MySQL 客户端与服务器间建立连接,客户端发送一条查询给服务器;
  2. 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果;否则进入下一阶段;
  3. 服务器端进行 SQL 解析、预处理,生成合法的解析树;
  4. 再由优化器生成对应的执行计划;
  5. 执行器根据优化器生成的执行计划,调用相应的存储引擎的 API 来执行,并将执行结果返回给客户端

对于更新语句来说,这套流程同样也是要走一遍的,不同的是,更新流程还涉及两个重要的日志模块 bin log 和 redo log。

以下面这条简单的 SQL 语句为例,我们来解释下执行器和 InnoDB 存储引擎在更新时做了哪些事情:

update table set age = age + 1 where id = 1;
  • 执行器:找存储引擎取到 id = 1 这一行记录
  • 存储引擎:根据主键索引树找到这一行,如果 id = 1 这一行所在的数据页本来就在内存池(Buffer Pool)中,就直接返回给执行器;否则,需要先从磁盘读入内存池,然后再返回
  • 执行器:拿到存储引擎返回的行记录,把 age 字段加上 1,得到一行新的记录,然后再调用存储引擎的接口写入这行新记录
  • 存储引擎:将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务

注意不要把这里的提交事务和我们 sql 语句中的提交事务 commit 命令搞混了哈,我们这里说的提交事务,指的是事务提交过程中的一个小步骤,也是最后一步。当这个步骤执行完成后,commit 命令就执行成功了。

  • 执行器:生成这个操作的 bin log,并把 bin log 写入磁盘
  • 执行器:调用存储引擎的提交事务接口
  • 存储引擎:把刚刚写入的 redo log 状态改成提交(commit)状态,更新完成

可以看到,所谓两阶段提交,其实就是把 redo log 的写入拆分成了两个步骤:prepare 和 commit

所以,为什么要这样设计呢?这样设计怎么就能够实现崩溃恢复呢?

根据两阶段提交,崩溃恢复时的判断规则是这样的:

  1. 如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交
  2. 如果 redo log 里面的事务处于 prepare 状态,则判断对应的事务 binlog 是否存在并完整
  • a. 如果 binlog 存在并完整,则提交事务;
  • b. 否则,回滚事务。

如下图所示,假设数据库在写入 redo log(prepare) 阶段之后、写入 binlog 之前,发生了崩溃,此时 redo log 里面的事务处于 prepare 状态,binlog 还没写(对应 2b),所以崩溃的时候,这个事务会回滚。

Why?

因为 binlog 还没有写入,之后从库进行同步的时候,无法执行这个操作,但是实际上主库已经完成了这个操作,所以为了主备一致,在主库上需要回滚这个事务

并且,由于 binlog 还没写,所以也就不会传到备库,从而避免主备不一致的情况。

而如果数据库在写入 binlog 之后,redo log 状态修改为 commit 前发生崩溃,此时 redo log 里面的事务仍然是 prepare 状态,binlog 存在并完整(对应 2a),所以即使在这个时刻数据库崩溃了,事务仍然会被正常提交。

Why?

因为 binlog 已经写入成功了,这样之后就会被从库同步过去,但是实际上主库并没有完成这个操作,所以为了主备一致,在主库上需要提交这个事务。

所以,其实可以看出来,处于 prepare 阶段的 redo log 加上完整的 bin log,就能保证数据库的崩溃恢复了

MySQL 咋知道 bin log 是不是完整的?

简单来说,一个事务的 binlog 是有完整格式的:

  • statement 格式的 bin log,最后会有 COMMIT
  • row 格式的 bin log,最后会有 XID event

而对于 bin log 可能会在中间出错的情况,MySQL 5.6.2 版本以后引入了 binlog-checksum 参数,用来验证 bin log 内容的正确性

思考一个问题,两阶段提交是必要的吗?可不可以先 redo log 写完,再写 bin log 或者反过来?

1)对于先写完 redo log 后写 bin log 的情况:

假设在 redo log 写完,bin log 还没有写完的时候,MySQL 崩溃。主库中的数据确实已经被修改了,但是这时候 bin log 里面并没有记录这个语句。因此,从库同步的时候,就会丢失这个更新,和主库不一致。

2)对于先写完 binlog 后写 redo log 的情况:

如果在 bin log 写完,redo log 还没写的时候,MySQL 崩溃。因为 binlog 已经写入成功了,这样之后就会被从库同步过去,但是实际上 redo log 还没写,主库并没有完成这个操作,所以从库相比主库就会多执行一个事务,导致主备不一致

如何解决 bin log 与 redo log 的一致性问题相关推荐

  1. MySQL日志(undo log 和 redo log 实现事务的原子性/持久性/一致性)

    日志的重要性 日志绝对是数据库的核心.   持久化的日志记录了各种重要的信息. 数据的恢复需要依赖日志.  慢查询sql语句需要用到慢查询日志.以及错误日志中保存着mysqld数据库服务端在启动过程中 ...

  2. oracle安装 redo log,Oracle Redo Log 及Logmnr配置使用

    三.日志文件组.日志切换和日志归档 -------------Member 默认情况下,Oracle数据库实例创建完成以后就已创建了3组日志组.每组有两个日志文件(每个日志文件称为Member),每个 ...

  3. oracle redo log恢复,REDO LOG 丢失恢复方法小结

    一.在shutdown immediate情况下 1.SQL> shutdown immediate 数据库已经关闭. 已经卸载数据库. ORACLE 例程已经关闭. 2.删除所有联机日志文件 ...

  4. oracle 误删 log文件,Redo log文件被删除恢复

    1. Redolog file是CURRENT的时候被删除, 清除日志时报错:ORA-01624: SQL> startup mount ORA-32004: obsolete or depre ...

  5. redo log和bin log以及两阶段提交(笔记)

    1.redo log 如果熟悉MySQL你肯定知道MySQL能过对数据进行恢复(前提是开启bin log日志),当然这要归功于bin log日志.但是你可曾听过redo log呢? 首先redo lo ...

  6. bin log,redo log以及undo log详解

    1 bin log 1.1 定义 bin log应该说是Mysql里最核心的日志,是MySQL数据库级别的文件,记录对MySQL数据库各种引擎下执行修改的所有操作(包括DDL和DML语句),不会记录s ...

  7. MYSQL专题-MySQL三大日志binlog、redo log和undo log

    日志是mysql数据库的重要组成部分,记录着数据库运行期间各种状态信息.mysql日志主要包括重做日志(redo log).回滚日志(undo log).二进制日志(bin log).错误日志(err ...

  8. mysql- 数据库的6种日志:错误日志、通用日志、慢日志、二进制日志、redo log、undo log

    MySQL日志 日志用来做什么? 1.用来排错 2.用来做数据分析 3.了解程序的运行情况,是否健康 日志放在哪里? 日志一般放在数据目录 日志分类 错误日志.通用日志.慢日志.二进制日志 一.错误日 ...

  9. 精讲 MySQL 事务日志:redo log 和 undo log

    来源:https://blog.csdn.net/demonson/article/details/104369733 innodb事务日志包括redo log和undo log.redo log是重 ...

最新文章

  1. Xamarin Essentials教程陀螺仪Gyroscope
  2. zipfile不能解压分卷压缩的文件
  3. 利用指针的指针,修改被调函数的局部值【传引用】
  4. 联机分析的列式数据库 clickHouse
  5. .NET与鲲鹏共展翅,昇腾九万里(二)
  6. mc用云服务器搭建_最全的云服务器架设我的世界私服教程,不看后悔哦!
  7. 如何设置 jqplot 图表插件的轴和网格
  8. SQL 查询笔记:子查询,分组查询,左连接查询。。。。。
  9. 如何去定义一个jquery插件
  10. Linux 上的数据可视化工具
  11. 推荐12个漂亮的CSS3按钮实现方案
  12. wikioi 1098 均分纸牌
  13. t-SNE数据降维可视化
  14. 卡尔曼滤波器原理简介
  15. 端口和网络安全的关系
  16. 北京网络行业协会鉴定称飞流软件无法卸载
  17. P4315 月下“毛景树” 树链剖分+线段树
  18. Bzoj4698: [Sdoi2008]Sandy的卡片
  19. c++求三个数中的最大值和最小值
  20. 调试经验——使用VBA在Excel中打开Word文档(Open Word file in Excel with VBA)

热门文章

  1. “系统建模与辨识数据库”系统辨识-伊利湖问题建模
  2. signature=a95d3b624ea7b2de0432eee0b4f584d9,Braves mourn Hank Aaron
  3. php isset()和empty()的使用区别
  4. win10硬盘启动从IDE改成ahci后无法启动系统的解决方式
  5. SPSS Modeler建立ODBC数据源使用数据库文件
  6. Ubuntu下怎么退出vim编辑器
  7. Linux的文件和目录管理
  8. flv.js php,B站视频开源代码flv.js+HTML5无flash播放视频
  9. 【大学物理学】质点动力学
  10. Python数据预处理——格式转换及抽取数据文本信息