图解MySQL【日志】——两阶段提交

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
日志服务 SLS,月写入数据量 50GB 1个月
简介: 两阶段提交是为了解决Redo Log和Binlog日志在事务提交时可能出现的半成功状态,确保两者的一致性。它分为准备阶段和提交阶段,通过协调者和参与者协作完成。准备阶段中,协调者向所有参与者发送准备请求,参与者执行事务并回复是否同意提交;提交阶段中,若所有参与者同意,则协调者发送提交请求,否则发送回滚请求。MySQL通过这种方式保证了分布式事务的一致性,并引入组提交机制减少磁盘I/O次数,提升性能。

两阶段提交

为什么需要两阶段提交?

事务提交后,Redo Log 和 Binlog 都要持久化到磁盘中,但是这两个是独立的逻辑,可能会出现半成功状态,造成两种日志之间的逻辑不一致。

1.1. 半成功状态

Redo Log 成功持久化,而 Binlog 失败

  • 如果在将 Redo Log 刷入到磁盘后,MySQL 突然宕机了,而 Binlog 还未来得及写入。MySQL 异常重启后,通过 Redo Log 恢复,而 Binlog 在被复制到从库时,丢失了这条语句,导致主从数据不一致。

Binlog 成功持久化,而 Redo Log 失败

  • 如果在将 Binlog 刷入到磁盘后,MySQL 突然宕机了,而 Redo Log 还未来得及写入,崩溃后该事务无效,重置为事务执行前的值,而 Binlog 被复制到从库,从库执行了该语句,导致主从数据不一致。

1.2. 两阶段提交

  • MySQL 为了解决 Redo Log 与 Binlog 的半成功问题,使用了【两阶段提交】来解决。
  • 两阶段提交:一种分布式事务一致性协议,可以保证多个逻辑操作,要么全部成功,要么全部失败,不会出现这种半成功的状态。它将单个事务的提交拆分成 2 个阶段,【准备阶段】和【提交阶段。
  • 两阶段提交的参与者
  • 协调者(Coordinator):负责管理整个事务的提交或回滚过程,向所有参与者发送给请求并收集响应。
  • 参与者(Participant):执行事务的具体操作,根据协调者的指令提交或回滚事务。
  • 准备阶段
  • 协调者向所有参与者发送准备请求(Prepare Request),询问是否可以提交事务。
  • 参与者执行事务操作,并将结果写入日志(确保故障后可以恢复)。
  • 参与者根据执行结果回复协调者:
  • 如果事务可以提交,回复同意(Yes)
  • 如果事务无法提交(如发生错误),回复中止(No)
  • 提交阶段:
  • 如果所有参与者都回复“同意”,协调者向所有参与者发送提交请求(Commit Request),参与者正式提交事务。
  • 如果任一参与者回复“中止”,协调者向所有参与者发送回滚请求(Rollback Request),参与者回滚事务。
  • 参与者完成提交或回滚后,向协调者发送确认消息。

两阶段提交过程

  • prepare 阶段
  • 将 XID(内部 XA 事务的 ID)写入到 Redo Log。
  • 将 Redo Log 对应的事务状态设置为 prepare 阶段,然后将 Redo Log 持久化到磁盘(受 innodb_flush_log_at_trx_commit 参数控制)
  • commit 阶段
  • 将 XID 写入到 Binlog
  • 将 Binlog 持久化到磁盘中(受 sync_binlog 参数控制)
  • 调用引擎的提交接口,将 Redo Log 设置为 commit 状态,此时该状态并需要持久化到磁盘中,只需 write 到 OS 的 page cache 中即可,因为只要 Binlog 刷盘成功,Redo Log 的即使是 prepare 状态也无所谓,一样会被认为事务执行成功。

两阶段异常重启及解决

  • 不管是时刻 A(redo log 已经写入磁盘, binlog 还没写入磁盘),还是时刻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 阶段的 redolog,即可以提交事务,也可以回滚事务,这取决于是否能在binlog 中查找到与 redo log 相同的 XID,如果有就提交事务,如果没有就回滚事务。这样就可以保证redo log 和 binlog 这两份日志的一致性了。
  • 两阶段提交是以 binlog 写成功为事务提交成功的标识,因为 binlog 写成功了,就意味着能在binlog 中查找到与 redo log 相同的 XID。

事务没提交的时候,redo log 会被持久化到磁盘吗?

  • 会的。事务执行中间过程的 redo log 也是直接写在 redo log buffer 中的,这些缓存在 redo log buffer 里的 redolog 也会被「后台线程」每隔一秒一起持久化到磁盘。

如果 mysql崩溃了,还没提交事务的 redo log 已经被持久化磁盘了,mysql 重启后,数据不就不一致了?

  • 不会这种情况 mysql重启会进行回滚操作,因为事务没提交的时候,binlog 是还没持久化到磁盘的。
  • 所以,redo log 可以在事务没提交之前持久化到磁盘,但是 binlog,必须在事务提交之后,才可以持久化到磁盘。

两阶段提交的问题

磁盘 I/O 次数高

  • 对于 innodb_flush_log_at_trx_commit = 1 并且 sync_binlog = 1 的双“1”配置,每个事务提交都会进行两次刷盘(Redo Log + Binlog)。

锁竞争激烈

  • 两阶段提交虽然能保证【单事务】两个日志的内容一致,但在【多事务】时,却无法保证两者提交顺序一致,因此需要锁来保证在多事务情况下,两个日志提交顺序的一致。

解决:组提交

Binlog 组提交

当有多个事务提交时,会将多个 Binlog 刷盘操作合并成一个,以减少磁盘 I/O 次数。

过程:

  • flush:多个事务按进入的顺序将 Binlog 从 cache 写入文件(不刷盘)。
  • sync:对 Binlog 文件做 sync 操作(多个事务的 Binlog 合并一次刷盘)。
  • commit:各个事务按顺序做 InnoDB commit 操作。
  • 队列 leader:组提交的各个阶段都有一个队列,每个阶段都有锁进行保护,因此保证了事务写入顺序,第一个进入队列的事务会成为 leader,leader 领导所在队列的所有事务,全权负责整队的操作,完成后,通知队内其他事务操作结束。
  • 锁粒度减小:用每个阶段引入了队列,代替锁住事务的整个过程,锁粒度减小,使得多个阶段可以并发执行,提升了效率。

Redo Log 组提交

MySQL 5.7 及以后版本,引入了 Redo Log 组提交,改进点:prepare 阶段时,不再让事务独自执行 Redo Log 的刷盘操作,而是推迟到组提交的 flush 阶段,即 prepare 阶段融合在了 flush 阶段。

过程(双“1”配置)

  • flush
  • 第一个事务成为 flush 阶段的 Leader,之后的事务都是 Follower。
  • 获取队列的事务组,由绿色事务组的 Leader 对 Redo Log 做一次 write + fsync,即一次将同组事务的 Redo Log 刷盘。
  • 完成 prepare 阶段后,将绿色这一事务组执行过程中产生的 Binlog 写入 Binlog 文件(调用 wirte 而不 fsync
  • 综上得知:flush 阶段队列的作用是用于支撑 Redo Log 的组提交
  • 如果在这个阶段数据库发生崩溃,由于 Binlog 中没有该组事务记录,MySQL 在重启后回滚该组事务。

  • sync
  • 事务不会写入 Binlog 文件后立即刷盘,而是会等待一段时间(由参数 Binlog_group_commit_sync_delay 控制),目的是为了组合更多事务的 Binlog,然后一起刷盘。
  • 但在等待时间内,如果事务数量达到了 Binlog_group_commit_sync_no_delay_count 参数设置的值,就会立即刷盘。
  • 综上得知,sync 阶段队列是用于支持 Binlog 的组提交
  • 如果该阶段发生崩溃,由于 Binlog 已经有了事务记录,MySQL 重启后通过 Redo Log 刷盘的数据进行事务提交。

  • commit
  • 调用引擎的提交接口,将 Redo Log 状态设置为 commit。
  • commit 阶段是为了承接 sync 阶段的事务,完成最后的引擎提交,使得 sync 可以尽早地处理下一组事务,最大化组提交的效率。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
数据可视化 关系型数据库 MySQL
ELK实现nginx、mysql、http的日志可视化实验
通过本文的步骤,你可以成功配置ELK(Elasticsearch, Logstash, Kibana)来实现nginx、mysql和http日志的可视化。通过Kibana,你可以直观地查看和分析日志数据,从而更好地监控和管理系统。希望这些步骤能帮助你在实际项目中有效地利用ELK来处理日志数据。
266 90
|
20天前
|
SQL 运维 关系型数据库
MySQL Binlog 日志查看方法及查看内容解析
本文介绍了 MySQL 的 Binlog(二进制日志)功能及其使用方法。Binlog 记录了数据库的所有数据变更操作,如 INSERT、UPDATE 和 DELETE,对数据恢复、主从复制和审计至关重要。文章详细说明了如何开启 Binlog 功能、查看当前日志文件及内容,并解析了常见的事件类型,包括 Format_desc、Query、Table_map、Write_rows、Update_rows 和 Delete_rows 等,帮助用户掌握数据库变化历史,提升维护和排障能力。
|
1月前
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
52 16
|
2月前
|
存储 缓存 关系型数据库
图解MySQL【日志】——Redo Log
Redo Log(重做日志)是数据库中用于记录数据页修改的物理日志,确保事务的持久性和一致性。其主要作用包括崩溃恢复、提高性能和保证事务一致性。Redo Log 通过先写日志的方式,在内存中缓存修改操作,并在适当时候刷入磁盘,减少随机写入带来的性能损耗。WAL(Write-Ahead Logging)技术的核心思想是先将修改操作记录到日志文件中,再择机写入磁盘,从而实现高效且安全的数据持久化。Redo Log 的持久化过程涉及 Redo Log Buffer 和不同刷盘时机的控制参数(如 `innodb_flush_log_at_trx_commit`),以平衡性能与数据安全性。
85 5
图解MySQL【日志】——Redo Log
|
1月前
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
43 4
|
2月前
|
关系型数据库 MySQL 数据库
MySQL日志
本文介绍了MySQL中三个重要的日志:binlog、redolog和undolog。binlog记录数据库更改操作,支持数据恢复、复制和审计;redolog保证事务的原子性和持久性,实现crash-safe;undolog用于事务回滚及MVCC的实现。每个日志都有其独特的作用和应用场景,确保数据库的稳定性和数据一致性。
|
2月前
|
关系型数据库 MySQL
图解MySQL【日志】——磁盘 I/O 次数过高时优化的办法
当 MySQL 磁盘 I/O 次数过高时,可通过调整参数优化。控制刷盘时机以降低频率:组提交参数 `binlog_group_commit_sync_delay` 和 `binlog_group_commit_sync_no_delay_count` 调整等待时间和事务数量;`sync_binlog=N` 设置 write 和 fsync 频率,`innodb_flush_log_at_trx_commit=2` 使提交时只写入 Redo Log 文件,由 OS 择机持久化,但两者在 OS 崩溃时有丢失数据风险。
83 3
|
2月前
|
缓存 关系型数据库 MySQL
图解MySQL【日志】——Buffer Pool
Buffer Pool 是数据库管理系统(DBMS)中用于缓存磁盘数据页的内存区域,主要包含数据页、索引页、undo 页等。它通过减少磁盘 I/O 提升性能,特别是在处理大型数据库时效果显著。查询时,整个数据页而非单条记录会被加载到 Buffer Pool 中,以提高访问效率。
39 0
图解MySQL【日志】——Buffer Pool
|
1月前
|
SQL 存储 关系型数据库
简单聊聊MySQL的三大日志(Redo Log、Binlog和Undo Log)各有什么区别
在MySQL数据库管理中,理解Redo Log(重做日志)、Binlog(二进制日志)和Undo Log(回滚日志)至关重要。Redo Log确保数据持久性和崩溃恢复;Binlog用于主从复制和数据恢复,记录逻辑操作;Undo Log支持事务的原子性和隔离性,实现回滚与MVCC。三者协同工作,保障事务ACID特性。文章还详细解析了日志写入流程及可能的异常情况,帮助深入理解数据库日志机制。
136 0
|
2月前
|
存储 关系型数据库 MySQL
图解MySQL【日志】——Undo Log
Undo Log(回滚日志)是 MySQL 中用于实现事务原子性和一致性的关键机制。在默认的自动提交模式下,MySQL 隐式开启事务,每条增删改语句都会记录到 Undo Log 中。其主要作用包括:
96 0

热门文章

最新文章

下一篇
oss创建bucket