mysql的半同步复制
1. binlog dump线程何时向从库发送binlog
mysql在server层进行了组提交之后,为了提高并行度,将提交阶段分为了 flush sync commit三个阶段,根据sync_binlog的不同,会在 flush阶段或者 sync阶段以更新binlog位置点的方式通知 dump 线程发送binlog,而在commit阶段等待从库的ACK应答情况,即 after_sync 和 after_commit。
flush stage; if sync_binlog != 1 { update binlog end pos -> binlogdump thread //发信号给dump线程 } sync stage; if sync_binlog == 1 { update binlog end pos -> binlogdump thread //发信号给dump线程 } if after_sync { wait for slave ack } commit stage; if after_commit { wait for slave ack }
MySQL宕机时sync_binlog的值对数据库的影响?
sync_binlog == 1:在sync阶段通知 dump 线程发送binlog给slave节点,这时binlog确定已经刷盘,主库宕机对从库无影响。
sync_binlog != 1:在 flush阶段通知 dump 线程发送 binlog给slave节点,这时主节点binlog还没有刷盘,此时主库宕机,最后一次binlog没有落盘,会出现从库比主库多一次事务的情况。
MySQL宕机时 after_commit和after_sync对数据库的影响?
after_sync:假设 master节点在等待接收从节点ack时宕机,因为引擎层没有提交,HA切换到从库,因为binlog已经在从库重放,这时在业务层面就会发现在主库没有提交的事务在从库已经提交了,从库比主库多一次事务。在 mysql层面上,因为binlog的sync完成已经对应着一次事务的写入完成,master节点重启之后可以直接挂在从库上。
after_commit:先在主库引擎层进行事务提交后等待从库确认。因此,在主库commit之后从库ack之前,该次事务的提交对其他业务连接可见。此时,如果在主库 commit之后从库 ack之前,master与slave之间网络出现抖动,造成binlog event没有发送给从库,此时主库宕机。HA切换到从库,就会发现新的主库缺少了最后一组事务;对于其他业务连接而言,就像出现了幻读。
after_commit 和 after_sync 哪个性能更好?
sync redo log; A = 1ms
flush/sync binlog; B = 1ms
wait for slave ack; C = 1ms
commit; D = 1ms
当mysql没有采用组提交时,after commit的性能更好。
当3个事务串行提交时,after_sync 执行顺序为
A。。B。。C。。D。。
A。。B。。C。。D。。
A。。B。。C。。D。。
耗时为 3 * (A + B + C + D)
after_commit执行顺序为
A。。B。。D。。C。。
A。。B。。D。。C。。
A。。B。。D。。C。。
耗时为 (A + B + D + C) + 2 * (A + B + D);明显 after_commit性能更好。
但是,当mysql采用组提交后,因为after_sync要等待日志传输到远程,事务才提交,那么后面等待提交的事务队列拉长,后续组提交涉及的事务数就越大,IO开销变小,唤醒事务队列的成本也更小,性能更好。但是当存在热点数据时,after commit模式下,事务已经在引擎层提交,不再持有事务内锁,此时after commit性能更好。
总结下来就是:
after_commit模式下,因为在 commit之后,wait slave ack之前就释放了事务锁,下一次事务就可以开始;因此在未采用组提交或着采用了组提交但是存在热点数据的情况下,性能更好。
after_sync模式下,事务要传输到远程,事务才提交,导致了后续等待提交的事务队列的拉长,后续组提交的队列也就越长,io开销变小,此时性能更好。
异步复制修改为半同步复制的流程:
1. 在主从节点上加载半同步复制插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
set global rpl_semi_sync_slave_enabled =1;【在从库开启半同步复制,主从都要开启,不要写在配置文件中】
set global rpl_semi_sync_master_enabled =1;【在主库开启半同步复制,主从都要开启,不要写在配置文件中】
set global rpl_semi_sync_master_timeout =1000; 【同步复制中由于网络原因导致复制时间超过1000ms后,增强半同步复制就变成了异步复制了】
set global rpl_semi_sync_master_wait_for_slave_count = 1;【该变量控制slave应答的数量,默认是1,表示master接收到几个slave应答后才commit】
其中,set global rpl_semi_sync_slave_enabled =1;和 set global rpl_semi_sync_master_enabled =1; 不建议写入配置文件,写入配置文件之后,如果slave挂掉重启,会自动开启增强半同步复制。如果slave库断开master时间较长,最好是先开启mysql异步复制,待slave追上master后再开启增强半同步复制。这样不会拖垮master节点。
2. 在从库上执行以下命令:
stop slave io_thread;
start slave io_thread;
3. 在主从库配置文件中添加
plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
rpl_semi_sync_master_timeout =1000;
rpl_semi_sync_master_wait_for_slave_count = 1;
4. 以上配置之后从库挂掉重启之后加入集群之后开启半同步复制的操作为:
set global rpl_semi_sync_slave_enabled =1;
set global rpl_semi_sync_master_enabled =1;
Stop slave;
Start slave;