MySQL:主从数据库同步是怎么实现的

如何配置MySQL的主从同步

当客户端提交一个事务到MySQL的集群后,直到客户端收到集群返回成功响应,这个过程种,MySQL集群需要执行很多操作:

  • 主库提交事务、更新存储引擎中的数据 、把binlog写到磁盘上、给客户端返回响应、把binlog复制到所有从库上
  • 每个从库把复制过来的binlog写到暂存日志中,回放这个binlog、更新存储引擎中的数据、给主库返回复制成功的响应

这些操作的时序非常重要,这里面的“时序”,说的就是这些操作的先后循环。同样的操作,因为时序不同,对应用程序来说,有很大的差异。比如,如果先复制binlog,等binlog复制到从节点上之后,主节点再去提交事务,这种情况下,从节点的binlog一直和主节点是同步的,任何情况下主节点宕机也不会丢数据。但是如果把这个时序倒过来,先提交事务再复制binlog,性能就会非常好,但是存在丢失数据的风险。

MySQL提供了几个参数来配置这个时序,我们先来看一下默认情况下的时序是怎么样的。

  • 默认情况下,MySQL采用了异步复制的方式,执行事务操作的线程不会等复制binlog的线程。
  • MySQL主库收到客户端提交事务的请求之后,会先写入binlog,然后再提交事务,更新存储引擎中的数据,事务提交完成后,给客户端返回操作成功的响应。
  • 同时,从库会有一个专门的复制线程,从主库接收binlog,然后把binlog写到一个中继日志里面,再给主库返回复制成功的响应
  • 从库还另外有一个回访binlog的线程,去读中继日志,然后回放binlog更新存储引擎中的数据,这个过程和主从复制关系不太,所以没有在下图中画出来。

提交事务和复制这两个流程在不同的线程中执行,互相不会等待,这是异步复制。异步复制没有办法保证数据能够第一时间复制到从库上

在这里插入图片描述
与异步相对的是同步复制。同步复制的时序和异步复制基本是一样的,唯一的区别是,什么时候给客户端返回响应。

  • 异步复制时,主库提交事务之后,就会给客户端返回响应;
  • 而同步复制时,主库在提交事务的时候,会等待数据复制到所有从库之后,再给客户端返回响应。

同步复制这种方式在实际项目中,基本没法用,原因有两个:

  • 一个是性能很差,因为要复制到所有节点才返回响应;
  • 二是可用性也很差,主库和所有从库任何一个数据库出问题,都会影响业务。

为了解决这个问题,MySQL从5.7版本开始,增加了一种半同步复制。异步复制是事务线程完全不等复制响应;同步复制是事务线程要等待所有的复制响应;半同步复制介于两者之间,事务线程不用等所有的复制成功响应,只要一部分复制响应回来之后,就可以给客户端返回了

比如说,一主二从的集群,配置成半同步复制,只要数据成功复制到任意一个从库上,主库的事务线程就直接返回了。这种半同步复制的方式,它兼顾了异步复制和同步复制的优点:

  • 如果主库宕机,至少还有一个从库有最新的数据,不存在丢数据的风险;
  • 而且性能也可以,也能够提供高可用,从库宕机不会影响主库提供服务。

那,实际应用中,选择半同步是需要注意哪些问题呢?

  • 配置半同步复制的时候,有一个重要的参数“rpl_semi_sync_master_wait_no_slave”,含义是:“至少等待数据复制到几个从节点再返回”。
    • 这个数量配置的越大,丢数据的风险越小,但是集群的性能和可用性就越差。最大可以配置成和从节点的数量一样,这样就变成了同步复制。
    • 一般情况下,配成默认值 1 也就够了,这样性能损失最小,可用性也很高,只要还有一个从库活着,就不影响主库读写。丢数据的风险也不大,只有在恰好主库和那个有最新数据的从库一起坏掉的情况下,才有可能丢数据。
  • 另外一个重要的参数是“rpl_semi_sync_master_wait_point”,这个参数控制主库执行事务的线程,是在提交事务之前(AFTER_SYNC)等待复制,还是在提交事务之后(AFTER_COMMIT)等待复制。
    • 默认是AFTER_SYNC,也就是先等待复制,再提交事务,这样完全不会丢数据。
    • AFTER_COMMIT具有更好的性能,不会长时间锁表,但还是存在宕机丢数据的风险。

另外,虽然我们配置了同步或者半同步复制,并且要等待复制成功后再提交事务,还是有一种特别容易被忽略、可能存在丢数据风险的情况:

  • 如果主库提交事务的线程等待复制的时间超时了,这种情况下事务仍然会被正常提交。
  • 但是,MySQL会自动降级为异步复制模式,直到有足够多(rpl_semi_sync_master_wait_no_slave)的从库追上主库,才能恢复成半同步复制。
  • 如果这个期间主库宕机,仍然存在丢数据的风险

复制状态机:所有分布式存储都是这么复制数据的

在MySQL中,无论是复制还是备份恢复,依赖的都是全量备份和binlog:

  • 全量备份相当于备份那一时刻的一个数据快照
  • binlog则记录了每次数据更详细的变化。

这种基于“快照 + 操作日志”的方法,不是 MySQL 特有的。比如说,redis cluster中,它的全量备份称为snapshot,操作日志叫做backlog,它的主从复制方式几乎和MySQL是一模一样的。

小结

几乎所有的存储系统和数据库,都是用这一套方法来解决备份恢复和数据复制问题的。这一套方法其实是有理论基础的,叫做复制状态机 (Replication State Machine)

也就是说,任何一个存储系统,无论它存储的是什么数据,用什么样的数据结构,都可以抽象成一个状态机

  • 存储系统中的数据叫做状态(也就是MySQL中的数据)
  • 状态的全量备份叫做快照(snapshot),就像给数据拍个照片一样
  • 按照顺序记录更新存储系统中每条操作命令,也就是操作日志(commit log,也就是Mysql中的binlog)

在这里插入图片描述
复制数据的时候,只要基于一个快照,按照顺序执行快照之后的所有操作日志,就可以得到一个完全一样的状态。在从节点持续的从主节点上复制操作日志并执行,就可以让从节点上的状态数据和主节点保持同步。

主从同步做数据复制时,一般可以采用几种复制策略。性能最好的是异步复制,主节点上先记录操作日志,再更新状态数据,然后异步把操作日志复制到所有从节点上,并在从节点执行操作日志,得到和主节点相同的状态数据。

异步复制的缺点是可能存在主从延迟,如果主节点宕机,可能会丢数据。另外一种常用的策略是半同步复制,主节点等到操作日志最少成功复制到N个从节点之后,再更新状态,这种方式再性能、高可用和数据可靠性几个方面都比较平衡,很多分布式存储系统默认使用这种方式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值