前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >谈谈二阶段提交在MySQL中的广义应用

谈谈二阶段提交在MySQL中的广义应用

作者头像
林淮川
发布2021-12-20 15:58:40
1.2K0
发布2021-12-20 15:58:40
举报
文章被收录于专栏:分布式架构

- 二阶段提交介绍 -

2PC全称是Two-PhaseCommit,翻译过来是二阶段提交,是分布式事务XA规范(XA规范是X/Open DTP定义的交易中间件与数据库之间的接口规范)的实现思路,满足CAP理论的CP,是强一致性事务。

二阶段提交将分布式事务分成二个阶段,表决阶段(Commit-Request-Phase)和提交阶段(Commit Phase)。角色分为:

  • 事务发起者(AP):定义事务边界(开始、结束),并操作事务边界内的资源。
  • 事务协调者(TM):负责管理事务(提交、回滚),监控事务执行进度,分为事务唯一标识
  • 事务参与者(RM):根据“事务协调者”命令进行操作,管理本地共享资源,记录执行日志

表决阶段

  • TM:对RM发送Prepare指令,等待RM的回执(ACK)
  • RM:接收TM发送的指令,锁定资源,执行事务操作,但不提交。记录撤销日志和重做日志,如果事务执行成功,回复“是”;如失败,回复“否”

提交阶段

  • TM:如果接收到了所有RM的“是”回执,发送Commit给RM;如果在超时时间内有RM没有任何回执,或者有RM回复了“否”,发送Rollback给RM。
  • RM:根绝TM发送的指令执行Commit或者Rollback操作,针对Rollback操作,RM使用表决阶段记录的撤销日志。操作完成后给TM发送回执“OK”。如果收不到指令,一直等待。

- 二阶段提交的应用 -

在分布式系统中,由于软件或者硬件的原因,导致两个进程之间的数据出现不一致问题。不一致问题的其中一个解决思路就是分布式事务,针对数据强一致性的需求场景,二阶段提交可以满足。

- MySQL中binlog和redo log的二阶段提交广义应用 -

MySQL的双日志(binlog 和 redo log)记录采用二阶段提交保证数据的强一致性。

binlog是由MySQL Server层记录,与任何存储引擎无关。binlog主要记录的是操作日志,有三种格式:Statement、Row、Mixedlevel。binlog的主要用途是故障恢复、主从同步。

redo log是由Innodb存储引擎记录,磁盘的最小单位是⻚,MySQL的记录是以⻚为单位存取的,redo log记录的是针对⻚上的修改日志。redo log的主要用途是进程崩溃恢复,主要用来恢复⻚上的数据。binlog无法修复⻚上的数据,所以redo log不能省掉。

如果不使用二阶段提交模式,会出现什么问题呢:MySQL为了保证事务持久性,采用的是WAL机制。正常情况下binlog和redo log中都有事务开始和结束标识。如果binlog和redo log都是直接同步写入磁盘方式,即write + fsync方式。事务执行期间,每次都要写一次磁盘,TPS非常低,所以数据库不会这么设计。binlog和redo log在事务执行期间只写内存,当前链接线程不会主动去刷新到磁盘。接收到commit请求之后,当前才将binlog和redo log刷新到磁盘。

  • 如果是先写binlog 再写 redo log。当binlog写入成功后,redo log未写入成功,主节点宕机,此时分两个状态:
  1. 事务执行中,由于Innodb存储引擎的恢复是基于redo log的,此时master和slave都没有该数据,数据是一致的。
  2. 事务已提交,master基于redo log的恢复后的数据和slave中的数据会出现不一致问题。
  • 如果先写redo log再写binlog。当redo log写入成功后,主节点宕机,此时分两种状态:
  1. 事务执行中,由于当前事务没有提交,基于redo log恢复,未提交的时候不会写入,slave和master都没有该数据,数据是一致的。
  2. 事务已提交,redo log的事务已提交,binlog 记录的事务没有提交,master节点重启后,该数据会写入master节点,而slave节点没有,数据不一致。

综上所述,只有事务处于已提交状态的情况下,才会出现数据不一致问题。为了保证数据一致性。事务提交时,redo log和binlog的Commit操作需要在同一个事务里,由于binlog和redo log由不同的层记录,需要分布式事务,为了保证数据一致性,二阶段提交满足这样的需求场景。

如图,可以看到redo log的写入有两个阶段,Prepare阶段和Commit阶段,Connect Client扮演事务发起者(AP),MySQL Server扮演事务协调者(TM),binlog和 redo log扮演事务参与者(RM)。redo log和 binlog既然是在同一个事务里,需要有一个事务id标识,即binlog文件中的Xid。

我们再分析一下基于二阶段提交方式的故障恢复过程。如果写redo log 处于Prepare阶段,主节点宕机(图中的①)。此时redo log 和binlog 都没有Commit标识,master崩溃恢复的时候此时事务会回滚,binlog没有写入,不会传输给slave。所以master和slave数据是一致的。

如果写binlog成功,主节点宕机(图中的②)。master崩溃恢复的时候,先判断redo log的状态(redo log处于prepare阶段时就要写入磁盘,否则崩溃无法恢复),此时没有Commit标识,会通过Xid判断当前事务在binlog中的状态,此时redo log有Commit标识(COMMIT或Xid event),直接提交。binlog已经写入,数据已同步给slave。所以master和slave的数据是一致的。

- MySQL二阶段提交特殊性 -

表决阶段:

  • 常规二阶段提交协议中,TM发个Prepare信息给RM是串行有序的。
  • MySQL中,Server 先发给redo log 进行Prepare fsync操作(数据写入磁盘)

提交阶段:

  • 常规二阶段提交协议中,TM发个Commit信息给RM是无序的,不用关注RM发送的先后顺序。
  • MySQL的二阶段,Server 先发给binLog 进行write + fsync进行合并操作,然后在通知redo log进行Commit。

设计优点

  • 少一次交互(对于分布式事务来说就少一次网络io)
  • 少一次持久化操作(少一次磁盘io)

总结:该机制名字叫最末参与者优化。

- 作者介绍 -

李凯 架构师一枚,现就职于快乐茄(原茄子快传)。主持设计过广告系统DSP平台、IM产品、百亿级Push平台。研究方向是分布式场景下架构设计。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 川聊架构 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档