tyltr技术窝

二阶段提交2PC是解决分布式事务的方法,但在innodbredo log的提交过程中,也存在二阶段提交。

注:redo log是innodb的机制,不是mysql的机制,所以只能被innodb独享的。
binlogmysql的机制,所以说可以被所有存储引擎共享。

数据不一致#

一次提交既需要写入innodbredo log,又需要写入mysqlbinlog
万一前一个写入成功,后一个写入失败,那一定会造成数据的不一致性。

注:前一个写入失败,后一个写入成功的情况,不会出现。因为可以人为的排斥

先写 redo log 后写 binlog#

假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。
由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,
所以恢复后这一行 c 的值是 1。但是由于 binlog 没写完就 crash 了,这时候 binlog 里面
就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。
然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,
这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。

先写 binlog 后写 redo log#

如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,
所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。所以,
在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。

主从一致性也会受到影响,如果先写 binlog,在写入 binlog 那一刻,就有可能同步到备节点并执行,
后续奔溃恢复删除这个 binlog 后,虽然保证了本节点的两个日志一致,但是这个被删除的 binlog 已经
被备节点执行了

MySQL通过两阶段提交解决了服务层binlog与引擎层Innodb的redo log的一致性与协同问题。

两阶段提交#

二阶段提交示意图,如下:

二阶段提交

第一阶段:持有锁prepare_commit_mutex,并且写redolog
设置为Prepared状态,此时binlog不作任何操作;

第二阶段:包含两部分

  • 1 写 Binlog
  • 2.将 redolog设置为commit,然后释放prepare_commit_mutex

注:以 binlog 的写入与否作为事务提交成功与否的标志,
innodb commit标志并不是事务成功与否的标志。