MySQL半同步复制
MySQL复制类型
不论复制为何种类型,大致流程为都为4阶段:
1.InnoDB Redo File Write
2.binlog File Flush & Sync
3.InnoDB Redo File Commit(同时释放事务持有的锁)
4.Send binlog to Slave。
相关参数:
rpl_semi_sync_master_enabled
rpl_semi_sync_master_timeout
rpl_semi_sync_master_wait_point(半同步与增强半同步参数)
异步复制
Master、Slave事务更新的不同步,就算是没有网络或者其他系统的异常,当业务并发上来时,slave因为要顺序执行master批量事务导致很大的延迟,在读写分离的架构中会导致用户读取数据不一致的现象。
半同步复制
after_commit模式下,4个阶段的顺序为1->2->3->4。
Master将每个事务写入binlog(sync_binlog=1),传递到slave刷新到磁盘(sync_relay=1),同时主库提交事务(commit)。Master等待Slave反馈收到relay-log,只有收到ACK后master才将commit OK结果反馈给客户端。在MySQL-5.7之前使用after_commit的模式下,客户端事务在存储引擎层提交后,在得到从库确认的过程中,主库宕机了。此时,即主库在等待Slave ACK的时候,虽然没有返回当前客户端,但事务已经提交其他客户端会读取到已提交事务。如果Slave端还没有读到该事务的events,同时主库发生了crash,然后切换到备库。那么之前读到的事务就不见了,出现了逻辑意义上的幻读。
增强半同步
after_sync模式下,4个阶段的顺序为1->2->4->3,消除幻读的问题。
半同步与增强半同步如何选择
现在假设阶段1、2、3各需要1ms时间,阶段4需要0.2ms时间,那么一次事务提交的时间:
T after_sync = 1 + 1 + 0.2 + 1 = 3.2 ms
T after_commit = 1 + 1 + 0.2 + 1 = 3.2 ms
after_sync的事务T1~T3的耗时
after_sync.png
after_commit的事务T1~T3的耗时
after_commit.png
直观感觉after_commit在耗时上优于after_sync,但是此结论为基于单线程的情况下如何加上Group Commit的背景又是如何呢?
在并发的场景下,若事务之间的修改不冲突,则事务是可以同时提交的,也就是可以进入到组提交(Group Commit)优化流程中。那么这时,事务的提交如下图所示:
group.png
事务TX1~TX4可以同时进入到提交阶段,这时会进入到MySQL的组提交优化中。这时产生的优化效果有:
- InnoDB Redo Prepare只需要一次I/O操作
- InnoDB binlog Write只需要一次I/O操作
- 接收到ACK后唤醒事务提交队列只需要一次
可以看到有组提交加持下数据库的的性能提升是非常明显的,假设没有组提交,并且唤醒等待线程需要0.02ms,则没有组提交的情况下,TX1~TX4事务所需要的时间为:
T[1~4 ]= ( 1 + 1 + 1 + 0.2 + 0.02 ) * 4 = 12.88 ms
在有组提交的优化加持下,TX1~TX4事务所需要的时间优化为了:
T[1~4] = 1 + 1 + 1 + 0.2 + 0.02 = 3.22 ms
那么对比after_sync和after_commit模式,并发的优势在于:after_sync的组提交比例远远高于after_commit,因为after_sync要等日志传送到远程,事务才提交。那么后面等待提交的事务队列将拉长,后续组提交的事务比例也就越高,I/O开销变小,唤醒事务队列的成本也将越小,当到达某一个组提交阈值点,after_sync就能逆转未来,性能超越after_commit。