浅谈 MySQL 写数据一致性保障机制

如何保障-2PC

MySQL是通过2PC来保证写数据一致性的,具体步骤如下。

  1. 执行器先向存储引擎取指定行。如果这些行数据所在的数据页本来就在内存中,就直接返回给执行器,否需要先从磁盘读入内存,然后再返回。
  2. 执行器拿到数据后更新,得到新的数据,再调用存储引擎接口写入新数据。
  3. 存储引擎将新数据更新到内存,同时将这个更新操作记录到 redo-log 里面,此时 redo-logprepare 状态。然后告知执行器执行完成了,可以 commit 事务。
  4. 执行器生成这个操作的 binlog并把 binlog 写入磁盘
  5. 执行器调用存储引擎的提交事务接口,存储引擎把 redo-log 改成 commit 状态,更新完成。

为什么2PC可以保障

  • 如果在 redolog_prepare → binlog 发生崩溃,因为事务没有提交,所以直接回滚就行,不会产生任何影响。

  • 如果在 binlog → redolog_commit 发生崩溃,MySQL的判断逻辑如下:

    1. 判断 redo-log 是否完整(是否处于commit状态),如果是就直接提交。
    2. 如果 redo-log 处于 prepare 状态,这时候会判断 binlog 是否完整(如果格式是statement,完整日志最后会有COMMIT标识,如果格式是row,完整日志最后会有一个XID event),如果完整就提交redo-log,不完整就回滚事务。

为什么其他方式不行

这里的其他方式指除2PC(redolog_prepare → binlog→ redolog_commit )外的redolog→ binlogbinlog→ redolog 两种方式。

我们可以简单用分布式事务来理解,MySQL的执行器和执行引擎是两个系统,必须保证这两个系统写数据的一致性。

或者采用反证法,一共就3种可能性,除了redolog_prepare → binlog → redolog_commit之外还有另外两种:

  1. redolog_full(redolog_prepare → redolog_commit) → binlog
    1. 如果 redolog 没写完就挂了,则一点影响都没有(redolog没成功写入意味着事务没有提交,就当这件事没发生过,redolog的写入机制决定了其一旦写入成功就不允许回滚了,如果回滚就可能会覆盖其他的事务 → 不同事务共用一块 redolog buffer,在落盘时还会顺带提交)。
    2. 如果写完 redo-log ,机器挂了,binlog 日志没有写入,那么机器重启后,这台机器会通过 redo-log 恢复数据,但是因为 binlog 并没有写入,因此后续进行备份或主从复制的时候,就会丢失相关记录 → 相当于少执行了一个事务。
  2. binlog → redolog_full
    1. 如果写完了 binlog,机器异常重启了,由于没有 redo-log,这个事务是无法恢复的,但是 binlog 又有记录,那么和上面同样的道理,会产生数据不一致 → 相当于多了一个事务。

你可能感兴趣的:(MySQL,mysql,数据库,java)