MySQL的主从复制模式

  MySQL的主从复制模式包括异步复制,全同步复制,半同步复制。MySQL默认为异步模式

异步复制:
(Asynchronous replication)。MySQL的默认复制,主库在执行完客户端提交的事务后会立刻将执行结果返回给客户端,并不关心从库是否已经接收处理,这样带来的问题就是当主死掉了,此时主上提交的事务可能还没有传到从上。而强行将从提升为主就会导致新主上的数据不完整。

异步复制是一种基于偏移量的主从复制,实现的原理是:主库开启bbinlog功能并授权从库连接主库,从库通过change master得到主库的相关同步信息,然后连接主库进行验证,主库的IO线程根据从库slave的线程请求,从master.info开始记录的位置点向下开始取信息,同时把提取到的位置点和最新的位置与binlog信息一同发给从库IO线程,从库将相关的sql语句放在relay_log中,最终从库的sql线程会将relay_log里的sql语句应用到从库上,至此同步过程完成,以后一直循环此过程。
对于异步复制而言,主库将事务的Binlog事件写入到binlog文件中,此时主库会通知下dump线程发送这些新的binlog然后主库会继续处理提交操作,而此时并不保证这些日志会传输到任何一个从库的节点上。

全同步复制:
(Fully synchronous replication)。当主库执行完一个事务,所有的从库都执行了该事务才会将结果返回给客户端。这样保证了数据的安全性,但是因为需要等待所有从库执行完该事务才能返回客户端结果,所以全同步复制的性能必然会受到很大的影响。
对于全同步复制而言,当主库提交一个事务后,要求所有从库节点必须收到,执行并提交这些事务,然后主库线程才能继续做后续操作,而因此带来的问题就是主库完成一个事务的时间被大幅度拉长,性能降低。

半同步复制:
(Semi synchronous replication)。介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时也会造成一定程度的延迟,这个延迟为一个TCP/IP往返的时间。所以半同步复制需要在低延时的网络中使用。
对于半同步复制而言,是介于同步复制和异步复制之间的一种,主库需要等待至少一个从库节点收到并且刷新binlog到relay日志中,主库不需要等待所有从库给主库反馈,同时这里只是收到反馈而不死和完全执行并且提交事务的反馈,这样会节省很多的时间。


MySQL的半同步复制技术

MySQL的异步复制依赖于二进制日志也就是binary log进行数据复制。
一台主机(master),一台从机(slave)
正常的复制:事务t1写入master的binlog buffer;master的dumper线程通知slave有新的事务t1,binlog buffer进行checkpoint;slave的io线程接收到t1并写入到自己的relay log;slave的sql线程写入到本地数据库。这个时候master和slave都能看到这条新的事务,即使master挂了,slave也可以提升为新的master。
异常的复制:事务t1写入master的binlog buffer;master的dumper线程通知slave有新的事务t1,binlog buffer进行checkpoint;slave因为网络不稳定,一直没收到t1,master挂掉,slave提升为新的master,t1丢失。
问题:无法解决主机和从机事务更新的不同步问题,就算没有网络或者其他的异常,当一个业务具有高并发,slave因为要批量执行master的事务就会导致很大的延迟。
为了解决上述问题,MySQL5.5开始推出半同步复制。相比异步复制,半同步复制提高了数据的完整性,因为很明确知道,在一个事务提交成功后,这个事务至少会存在在两个地方。因为在master的dumper线程通知slave后,增加了一个ack(消息确认)机制,即是否成功接收到t1的标识码,也就是dumper线程除了发送t1到slave还承担了接收slave的ack工作。如果出现异常没有收到ack会自动降级为普通的复制,直到异常修复以后又会变成半同步复制。

半同步复制的特性:

从库会在连接到主库时告诉主库它是不是配置了半同步。
从库节点只有在接收到某一事务的所有Binlog,将其写入并Flush到Relay Log文件后才会通知主库上面的等待线程。
半同步复制必须在主库和从库两端都开启才生效,如果在主库上或从库任一节点没打开,主库都会以异步的方式进行复制。
如果在主库的等待过程中,等待时间已经超过了配置的超时时间,没有任何一个节点通知当前事务,那么此时主库会自动转换为异步复制,当至少一个 半同步从节点赶上来时,主库便会转为半同步复制方式。

半同步的意思表示master只要接收到其中一台slave的返回信息就会commit,否则需要等待到超时时间转为异步进行提交。这种方式在损失很小的性能的情况下尽可能的提高了数据安全。

半同步复制本质上来说还是一种异步复制,因为主库产生binlog到主库的binlog file,传到从库的中继日志,,然后从库应用,可以说传输是异步的应用也是异步的。半同步复制指的是传输同步而应用还是异步的。也就是说保证了数据的安全不丢失,但是不能保证应用的同步即数据一致性。

半同步复制存在的问题:

客户端的事务在存储引擎层提交了,但在得到存库确认的过程中,主库宕机了,此时有两种可能的情况:

  • 事务还没有发送到从库上:
    客户端此时会受到事务提交失败的提示,而客户端会将请求提交到新的主上,当宕机的主库重新启动后,以从库的身份加入到这个主从结构中,会发现该事务在此从库中被提交了两次。一次是作为之前主库时,一次是作为新从库被同步来的。
  • 事务已经发送到从库上:
    此时从库已经收到并应用了该事务,但客户端仍会收到事务提交失败的信息,会重新提交请求到新的主上。

  简单来说就是,在MySQL5.5-5.6使用after_commit的模式,客户端事务在存储引擎层提交后,在得到从库的确认的过程中,主库宕机了。此时,主库在等待slave ACK的过程中,虽然没有返回结果给当前的客户端,但是实际事务时提交的,其他客户端会读取到当前的已提交事务,如果slave端还没有读到该事务的events,同时主库也开始了故障切换到了备库,那么之前读到的事务就会消失,也就是“幻读”。如果此时主库永远都无法启动那么这期间的事务便丢失了即数据丢失,这样的问题是MySQL不愿意看到的。
针对上述存在的问题,MySQL5.7引入了一种新的半同步方案,并且在5.7引入了一个新的参数,rpl_semi_sync_master_wait_point,这个参数有两种取值,1)AFTER_SYNC 2)AFTER_COMMIT 前者是新的半同步方案后者为老的半同步方案。

半同步复制的条件:

必要条件
1)MySQL5.5及以上版本
2)变量have_dynamic_loading 为YES(查看命令:show variables like "have_dynamic_loading";)
3)主从复制已经存在(即提前部署mysql主从复制环境,主从同步要配置基于整个数据库的,不要配置基于某个库的同步,即同步时不要过滤库)