MySQL半同步复制浅析

在关系型数据库中,数据的安全性需要通过备份或者容灾的方式去实现。容灾的实现方式主要是通过主备模式,即主库负责数据写入的同时,还需要将其生成的日志传输到备库,备库在接收到主库传过来的日志之后进行回放,以达到和主库数据一致的目的。

MySQL实现主备同步的方式和大多数关系型数据库不太一样,MySQL采用逻辑复制的方式实现主备同步,即采用同步二进制日志binlog的方式进行数据同步。

MySQL主备同步在同步方式的选取上,既考虑了性能问题,同时又做了最大化保证数据一致性的考量,最终选取半同步复制的方式(相比全同步复制提升了性能,相比异步复制保证了数据一致性)。在半同步复制的过程中,MySQL通过设置“桩”的方式来设置主库在什么时候收到从库的反馈信息(ACK)。

本文主要从MySQL半同步参数设置、半同步复制的建立、MySQL5.7的无损复制等方面做一些浅析,以此来理解MySQL实现半同步复制的大致过程。

1. 半同步复制的前置条件

主库开启半同步复制,且至少有一个半同步复制的从库。备库设置为半同步的参数为rpl_semi_sync_master_enabled,如果为ON,则会将status参数Rpl_semi_sync_slave_status设置为ON。需要注意的是,如果复制已经开始,而rpl_semi_sync_master_enabled为OFF,如果将其设置为ON,还需要做stop slave;start slave才能开启半同步。
在这里插入图片描述

源码判断条件如下:
在这里插入图片描述
当满足条件之后,主库的状态参数Rpl_semi_sync_master_status将被置为ON

在这里插入图片描述
参数解析

在这里插入图片描述

2. 半同步复制关系建立及维持

半同步复制的实质是,在主库被阻塞的过程中(等待从库反馈消息),主库处理线程不会返回去处理当前事务。当阻塞被激活之后,系统才会将控制权交给当前线程,然后继续处理当前事务余下的事情。处理完成之后,此时主库的事务提交,同时至少会有一个从库也已经收到了这个事务的Binlog,这样就尽可能地保证了主库和从库的数据一致性。

Mysql通过在一个事务处理过程中,在不同阶段设置“桩”的形式来实现插入

2.1 transmit_start

半同步复制关系的建立则是在transmit_start处实现,该桩的执行时机是在主库向从库发送Binlog之前,从库请求Binlog复制之后。即从库连接到主库之后,告诉主库其是不是配置了半同步。

从库请求Binlog复制的时候,如果主库已经开启半同步复制(rpl_semi_sync_master_enabled=ON),则通过slave对master的连接,设置会话参数rpl_semi_sync_slave=1,表示当前从库是半同步类型的复制,此参数为会话变量。

  • 源码调用入口函数mysql_binlog_send
    在这里插入图片描述
  • 半同步回调函数repl_semi_binlog_dump_start

首先:判断当前有没有开启半同步,如果没有,则直接返回

其次:如果开启半同步,则在ack_receiver中加入当前从库线程信息,且状态参数 Rpl_semi_sync_master_clients的值加1。(注:ack_receiver是在MySQL5.7版本中新加入的ACK接收管理机制。这种机制是单独建立的,通过select来对每一个注册的从库做监听,在有ACK信息返回时,通过读取ACK消息获取对应的Binlog位置)

备库设置rpl_semi_sync_slave变量源码

在这里插入图片描述
主库回调源码

在这里插入图片描述
2.2 before_send_event

该桩的执行时机是在发送Binlog之前,其作用是在预留的位置中填写半同步控制信息(在binlog事件头信息中打标志),目的是告诉从库在收到binlog之后,要不要向主库反馈ACK信息。

在这里插入图片描述
完成上面的逻辑判断后,通过修改当前要发送的binlog事件头内容,打上相应的标记,如果需要反馈ACK,则写入1,反之则写入0。

从库在接收到binlog之后,通过该标记信息判断需不需要给主库发送ACK信息。

2.3 after_send_event

该桩的执行时机是在Binlog事务发送完成之后,从从库接收ACK信息,来确定从库是不是已经收到Binlog,以便通知等待事务继续处理余下事情,同时继续向从库发送Binlog。

在上一步的before_send_event中确定了一个事务需要发送ACK请求,那么此时就会等待ACK反馈。在MySQL5.7版本中,接收ACK的信息放到一个专门的接收线程ack_receiver中。如果ACK位置比处于等待状态的主库事务线程的最小位置大,则通知他们可以继续提交操作。

至此,整个半同步建立及半同步维持的主要流程比较清晰,整个主要流程图如下:
在这里插入图片描述

3. after_sync与after_commit

按照上面半同步复制的梳理,在ACK等待的时机上,MySQL通过参数rpl_semi_sync_master_wait_point设置等待位点,在MySQL5.6版本中默认是after_commit,而在MySQL5.7中则默认是after_sync。通过增加该位点,MySQL5.7的半同步模式实现了数据的无损复制。

3.1 after_sync

after_sync等待ACK的时机是在Flush Binlog及sync之后,存储引擎提交之前。具体流程如下 :
在这里插入图片描述在该流程下,当主库提交事务之后,binlog日志写入日志文件并同步到从库的relay log。但该事务在主库的存储引擎并没有提交,该事务并没有执行成功。如果此时主库在等待从库反馈ACK信息的过程中发生了crash,则该事务在主库重启之后会回滚。但会导致的一个问题是备库已经应用并提交了该事务,备库会比主库多数据。MySQL在无法解决分布式数据一致性问题的情况下,能保证的是数据不丢失。

3.1.1 模拟场景验证

按照上面半同步参数设置模拟验证场景

主备:
rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=1000000
rpl_semi_sync_master_wait_for_slave_count=1
rpl_semi_sync_master_wait_no_slave=ON
rpl_semi_sync_master_wait_point=AFTER_SYNC

备库:
rpl_semi_sync_slave_enabled=ON

在这里插入图片描述
3.2 after_commit

after_commit等待ACK的时机是在存储引擎提交之后。具体流程如下
在这里插入图片描述
在该流程下,当主库提交事务之后,binlog日志写入日志文件并同步到从库的relay log,同时事务在主库的存储引擎提交。此时存在数据丢失的风险。如果主库发起提交事务,数据已经在主库的存储引擎提交,在binlog还没有同步到从库之前,主库发生crash,则从库上该事务数据丢失。

3.2.1 模拟场景验证

主备:
rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=1000000
rpl_semi_sync_master_wait_for_slave_count=1
rpl_semi_sync_master_wait_no_slave=ON
rpl_semi_sync_master_wait_point=AFTER_COMMIT

备库:
rpl_semi_sync_slave_enabled=ON
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值