天天看点

MySQL内核月报 2015.01-MySQL · 性能优化· Group Commit优化

<b>背景</b>

关于group commit网上的资料其实已经足够多了,我这里只简单的介绍一下。

众所周知,在mysql5.6之前的版本,由于引入了binlog/innodb的xa,binlog的写入和innodb commit完全串行化执行,大概的执行序列如下:

当sync_binlog=1时,很明显上述的第二步会成为瓶颈,而且还是持有全局大锁,这也是为什么性能会急剧下降。

oracle mysql 在5.6版本开始也支持binlog group commit,使用了和mariadb类似的思路,但将group commit的过程拆分成了三个阶段:flush stage 将各个线程的binlog从cache写到文件中; sync stage 对binlog做fsync操作(如果需要的话);commit stage 为各个线程做引擎层的事务commit。每个stage同时只有一个线程在操作。

tips:当引入group commit后,sync_binlog的含义就变了,假定设为1000,表示的不是1000个事务后做一次fsync,而是1000个事务组。

<b>xa recover</b>

在binlog打开的情况下,mysql默认使用mysql_bin_log来做xa协调者,大致流程为:

通过这种方式,可以让innodb和binlog中的事务状态保持一致。显然只要事务在innodb层完成了prepare,并且写入了binlog,就可以从崩溃中恢复事务,这意味着我们无需在innodb commit时显式的write/fsync redo log。

tips:mysql为何只需要扫描最后一个binlog文件呢 ? 原因是每次在rotate到新的binlog文件时,总是保证没有正在提交的事务,然后fsync一次innodb的redo log。这样就可以保证老的binlog文件中的事务在innodb总是提交的。

<b>问题</b>

其实问题很简单:每个事务都要保证其prepare的事务被write/fsync到redo log文件。尽管某个事务可能会帮助其他事务完成redo 写入,但这种行为是随机的,并且依然会产生明显的log_sys-&gt;mutex开销。

<b>优化</b>

从xa恢复的逻辑我们可以知道,只要保证innodb prepare的redo日志在写binlog前完成write/sync即可。因此我们对group commit的第一个stage的逻辑做了些许修改,大概描述如下:

通过延迟写redo log的方式,显式的为redo log做了一次组写入,并减少了log_sys-&gt;mutex的竞争。

目前官方mysql已经根据我们report的bug#73202锁提供的思路,对5.7.6的代码进行了优化,对应的release note如下:

<b>性能数据</b>

简单测试了下,使用sysbench, update_non_index.lua, 100张表,每张10w行记录,innodb_flush_log_at_trx_commit=2, sync_binlog=1000,关闭gtid

继续阅读