以下讨论的前提 是设置MySQL的crash safe相关参数为双1。
sync_Binlog=1
:MySQL 每次在提交事务前会将二进制日志同步到磁盘上,保证在服务器崩溃时不会丢失事务。innodb_flush_log_at_trx_commit=1
:每次COMMIT
后立即刷新同步数据到硬盘。WAL指的是对数据文件进行修改前,必须将修改先记录日志。MySQL为了保证ACID中的一致性和持久性,使用了WAL。
Redo log就是一种WAL的应用。当数据库忽然掉电,再重新启动时,MySQL可以通过Redo log还原数据。也就是说,每次事务提交时,不用同步刷新磁盘数据文件,只需要同步刷新Redo log就足够了。相比写数据文件时的随机IO,写Redo log时的顺序IO能够提高事务提交速度。
Redo log的刷盘操作将会是最终影响MySQL TPS的瓶颈所在。为了缓解这一问题,MySQL使用了组提交,将多个刷盘操作合并成一个,如果说10个事务依次排队刷盘的时间成本是10,那么将这10个事务一次性一起刷盘的时间成本则近似于1。
为了保证Redo log和Binlog的数据一致性,MySQL使用了二阶段提交,由Binlog作为事务的协调者。而引入“二阶段提交”使得Binlog又成为了性能瓶颈,先前的“Redo log组提交”也成了摆设。为了再次缓解这一问题,MySQL增加了“Binlog组提交”机制,目的同样是将Binlog的多个刷盘操作合并成一个,结合Redo log本身已经实现的“组提交”,分为三个阶段“Flush阶段”、“Sync阶段”、“Commit阶段”完成“Binlog组提交”,最大化每次刷盘的收益,弱化磁盘瓶颈,提高性能。
参见《MySQL-5.7事务二阶段提交机制.md》
注意:在MySQL中每个阶段都有一个队列,每个队列都有一把锁保护,第一个进入队列的事务会成为leader,leader领导所在队列的所有事务,全权负责整队的操作,完成后通知队内其他事务操作结束。
Binlog_group_commit_sync_delay=N
:在等待N μs后,开始事务刷盘(图3中Sync Binlog步骤)Binlog_group_commit_sync_no_delay_count=N
:如果队列中的事务数达到N个,就忽视Binlog_group_commit_sync_delay
的设置,直接开始刷盘(图4中Sync Binlog步骤)单纯通过SHOW BINLOG EVENTS
无法发现有关组提交的任何信息,但是通过mysqlbinlog
工具,便可以发现组提交的内部信息,类似如下。
[root]# mysqlbinlog mysql-bin.0000006 | grep last_committed #150520 14:23:11 server id 88 end_log_pos 259 CRC32 0x4ead9ad6 GTID last_committed=0 sequence_number=1 #150520 14:23:11 server id 88 end_log_pos 1483 CRC32 0xdf94bc85 GTID last_committed=0 sequence_number=2 #150520 14:23:11 server id 88 end_log_pos 2708 CRC32 0x0914697b GTID last_committed=0 sequence_number=3 #150520 14:23:11 server id 88 end_log_pos 3934 CRC32 0xd9cb4a43 GTID last_committed=0 sequence_number=4 #150520 14:23:11 server id 88 end_log_pos 5159 CRC32 0x06a6f531 GTID last_committed=0 sequence_number=5 #150520 14:23:11 server id 88 end_log_pos 6386 CRC32 0xd6cae930 GTID last_committed=0 sequence_number=6 #150520 14:23:11 server id 88 end_log_pos 7610 CRC32 0xa1ea531c GTID last_committed=6 sequence_number=7 #150520 14:23:11 server id 88 end_log_pos 8834 CRC32 0x96864e6b GTID last_committed=6 sequence_number=8 #150520 14:23:11 server id 88 end_log_pos 10057 CRC32 0x2de1ae55 GTID last_committed=6 sequence_number=9 #150520 14:23:11 server id 88 end_log_pos 11280 CRC32 0x5eb13091 GTID last_committed=6 sequence_number=10 #150520 14:23:11 server id 88 end_log_pos 12504 CRC32 0x16721011 GTID last_committed=6 sequence_number=11 #150520 14:23:11 server id 88 end_log_pos 13727 CRC32 0xe2210ab6 GTID last_committed=6 sequence_number=12 #150520 14:23:11 server id 88 end_log_pos 14952 CRC32 0xf41181d3 GTID last_committed=12 sequence_number=13 ...
可以发现MySQL 5.7二进制日志较之原来的二进制日志内容多了last_committed和sequence_number这两项内容。这两个值即所谓的“逻辑时间戳标记(Logical Clock)”,可以用于控制多线程复制(MTS)特性。
《[原理解析] MySQL组提交(group commit)》
https://mp.weixin.qq.com/s/_LK8bdHPw9bZ9W1b3i5UZA
《MySQL 5.7新特性:并行复制原理(MTS)》
https://blog.csdn.net/andong154564667/article/details/82117727