MySQL下的两阶段提交
两阶段提交
事务提交后,redo log 和bin log 都需要刷新到磁盘中,但这两个刷盘是独立的逻辑,可能出现某一个成功,另一个失败的状况。
- 在将redo log刷盘后,MySQL宕机,binlog没有来得及刷盘。此时在重启MySQL后,会通过redo log 将值更新,但bin log中没有这条更新操作,会导致主库是新值,从库是旧值。
- 在将bin log刷盘后,MySQL宕机,redolog没来得及刷盘。此时重启后由于redo log没有记录,该次事务失效,但binlog仍然记录了该操作,会导致主库是旧值,从库是新值。
所以,当redo log和bin log有一个日志持久化失败时就会导致主从环境数据不一致,这是因为 redolog影响主库,binlog影响从库
为了避免两份日志出现逻辑不一致的问题,使用两阶段提交来解决。分为 准备阶段、提交阶段
过程
MySQL会使用内部XA事务,内部XA事务由binlog作为协作者,存储引擎是参与者。当客户端在执行commit语句或者在自动提交的情况下,MySQL内部开启一个XA事务,分两阶段来完成XA事务的提交。
- prepare阶段:将XID写入到redo log,同时将redo log对应的事务状态设置为prepare,然后将redo log持久化到磁盘。(innodb_flush_log_at_trx_commit = 1 的作用)
- commit阶段:将XID写入到binlog,然后将binlog持久化到磁盘,接着调用引擎的事务提交接口,将redo log状态设置为commit,此时该状态并不需要刷盘,只需要write到文件系统的page cache即可,因为只要binlog写磁盘成功,就算redolog的状态还是prepare也没关系,一样认为事务执行成功。
两阶段提交针对异常重启
在两阶段提交的不同时刻,MySQL异常重启会由一些现象:
不管是A时刻还是B时刻,此时redo log的状态都是prepare,在MySQL重启后会按顺序扫描redolog 文件,对于处于prepare状态的redo log会根据它的XID去binlog查看是否存在此XID:
- 若binlog中没有该内部XA事务的XID,说明binlog没有完成刷盘,而redolog完成了,则会回滚事务。
- 若binlog中有当前内部事务的XID,说明binlog已经落盘,则提交事务。
两阶段提交的问题
- 磁盘IO次数多:对于双1配置,及sync_binlog 、innodb_flush_log_at_trx_commit 为1时,每次事务提交都会进行两次fsync刷盘。
- 锁竞争激烈:在多事务的情况下,为了保证两个日志的提交顺序一致,因此在两阶段提交的流程基础上,还需要加一个锁来保证提交的原子性。
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术