MySQL的undo/redo日志和binlog日志,以及2PC

发现本身的知识点有点散,今天就把它们链接起来,好好总结一下。html

 

1、undo log、redo log、binlog的定义和对比

  定义和做用                       所在架构层级 日志形式 所在文件和默认名称,组织结构 是否缓存,如何缓存  写文件方式
undo log

回滚日志,在事务执行的过程当中操做任何数据以前先将数据备份到undolog中。mysql

事务失败时可根据undo log进行回滚。sql

用来保证事务的一致性。数据库

还能够用来实现多版本并发控制MVCC。缓存

InnoDB引擎层 逻辑日志,以行的形式进行记录。

共享表空间文件,ibdata0/ibdata1。架构

undo只是该文件的的一部分(rollback segment),文件由页组成,每一页又由一行行的数据组成,undo相对有本身的固定页,会循环覆盖。并发

Rollback segment,一共有128个,分别从resg slot0 - resg slot127,每个resg slot,也就是每个回滚段,内部由1024个undo segment组成。分布式

是,innodb_buffer_pool缓冲池中有undo页

尽可能顺序写。 post

回滚,实际作的是与以前相反的工做,好比INSERT须要的是DELETE,而DELETE须要的是INSERT。url

执行相反的UPDATE,将修改前的行放回去。

回滚操做写入磁盘时为随机写。

redo log

重作日志,在事务执行的过程当中不断记录事务操做的变化。

恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。

用来保证事务的原子性和持久性。

InnoDB引擎层 物理日志,记录的是数据页的物理修改。

重作日志文件,ib_logfile0/ib_logfile1。

有本身的页结构,会循环覆盖。

是,专门的独立的redo缓冲区

尽可能顺序写。

先写入日志缓冲中,而后按照必定的条件顺序写入redo日志文件。

恢复操做写入磁盘时为随机写。

 

 
binlog

二进制日志,在事务提交后进行记录。

用来备份, 经过主从复制来实现数据同步和读写分离。

MySQL数据库(上)层 逻辑日志,记录数据库全部增删改操做(sql语句)。

二进制日志文件,localhost-bin.000001~localhost-bin.00000n。

有本身的文件格式和文件结构,不会循环覆盖,追加写,文件写满再新建。

是,每一个会话有一个默认32K的缓冲。 顺序写。 

 

 2、undo log与redo log的总结和补充

Undo 记录某数据被修改的值,能够用来在事务失败时进行rollback;重要的是,undo log会产生redo log,也就是undo log的产生也会伴随redo log的产生,这是由于undo log也须要持久性的保护。即undo也是数据页的一部分。

Redo 记录某数据块被修改的值,能够用来恢复未写入data file 的已成功事务更新的数据。即redo log是对数据页修改后刷脏的一个有力补充。即WAL技术,Write-Ahead Logging,先写日志文件,再写到数据库页缓存,最后刷到磁盘的数据库中。

例如某一事务的事务序号为T1,其对数据X进行修改,设X的原值是5,修改后的值为15,那么Undo日志为<T1, X, 5>,Redo日志为<T1, X, 15>。

 

3、redo log和binlog,以及2PC

redo log是在事务进行中不断被写入,因此每一个事务对应多个日志条目。

binlog 是在事务提交完成后,进行一次写入。因此对于每一个事务仅仅对应一个日志记录。

 

redo log日志刷盘机制和参数innodb_flush_log_at_trx_commit有关。

binlog 何时刷新到磁盘跟参数sync_binlog有关。 

innodb_flush_log_at_trx_commit

0: 每隔1s,由系统后台线程刷log buffer,也就是把redo日志刷盘,这里会调用fsync,因此可能丢失最后1s的事务。

1: 每次commit时,刷redo日志,肯定fsync刷盘。为默认值。

2: 每次提交时,刷redo日志到文件系统,不调用fsync刷盘,5.6.6以前是每隔1s刷盘,以后的版本是经过参数innodb_flush_log_at_timeout设置,默认也是1s。因此也可能丢最后一秒的事务。若是有掉电保护组件的话,能够开启。

sync_binlog

表示每多少个sync事件触发一次真正的binlog fsync刷盘,默认是1,表示每次commit时binlog都会fsync。

建议这两个参数都设置成1.

  

内部XA事务与2PC

InnoDB存储引擎提供了对XA事务的支持,并经过XA事务来支持分布式事务的实现。

分布式事务(Distributed Transactions)指的是容许多个独立的事务资源(transactional resources)参与到一个全局的事务中。全局事务也必须遵循ACID原则。

XA事务容许不一样数据库之间的分布式事务,例如一台MySQL数据,一台Oracle数据库,只要全局事务中的每一个节点都支持XA事务便可。此时,InnoDB的隔离级别必须是SERIALIZABLE。

分布式事务采用两阶段提交(two-phase commit)的方式。

在第一阶段,全部参与全局事务的节点开始准备(PREPARE),告诉事务管理器它们准备好提交了。

在第二阶段,事务管理器告诉资源管理器执行ROLLBACK仍是COMMIT。若是任何一个节点显示不能提交,则全部节点被告知须要回滚。

因此,与本地事务对比,分布式事务多了一次PREPARE操做,待收到全部节点的赞成信息后,再进行提交或者回滚操做。

 

以上讨论的是外部事务,即资源管理器是MySQL数据库自己。而在MySQL数据库内部也能够存在这样相似的分布式事务。

资源管理器能够是存储引擎或插件,因此能够是存储引擎和插件之间,或者存储引擎与存储引擎之间,这种被称为内部XA事务

最为常见的内部XA事务存在于binlog与InnoDB存储引擎之间

既然是XA事务,必然涉及到两阶段提交,对于内部XA而言,一样存在着提交的两个阶段。

 

这个两阶段提交是在开启binlog以后,redo与binlog的两阶段提交。

在更新一条数据时,会先执行,而后写入redo log中,redo log进入prepare状态,执行器执行完成。

而后执行器生成这个操做的binlog,并写入磁盘。

而后提交commit,更新完成。

 

假设在任何状况下(机器掉电)mysqld crash或者os crash,MySQL仍然能保证数据库的一致性。数据的一致性是如何作到的哪?正是二阶段提交。

咱们结合几种场景来分析下二阶段提交是如何作到的:

1.prepare阶段,redo log落盘前,mysqld crash

2.prepare阶段,redo log落盘后,binlog落盘前,mysqld crash

3.commit阶段,binlog落盘后,mysqld crash

对于第一种状况,因为redo没有落盘,毫无疑问,事务的更新确定没有写入磁盘,数据库的一致性不受影响;

对于第二种状况,这时候redo log写入完成,但binlog还未写入,是提交仍是回滚呢?

对于第三种状况,此时,redo log和binlog都已经落盘,只是undo状态没有更新,虽然redo log和binlog已经一致了,事务是否应该提交?

 

对于第三种状况,咱们能够搜集到未提交事务的binlog event,因此须要提交

对于第二种状况,因为binlog未写入,须要经过执行回滚操做来保证数据库的一致性。

简而言之,对于异常的XA事务,若binlog已落盘,则事务应该提交;binlog未落盘,则事务就应该回滚。

 

注:以上XA事务的2PC流程主要参考第二篇,和书上稍微有些差异,书上写的是先提交binlog,我以为可能更合理。可是不影响对事务2PC的总体理解。 

 

 

参考资料:

《MySQL技术内幕InnoDB存储引擎》

相关文章
相关标签/搜索