阅读 366

MySQL 半同步复制及半同步复制增强

1. MySQL复制基础


默认情况下,Mysql复制就是异步的,基本原理掘金讲主从复制的有很多,这里不再复述,简单描述下当我们执行完change master以后,各个线程的情况:

当我们在从库上执行change master 命令后,参数中设置了对应主库的 IP、端口、用户名、密码,以及要从哪个位置开始请求binlog,这个位置包含文件名(binlog file)和日志偏移量(binlog file position)。之后在从库上执行start slave命令,启动io_thread 和 sql_thread。其中io_thread负责与主库建立连接,sql_thread负责对中转日志进行重做。主库校验完用户名、密码后,按照从库传过来的位置,从本地读取binlog,通过dump_thread发给从库。从库拿到binlog后,写入本地文件,称为中转日志(relay log)。sql_thread读取中转日志,解析出日志里的命令,并执行。

相应带来的问题:

  1. 数据丢失(因为主库提交不需要保证从库完全且正确接收到,相应的当从库接收失败或重做失败的情况下,主库也无法感知)
  2. 主从延迟(又是一个大坑,先挖着)

2. MySQL半同步复制


正因为异步复制存在种种缺陷,mysql在5.5版本推出半同步复制。主库事务提交完成(after commit),binlog落盘后(sync_binlog=1),从库接收完binlog后给主库一个确认,但并不管relay-log中继日志是否正确执行完(也就是说从库对于relay log的应用仍然是异步的),主库收到确认后,将commit ok结果反馈给客户端。

相应带来的问题:

  1. 幻读
  2. 数据丢失

从库接收binlog的过程中,由于网络波动等原因,主库迟迟收不到从库的确认(rpl_semi_sync_master_timeout,默认10s,超时降级为异步复制),等待过程当中主库宕机,数据库主节点切换到从库,由于主库事务已经提交,而从库此时并没有收到完整的binlog,反映到客户端可能就是,用户发现之前能查到的订单,刷新之后,突然查不到了。

3. MySQL半同步复制增强


为解决MySQL5.6半同步问题,MySQL5.7.2后,推出了半同步复制增强(rpl_semi_sync_master_wait_point=alter_sync)。在两阶段提交中,binlog会在binlog fync之后,redo log commit之前发送给从库,主库收到从库确认后,redo log commit。即如果日志没有传输到从库,主库这时候也不会commit。若这时候服务挂掉了,主库从库均无法读到未提交的数据,解决了幻读,并且也没有传输到从库,所以也不存在数据丢失的问题。

4. 一个问题

MySQL半同步复制增强的架构下,A为主库,B为从库。某天,A库因为掉电挂掉了,B库接管了服务成为了新的主库,之后运维人员重新启动了A服务器,A还能重新加入新的主库么?

  1. 如果A是在binlog fsync之后,发送binlog给B之前挂了,此时binlog在原主库其实已经落盘,只是在引擎层还没有提交。此时redo log的事务里面只有完整的prepare而无对应的commit标识,原主库在恢复过程中,虽然这个事务在redo log并无完整,也就是事务没有提交,但是因为binlog是完整的,所以崩溃恢复流程中会根据redo log,再加上完整的binlog,去把主库的事务提交。那么在把A重新加入B的过程中,因为B未收到binlog,而A根据已落盘的binlog恢复了新的事务,就会发生A比B节点多一些事务的情况。

  2. 如果A在binlog fync,发送完binlog,等待从库B确认的过程中挂掉了,B已经收到完整的Binlog,A恢复后能够正常加入,而不会有多事务的情况。

换个说法,如果A在binlog fync后,等待从库B确认的过程中,发生了网络问题,一直收不到ack,事务一直不提交,而B因为有完整的binlog,sql_thread读取relay log并执行,此时同时查询主从两个节点,可能会有主节点事务比从节点少的情况。

崩溃恢复的判断:
如果redo log里面的事务是完整的,也就是已经有了commit标识,则直接提交;
如果redo log里面的事务只有完整的prepare,则判断对应的事务binlog是否存在并完整:
a. 如果是,则提交事务;
	怎么判断binlog是完整的:
	a. statement格式的binlog,最后会有COMMIT;
        b. row格式的binlog,最后会有一个XID event(XID为binlog 和redo log的共有字段,用来关联);   
b. 否则,回滚事务。
复制代码

参考文档:

dev.mysql.com/doc/refman/…

blog.csdn.net/qq_38114620…

文章分类
后端
文章标签