mysql 内部xa(两阶段提交)
原文链接:https://www.linuxidc.com/Linux/2015-11/124942.htm
XA 将事务的提交分为两个阶段,而这种实现,解决了 binlog 和 redo log的一致性问题,这就是MySQL内部XA的第三种功能。
MySQL为了兼容其它非事物引擎的复制,在server层面引入了 binlog, 它可以记录所有引擎中的修改操作,因而可以对所有的引擎使用复制功能;MySQL在4.x 的时候放弃redo的复制策略而引入binlog的复制(淘宝丁奇)。
2> InnoDB维持了状态为Prepare的事务链表,将这些事务的xid和Binlog中记录的xid做比较,如果在Binlog中存在,则提交,否则回滚事务。
将Binlog Group Commit的过程拆分成了三个阶段:
1> flush stage 将各个线程的binlog从cache写到文件中;
2> sync stage 对binlog做fsync操作(如果需要的话;最重要的就是这一步,对多个线程的binlog合并写入磁盘);
3> commit stage 为各个线程做引擎层的事务commit(这里不用写redo log,在prepare阶段已写)。每个stage同时只有一个线程在操作。(分成三个阶段,每个阶段的任务分配给一个专门的线程,这是典型的并发优化)
淘宝对binlog group commit进行了进一步的优化,其原理如下:
从XA恢复的逻辑我们可以知道,只要保证InnoDB Prepare的redo日志在写Binlog前完成write/sync即可。因此我们对Group Commit的第一个stage的逻辑做了些许修改,大概描述如下:
Step1. InnoDB Prepare,记录当前的LSN到thd中;
Step2. 进入Group Commit的flush stage;Leader搜集队列,同时算出队列中最大的LSN。
Step3. 将InnoDB的redo log write/fsync到指定的LSN (注:这一步就是redo log的组写入。因为小于等于LSN的redo log被一次性写入到ib_logfile[0|1])
Step4. 写Binlog并进行随后的工作(sync Binlog, InnoDB commit , etc)
也就是将 redo log的write/sync延迟到了 binlog group commit的 flush stage 之后,sync binlog之前。
通过延迟写redo log的方式,显式的为redo log做了一次组写入(redo log group write),并减少了(redo log) log_sys->mutex的竞争。
也就是将 binlog group commit 对应的redo log也进行了 group write. 这样binlog 和 redo log都进行了优化。
参数innodb_support_xa默认为true,表示启用XA,虽然它会导致一次额外的磁盘flush(prepare阶段flush redo log). 但是我们必须启用,而不能关闭它。因为关闭会导致binlog写入的顺序和实际的事务提交顺序不一致,会导致崩溃恢复和slave复制时发生数据错误。如果启用了log-bin参数,并且不止一个线程对数据库进行修改,那么就必须启用innodb_support_xa参数。