【MySQL】详解binlog和redolog两阶段提交

server/2024/12/22 18:03:56/

在 MySQL 的事务执行过程中,binlog 和 redo log(重做日志)协同工作来确保事务的持久性和数据一致性。MySQL 使用一种称为 【两阶段提交】 的机制来确保这两个日志之间的一致性,以避免在崩溃时出现数据不一致的情况。 在我前面的 博客 中也有详细的介绍这两种日志,感兴趣的可以点击链接查阅。

1. redo log 和 binlog 的作用

redo log(重做日志):它是 InnoDB 存储引擎的日志,主要用于实现 事务的持久性崩溃恢复。当事务在 MySQL 中被提交时,数据并不会立即写入磁盘,而是先写入内存页,再通过 redo log 记录修改。在系统崩溃后,InnoDB 会通过 redo log 恢复未写入磁盘的事务,保证事务的持久性(即满足 事务的 ACID 中的 D:Durability)。

binlog(二进制日志):它是 MySQL Server 层的日志,记录所有导致数据修改的 SQL 语句。binlog 主要用于 主从复制基于时间点的恢复,使得主库和从库保持一致。

由于这两个日志分别在 MySQL Server 层和 InnoDB 存储引擎层,MySQL 需要确保这两个日志的状态在事务提交时保持一致。

为什么会发生这些不一致?

redo log 负责在主库崩溃时恢复数据,因此它影响的是 主库的数据持久性。
binlog 主要用于 主从复制,确保事务的操作可以复制到从库,从而影响 从库的数据一致性。

由于这两份日志分别负责不同的功能,如果在事务提交过程中,redo log 和 binlog 的刷盘过程不同步(即出现了 “半成功” 状态),就会导致主库和从库之间的数据不一致:

当 redo log 刷入磁盘成功,但 binlog 未写入磁盘时:主库的数据更新成功,但由于 binlog 丢失,从库不会执行相应的更新。
当 binlog 刷入磁盘成功,但 redo log 未写入磁盘时:从库的数据更新成功,但由于主库没有完成事务提交,主库回滚了这次更新。

这两种情况下,主库和从库的数据都会发生不一致,原因是 redo log 和 binlog 分别控制了主库的事务持久性和从库的事务一致性,如果它们之间的操作没有严格同步,主从数据就可能出现不一致。

看下面第2节的例子。

2. 为什么需要两个阶段提交(保持两种日志的一致)

假设 id =1这行数据的字段 name 的值原本是’lisi’,然后执行 UPDATE user SET name = ‘zhangsan’ WHERE id = 1;如果在持久化redo log 和 binlog 两个日志的过程中,出现了半成功状态,那么就有两种情况

情况一:redo log 刷入磁盘成功,但 binlog 没有写入磁盘

过程

  • 执行 UPDATE user SET name = ‘zhangsan’ WHERE id = 1;,首先将事务的修改(name 从lisi 变为 zhangsan)写入 redo log 的 prepare 状态并刷入磁盘。
  • 此时,redo log 已经确保数据的持久性,即便 MySQL 发生崩溃,重启后依然能通过 redo log 恢复内存中的数据,将 name 恢复到新的值 zhangsan。
  • 但在 redo log 刷入磁盘之后,MySQL 在还没有来得及写入 binlog 的时候宕机。

重启后的结果

  • 主库:由于 redo log 已经持久化,事务恢复时会根据 redo log 的内容将 id = 1 这一行的 name 字段恢复到新值 zhangsan。
  • 从库:binlog 没有写入,因此在主库宕机之前,这条更新语句没有记录在 binlog 中。从库通过复制机制读取的是主库上次宕机前的 binlog,由于 binlog 丢失了这条更新语句,从库的 name 字段仍然是旧值 lisi。

问题:主库的 name 值是 zhangsan,从库的 name 值是 lisi,导致主从数据不一致。

=====================================================================================================

情况二:binlog 刷入磁盘成功,但 redo log 没有刷入磁盘

过程

  • 执行 UPDATE user SET name = ‘zhangsan’ WHERE id = 1;,先将 SQL 语句记录在 binlog 中,并成功将 binlog 刷入磁盘。
  • 在 binlog 刷入磁盘后,MySQL 发生崩溃,而此时 redo log 还没有提交成功,即 redo log 还处于 prepare 状态,没有完成持久化。

重启后的结果:

  • 主库:由于 redo log 还没有提交,所以在崩溃恢复时,MySQL 发现该事务并没有真正提交,因此会回滚这次事务。重启后,主库的 id = 1 这一行 name 字段会保持旧值 lisi。
  • 从库:由于 binlog 已经刷入磁盘,并且在主从复制时会将 binlog 传递给从库,所以从库会执行 binlog 中记录的这条更新语句,结果是从库将 id = 1 这一行的 name 字段更新为zhangsan。

问题:主库的 name 值是lisi,而从库的 name 值是 zhangsan,同样会导致主从数据不一致。

3. 两阶段提交的执行过程

在事务提交过程中,MySQL 的 binlog 和 InnoDB 的 redo log 需要通过两阶段提交机制来保持一致性。这个过程大致如下:
在这里插入图片描述【图片来自:小林coding】

阶段 1:准备阶段(Prepare Phase)

  1. 记录 redo log:当一个事务执行并准备提交时,InnoDB 会将事务的修改先记录到 redo log 的 prepare 状态。这时的 redo log 还没有真正提交,但已经将所有修改持久化到了日志中。该状态确保在崩溃恢复时,系统能够根据这个 redo log 的 prepare 状态判断事务的执行情况。

  2. 写入内存:事务的数据修改通常首先在内存中操作(内存页或缓冲池),此时数据还没有被写入磁盘,但 redo log 的准备记录确保了这些修改可以在崩溃后恢复。

  3. 等待 binlog 的同步:在这一步,InnoDB 已经做好了写入日志的准备,但事务还没有完全提交,系统等待 binlog 的同步。

阶段 2:提交阶段(Commit Phase)

  1. 写入 binlog:MySQL 将该事务的修改操作(如 INSERT、UPDATE、DELETE)记录到 binlog 中,并根据配置(例如 sync_binlog)决定是否将 binlog 刷盘写入磁盘。这一步是为了确保在主从复制时,能够完整地同步所有操作。

  2. 提交 redo log:当 binlog 写入成功后,将 redo log 的状态从 prepare 改为 commit,并将日志数据刷入磁盘。这一过程确保事务的持久化和一致性。

  3. 事务提交完成:此时,事务的所有数据修改已经成功写入到 redo log 和 binlog 中,事务被正式提交。

4. 为什么两阶段提交不会出现重启后不一致的情况

在这里插入图片描述【图片来自:小林coding】

不管是时刻 A(redo log 已经写入磁盘, binog 还没写入磁盘),还是时刻 B(redo log 和 binlog 都已经写入磁盘,还没写入 commit 标识)崩溃,此时的redo log 都处于 prepare 状态。

在 MySQL 重启后会按顺序扫描 redo log 文件,碰到处于 prepare 状态的 redo log,就拿着 redo log 中的XID 去 binlog 查看是否存在此 XID:

  • 如果 binlog 中没有当前内部 XA 事务的 XID,说明 redolog 完成刷盘,但是 binlog 还没有刷盘,则回滚事务。对应时刻 A 崩溃恢复的情况。
  • 如果 binlog 中有当前内部 XA 事务的 XID,说明 redolog 和 binlog 都已经完成了刷盘,则提交事务对应时刻 B 崩溃恢复的情况。

可以看到,对于处于 prepare 阶段的 redo log,即可以提交事务,也可以回滚事务,这取决于是否能在binlog 中查找到与 redo log 相同的 XID,如果有就提交事务,如果没有就回滚事务。这样就可以保证redo log 和 binlog 这两份日志的一致性了。

所以说,两阶段提交是以 binlog 写成功为事务提交成功的标识,因为 binlog 写成功了,就意味着能在binlog 中查找到与 redo log 相同的 XID。


http://www.ppmy.cn/server/131650.html

相关文章

众数信科 AI智能体政务服务解决方案——寻知智能笔录系统

政务服务解决方案 寻知智能笔录方案 融合民警口供录入与笔录生成需求 2分钟内生成笔录并提醒错漏 助办案人员二次询问 提升笔录质量和效率 寻知智能笔录系统 众数信科AI智能体 产品亮点 分析、理解行业知识和校验规则 AI实时提醒用户文书需注意部分 全文校验格式、内容…

linux 大小写转换

var"TM_card_INFo" # 把变量中的第一个字符换成大写 echo ${var^} # 把变量中的所有小写字母,全部替换为大写 echo ${var^^} # 把变量中的第一个字符换成小写 echo ${var,} # 把变量中的所有大写字母,全部替换为小写 echo ${var,,} 参考…

ubuntu 安装docker-compose

一、执行命令 sudo curl -L "https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose docker-compose --version 二、准备镜像 编写&…

【多线程奇妙屋】“线程等待” 专讲,可不要只会 join 来线程等待哦, 建议收藏 ~~~

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. 🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人…

R语言绘制三维散点图

之前我们绘制的属于二维散点图,具有两个维度通常是 x 轴和 y 轴)上展示数据点的分布。只能呈现两个变量之间的关系。而三维散点图则具有三个维度(x 轴、y 轴和 z 轴)上展示数据点的分布。可以同时呈现三个变量之间的关系&#xff…

鹏哥C语言77---指针的定义和类型

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> //---------------------------------------------------BIT - 6 - 指针------------------------------------------------- 1.指针是什么 2.指针和指针类型 3.野指针 4.指针运算 5.指…

精益与数字化的融合:制造业的创新之路

回望过去&#xff0c;精益管理作为制造业的瑰宝&#xff0c;以其“消除浪费、持续改进、顾客至上”的核心理念&#xff0c;引领了无数企业走向成功。从丰田生产方式到全球范围内的广泛实践&#xff0c;精益管理不仅提升了生产效率&#xff0c;更重塑了企业的文化和价值观。它教…

界面控件DevExpress中文教程 - 如何拓展具有AI功能的文本编辑器(二)

NLP是人工智能的一个分支&#xff0c;它允许计算机与人类语言进行交互&#xff0c;这包括以有意义/有用的方式理解、解释、生成和回应文本(和语音)的能力。基于NLP的功能允许更好的数据分析、个性化体验、高效的沟通&#xff0c;并导致更明智的决策和提高效率。例如&#xff1a…