共计 2311 个字符,预计需要花费 6 分钟才能阅读完成。
MySQL 5.7 增强了半同步复制,rpl_semi_sync_master_wait_point 增加了 AFTER_SYNC 的值,由该参数 AFTER_SYNC/AFTER_COMMIT 两个值选择是否启用增强半同步。
mysql> SET rpl_semi_sync_master_wait_point= AFTER_SYNC; 开启了 mysql 5.7 增强半同步,5.7 默认就是开启的;
mysql> SET rpl_semi_sync_master_wait_point= AFTER_COMMIT; 5.6 的半同步方式;
当半同步模式为 AFTER_COMMIT 时:
过程分析如下:
1 > session 发出 commit 请求
2 > flush binlog and fsync binlog
3 > InnoDB 引擎层 commit
4 > 发送 binlog 到 SLAVE,等待 slave 发送 ack 确认
5 > slave 接受 binlog 写入 relay log,刷盘完成发送 ack 确认包给 master
6 > master 返回 commit ok 信息给 session
另外 (master 等待事务 A 的 ACK 的时候宕机,此时新事务 B 在宕机之前开启):
1> binlog 未发送到从库:
事务 B 获取到事务 A 提交的内容,此时宕机故障切换到 slave,事务 B 获取到的内容却丢失了。事务 A commit 没有收到反馈信息 (则需要业务判断了)。
2> binlog 已经发送给从库 :
事务 B 获取到事务 A 提交的内容,故障切换到 salve,B 仍然获取到 A 提交的内容,没毛病。事务 A commit 没有收到反馈信息,若重新执行该事务,则相当于执行两次 A 事务 (则需要业务判断了)。
当半同步模式为 AFTER_SYNC(5.7 版本推荐使用) 时:
过程分析如下:
1 > session 发出 commit 请求
2 > flush binlog and fsync binlog
3 > 发送 binlog 到 SLAVE,等待 slave 发送 ack 确认
4 > slave 接受 binlog 写入 relay log,刷盘完成发送 ack 确认包给 master
5 > InnoDB 引擎层 commit
6 > master 返回 commit ok 信息给 session
另外 (master 等待事务 A 的 ACK 的时候宕机,此时新事务 B 在宕机之前开启):
1> 事务 B 读取不到事务 A 的内容,因为事务 A 的 ENGINE 层还没有提交 (无损复制)
dump thread 过程分析:
mysql5.6 版本之前:
1> master dump thread 发送 binlog events 给 slave 的 IO thread,等待 slave 的 ack 回包
2> slave 接受 binlog events 写入 redo log,返回 ack 包给 master dump thread
3> master dump thread 收到 ack 包,给 session 返回 commit ok,然后继续发送写一个事务的 binlog。
mysql5.7 之后新增 ack 线程:
1> master dump thread 发送 binlog events 给 slave 的 IO thread,开启 ack 线程等待 slave 的 ack 回包,dump 线程继续向 slaveIO thread 发送下一个事务的 binlog。
2> slave 接受 binlog events 写入 redo log,返回 ack 包给 master ack 线程,然后给 session 返回 commit ok。
过程总结:
Master 在收到 slave 的应答后才 Commit 事务 –after_sync(5.6 上 Master 在 commit 后,才等待 Slave 的应答 –after commit).
因此在确认事务复制到 Slave 上之前,并发的事务看不到当前事务的数据.
当 Master 出现故障时, 所有已经提交的事务都复制到了 Slave 上.
缺省采用无数据丢失的应答等待机制 after_sync。用户也可以选择使用 5.6 的应答等待机制 after_commit
设置方法:
mysql> SET rpl_semi_sync_master_wait_point= AFTER_SYNC;
Master 接收到 N 个 slave 的应答后,才 commit 事务.
用户可以设置应答 Slave 的数量:
mysql> SET GLOBAL rpl_semi_sync_master_wait_for_slave_count= N;
总结:相对于 mysql 5.6 的 after_commit 方式,5.7 的 after_sync 的增强主要表现在保证了从库不会丢失数据,因为是 master fsync binlog 之后,也就是把 binlog 从 binlog cache 刷新到底层磁盘(binlog 文件),master 的 dump 进程就发送 binlog 给 slave,等 slave 的 ack 告诉 master 接收并刷盘成功,master 才进行 InnoDB 引擎层 commit,之后 master dump 线程继续向 slaveIO thread 发送下一个事务的 binlog, 而不用等到 master InnoDB 引擎层 commit 之后才发送,5.7 的这种增强保证了从库不会丢失数据;需要注意 innodb commit 的两阶段提交,最后一步才是 InnoDB 引擎层 commit,然后 InnoDB 引擎层 commit 之后,就认为是 commit 成功了,尽管还没有返回 commit ok 信息给 session,如果此时 crash, 那么启动后,实例恢复是需要借助 redo, 完成前滚;