MySQL是通用的关系型数据库,一般情况下部署会采用主从模式,主从模式的主库负责数据写入,从库负责数据查询;

主从复制原理

20220308180543 MySQL在主从同步中,会使用三个线程:

  • Binary log dump thread: 当从节点连接到主节点时,主节点会新建一个线程发送binary log到从节点. 通过在主节点上运行show processlist可以看到当前所有运行在主节点上的Binlog dump线程。

    20220308180620

  • Replication I/O thread: 当在从节点上执行start slave时,从节点会创建一个I/O线程连接到主节点,请求主节点发送Binary logs. Replication I/O thread读取Binary log dump thread发送的数据并将其写入Relay Log;

    • 使用show slave status返回的Slave_IO_running表示Replication I/O thread的工作状态;
  • Replication SQL thread:从节点创建一个SQL Thread读取Relay log中的数据并执行;

值得注意的是, MySQL在5.6版本中提供slave_parallel_workers/replica_parallel_workersslave_parallel_type/replica_parallel_type参数在从节点进行并行复制.slave_parallel_type表示多线程复制过程中事务执行的规则(LOGICAL_CLOCK:安装时间戳;DATABASE:按照db)。

主从复制模式

复制模式 特点
Row 准确复制行数据,但是会增加二进制文件大小,无法判断哪些sql占用的带宽大
statement 实现简单,日志紧凑,但是一些sql可能服务被正确复制,例如now
Mixed

主从复制方案

MySQL中存在3种不同的主从复制方案。

异步复制(Asynchronous Replication)

异步复制的原理图如下: 20220308180924 异步复制是MySQL集群默认的主从同步方式,Master节点将事务写入binlog后立即提交事务,并将新写入的binlog事务日志异步传送给slave节点,并不会等待传输的结果。 异步复制的优势有:

  • write、update和delete操作均需要在主库上操作,读可以在任意在任意从节点操作,通过增加salve的个数可以显著增加集群读性能;
  • 异步复制机制可以保证从节点的状态不会影响主节点和其他从节点的状态,通过从节点备份数据也不会对整个集群产生影响; 异步复制的主要问题是:
  • 因网络延迟等原因无法保证Slave节点的数据是最新的,如果主节点故障,切主到从节点,可能存在数据丢失等事务一致性问题。

增强半同步复制(Semisynchronous Replication)

与异步复制相对的是半同步复制,原理图如下: 20220308181015

半同步复制是MySQL对异步复制的一个改进版本(配置项rpl_semi_sync_master_wait_point=AFTER_SYNC),半同步复制在主节点将事务写入到binlog后立即提交事务(不立即返回ACK到客户端),然后将新写入的binlog事务日志传送到从节点,并等待从节点返回传送的结果;从节点收到binlog事务后,将其写入relay log并flush到磁盘中,然后向主节点返回ACK;主节点收到(任意rpl_semi_sync_master_wait_for_slave_count个,rpl_semi_sync_master_wait_for_slave_count可配置,默认为1)从节点的ACK后,返回ACK到客户端; rpl_semi_sync_master_wait_point有两个取值:

  1. AFTER_SYNC: 主节点将每个事务写到binary log并flush到磁盘中,也将其发送到从节点.然后主节点等待从节点回复ACK,拿到ACK后主节点commit事务到存储引擎并返回结果;

  2. AFTER_COMMIT: 与AFTER_SYNC不同,AFTER_COMMIT先commit到存储引擎再等待ACK;由于主提交后客户端是能够看到已经提交的数据的,如果此时主宕机,切主完成后,之前commit的内容在新主无法查到,会造成幻读; 半同步复制只能保证如果主节点挂掉,所有已经提交的事务至少会提交到一个从节点上;

半同步复制的主要问题是:

  • 主节点如果在等待从节点的ACK的时候超时了,就会自动提交事务,并返回ACK到客户端,此时半同步复制就退化为异步复制;
  • 网络会影响同步性能;

MySQL 5.7为了解决MySQL 5.6半同步复制的缺陷,新增了增强半同步复制(配置项rpl_semi_sync_master_wait_point=AFTER_COMMIT)。增强半同步复制在主节点将事务写入到binlog不提交事务,将新写入的binlog事务日志传送到从节点,并等待从节点返回传送的结果;从节点收到binlog事务后,将其写入relay log并flush到磁盘中,然后向主节点返回ACK;主节点收到(任意rpl_semi_sync_master_wait_for_slave_count 个)从节点的ACK后提交事务并返回ACK到客户端; 增强半同步复制的主要问题是:

  • 当Master节点故障后切主到Slave节点,原先的Master节点恢复后不能作为Slave节点直接加入集群,否则可能存在主从事务不一致的问题(事务还未commit,但是binlog已经写入,当故障恢复);
  • MySQL存在一个柔性机制,Slave节点响应时间太长或者不响应会大大降低Master节点的吞吐量,在Slave节点长时间未响应时增强半同步复制会退化成异步复制。

组复制(Group Replication)

20220308181139 组复制是一种可用于实现容错(fault-tolerant)系统的技术. 复制组中的每个节点都保存有全量数据并通过消息与其他节点进行信息同步. 通信层使用一系列共识技术(原子消息,有序消息)来保证数据一致性. MySQL组复制中的节点可以独立执行事务, 但是读写事务必须得到复制组的ACK才能提交, 因此事务提交不是仅仅取决于当前服务器. 仅读的事务可以不需要复制组的确认即可立即提交.

当读写事务准备提交时, 提交事务的节点会自动广播(原子性的广播,Atomic broadcast)需要修改的行和内容, 其他节点只会存在两种状态:要不所有节点都收到了事务,要不所有节点都没有收到事务. 如果其他节点接收到了事务提交, 表明所有节点都是按照相同的顺序收到了事务, 因此事务也就按照全局一致性顺序执行.

Atomic broadcast: 在分布式系统中, atomic broadcast(total order broadcast)是多个进程正确按照相同顺序接收处理相同的一组消息的广播. 原子性表征为要不全部正确处理, 要不全部失败且无其他影响.

但是如果两个冲突的事务在不同节点上并发执行, 如果不采取其他措施必然会导致数据不一致. MySQL组复制通过certification进程来处理事务冲突. certification是行级别的: 如果不同节点上的并发事务更新了相同的列, 说明这两个事务是冲突的, 需要解决冲突. 解决冲突的方法是: 按照时间顺序, 先被其他节点接受的事务被认为是合法的, 后被其他节点接收的事务需要其他节点进行回滚. 需要注意的是, 如果需要执行DDL(Data Definition Language), 则需要保证在相同的节点上执行, 否则会导致数据不一致

MySQL DDL不具有原子性, 并且不是一个事务, 所以组复制模式中节点会不经过组复制安全协议直接执行并且提交修改.

如果一个新的节点准备加入复制组,需要进行如下操作:

  1. 选择一个正常的节点作为donor, 并通过Replication Channels复制所有缺失的数据, 与此同时也缓存group中的事务;
  2. 执行步骤1中缓存的事务, 当缓存的事务的数量为0时, 该节点变成Online状态并开始成为复制组的一个子节点;

MySQL组复制是最终一致性系统, 组复制允许节点在不违反数据一致性和有效性的前提下不按照顺序执行事务.

方案对比

20220308181213

其他

组提交-两阶段提交

  1. prepare阶段:写redolog,不包含commit日志
  2. commit阶段: a. 写binlog:先将binlog写到文件系统,然后调用fsync将文件写入到磁盘; b. 完成事务提交:在redolog中为事务添加commit标签 20220308181324
  • 如果是写完redolog,mysql 宕机,因为没有写binlog,则事务会回滚,从库也不会读取到binlog;
  • 如果是写完binlog,mysql宕机,因为redo已经写入,重新恢复后事务会commit,从库也会读取到binlog;