MySQL 中常见的几种高可用架构部署方案

MySQL Replication

MySQL Replication 是官方提供的主从同步方案,用于将一个 MySQL 的实例同步到另一个实例中。Replication 为保证数据安全做了重要的保证,是目前运用最广的 MySQL 容灾方案。Replication 用两个或以上的实例搭建了 MySQL 主从复制集群,提供单点写入,多点读取的服务,实现了读的 scale out

上面的栗子,一个主库(M),三个从库(S),通过 replication,Master 生成 event 的 binlog,然后发给 slave,Slave 将 event 写入 relaylog,然后将其提交到自身数据库中,实现主从数据同步。

对于数据库之上的业务层来说,基于 MySQL 的主从复制集群,单点写入 Master ,在 event 同步到 Slave 后,读逻辑可以从任何一个 Slave 读取数据,以读写分离的方式,大大降低 Master 的运行负载,同时提升了 Slave 的资源利用。

优点:

1、通过读写分离实现横向扩展的能力,写入和更新操作在源服务器上进行,从服务器中进行数据的读取操作,通过增大从服务器的个数,能够极大的增强数据库的读取能力;

2、数据安全,因为副本可以暂停复制过程,所以可以在副本上运行备份服务而不会破坏相应的源数据;

3、方便进行数据分析,可以在写库中创建实时数据,数据的分析操作在从库中进行,不会影响到源数据库的性能;

实现原理

在主从复制中,从库利用主库上的 binlog 进行重播,实现主从同步,复制的过程中蛀主要使用到了 dump thread,I/O thread,sql thread 这三个线程。

IO thread: 在从库执行 start slave 语句时创建,负责连接主库,请求 binlog,接收 binlog 并写入 relay-log;

dump thread:用于主库同步 binlog 给从库,负责响应从 IO thread 的请求。主库会给每个从库的连接创建一个 dump thread,然后同步 binlog 给从库;

sql thread:读取 relay log 执行命令实现从库数据的更新。

来看下复制的流程:

1、主库收到更新命令,执行更新操作,生成 binlog;

2、从库在主从之间建立长连接;

3、主库 dump_thread 从本地读取 binlog 传送刚给从库;

4、从库从主库获取到 binlog 后存储到本地,成为 relay log(中继日志);

5、sql_thread 线程读取 relay log 解析、执行命令更新数据。

不过 MySQL Replication 有个严重的缺点就是主从同步延迟。

因为数据是进行主从同步的,那么就会遇到主从同步延迟的情况。

为什么会出现主从延迟?

1、从库机器的性能比主库差;

2、从库的压力大;

  • 大量查询放在从库上,可能会导致从库上耗费了大量的 CPU 资源,进而影响了同步速度,造成主从延迟。

3、大事务的执行;

  • 有事务产生的时候,主库必须要等待事务完成之后才能写入到 binlog,假定执行的事务是一个非常大的数据插入,这些数据传输到从库,从库同步这些数据也需要一定的时间,就会导致从节点出现数据延迟。

4、从库的复制能力较差;

如果从库的复制能力,低于主库,那么在主库写入压力很大的情况下,就会造成从库长时间数据延迟的情况出现。

如何解决?

1、优化业务逻辑,避免出现多线程大事务的并发场景;

2、提高从库的机器性能,减少主库写 binlog 和从库读 binlog 的效率差;

3、保证主库和从库的网络连接,避免出现网络延迟导致的 binlog 传输延迟;

4、强行读主库;

5、配合 semi-sync 半同步复制;

semi-sync 半同步复制

MySQL 有三种同步模式,分别是:

1、异步复制:MySQL 中默认的复制是异步的,主库在执行完客户端提交的事务后会立即将结果返回给客户端,并不关心从库是否已经接收并且处理。存在问题就是,如果主库的日志没有及时同步到从库,然后主库宕机了,这时候执行故障转移,在从库冲选主,可能会存在选出的主库中数据不完整;

2、全同步复制:指当主库执行完一个事务,并且等到所有从库也执行完成这个事务的时候,主库在提交事务,并且返回数据给客户端。因为要等待所有从库都同步到主库中的数据才返回数据,所以能够保证主从数据的一致性,但是数据库的性能必然受到影响;

3、半同步复制:是介于全同步和全异步同步的一种,主库至少需要等待一个从库接收并写入到 Relay Log 文件即可,主库不需要等待所有从库给主库返回 ACK。主库收到 ACK ,标识这个事务完成,返回数据给客户端。

MySQL 中默认的复制是异步的,所以主库和从库的同步会存在一定的延迟,更重要的是异步复制还可能引起数据的丢失。全同步复制的性能又太差了,所以从 MySQL 5.5 开始,MySQL 以插件的形式支持 semi-sync 半同步复制。

半同步复制潜在的问题

在传统的半同步复制中,主库写数据到 binlog,并且执行 commit 提交事务后,会一直等待一个从库的 ACK。从库会在写入 Relay Log 后,将数据落盘,然后回复给主库 ACK,主库收到这个 ACK 才能给客户端事务完成的确认。

这样会存在问题就是,主库已经将该事务的 commit 存储到了引擎层,应用已经可以看到数据的变化了,只是在等待从库的返回,如果此时主库宕机,可能从库还没有写入 Relay Log,就会发生主从库数据不一致。

为了解决这个问题,MySQL 5.7 引入了增强半同步复制。主库写入数据到 binlog 后,就开始等待从库的应答 ACK,直到至少一个从库写入 Relay Log 后,并将数据落盘,然后返回给主库 ACK,通知主库可以进行 commit 操作,然后主库再将事务提交到事务引擎,应用此时才能看到数据的变化。

不过看下来增强半同步复制,在同步给从库之后,因为自己的数据还没有提交,然后宕机了,主库中也是会存在数据的丢失,不过应该想到的是,这时候主库宕机了,是会重新在从库中选主的,这样新选出的主库数据是没有发生丢失的。

MySQL Group Replication

MySQL Group Replication 组复制,又称为 MGR。是 Oracle MySQL 于 2016 年 12 月发布 MySQL 5.7.17 推出的一个全新高可用和高扩展的解决方案。

引入复制组主要是为了解决传统异步复制和半同步复制可能产生数据不一致的问题。

MGR 由若干个节点共同组成一个复制组,一个事务的提交,必须经过组内大多数节点 (N / 2 + 1) 决议并通过,才能得以提交。

当客户端发起一个更新事务时,该事务先在本地执行,执行完成之后就要发起对事务的提交操作。在还没有真正提交之前,需要将产生的复制写集广播出去,复制到其它成员。因为事务是通过原子广播发送的,所以组中的成员要么都接收事务,要么都不接收事务。如果组中的所有成员收到了该广播消息(事务),那么他们会按照之前发送事务的相同顺序收到该广播消息。因此,所有组成员都以相同的顺序接收事务的写集,并为事务建立全局顺序。因此,所有组成员都以相同的顺序接收事务的写集,并为事务建立全局顺序。

在不同组成员并发执行的事务可能存在冲突。冲突是通过检查和比较两个不同并发事务的 write set 来验证的,这个过程称为认证。在认证期间,冲突检测在行级别执行的:如果在不同组成员上执行的两个并发事务更新了同一行数据,则存在冲突。根据冲突认证检测机制判断,按照顺序,第一次提交的会正常执行,第二次提交的事务会在事务发起的原始组成员上执行回滚,,组中的其他成员对该事务执行删除。如果两个事务经常发生冲突,那么最好将这两个事务放在同一个组成员中执行,这样它们在本地锁管理器的协调下将都有机会提交成功,而不至于因为处在两个不同的组成员中由于冲突认证而导致其中一个事务被频繁回滚。

最终,所有组内成员以相同的顺序接收同一组事务。因此组内成员以相同的顺序应用相同的修改,保证组内数据强一致性。

有下面的几种特性:

1、避免脑裂:MGR 中不会出现脑裂的现象;

2、数据一致性保障:MGR 的冗余能力很好,能够保证 Binlog Event 至少被复制到超过一半的成员上,只要同时宕机的成员不超过半数便不会导致数据丢失。MGR还保证只要 Binlog Event 没有被传输到半数以上的成员,本地成员不会将事务的 Binlog Event 写入 Binlog 文件和提交事务,从而保证宕机的服务器上不会有组内在线成员上不存在的数据。因此,宕机的服务器重启后,不再需要特殊的处理就可以加入组;

3、多节点写入支持:多写模式下支持集群中的所有节点都可以写入。

组复制的应用场景

1、弹性复制:需要非常灵活的复制基础设施的环境,其中MySQL Server的数量必须动态增加或减少,并且在增加或减少Server的过程中,对业务的副作用尽可能少。例如,云数据库服务;

2、高可用分片:分片是实现写扩展的一种流行方法。基于 组复制 实现的高可用分片,其中每个分片都会映射到一个复制组上(逻辑上需要一一对应,但在物理上,一个复制组可以承载多个分片);

3、替代主从复制:在某些情况下,使用一个主库会造成单点争用。在某些情况下,向整个组内的多个成员同时写入数据,对应用来说可能伸缩性更强;

4、自治系统:可以利用组复制内置的自动故障转移、数据在不同组成员之间的原子广播和最终数据一致性的特性来实现一些运维自动化。

InnoDB Cluster

InnoDB Cluster 是官方提供的高可用方案,是 MySQL 的一种高可用性(HA)解决方案,它通过使用 MySQL Group Replication 来实现数据的自动复制和高可用性,InnoDB Cluster 通常包含下面三个关键组件:

1、MySQL Shell: 它是 MySQL 的高级管理客户端;

2、MySQL Server 和 MGR,使得一组 MySQL 实例能够提供高可用性,对于 MGR,Innodb Cluster 提供了一种更加易于编程的方式来处理 MGR;

3、MySQL Router,一种轻量级中间件,主要进行路由请求,将客户端发送过来的请求路由到不同的 MySQL 服务器节点。

MySQL Server 基于 MySQL Group Replication 构建,提供自动成员管理,容错,自动故障转移动能等。InnoDB Cluster 通常以单主模式运行,一个读写实例和多个只读实例。不过也可以选用多主模式。

优点:

1、高可用性:通过 MySQL Group ReplicationInnoDB Cluster 能够实现数据在集群中的自动复制,从而保证数据的可用性;

2、简单易用:InnoDB Cluster 提供了一个简单易用的管理界面,使得管理员可以快速部署和管理集群;

3、全自动故障转移: InnoDB Cluster 能够自动检测和诊断故障,并进行必要的故障转移,使得数据可以继续可用。

缺点:

1、复杂性:InnoDB Cluster 的部署和管理比较复杂,需要对 MySQL 的工作原理有一定的了解;

2、性能影响:由于自动复制和高可用性的要求,InnoDB Cluster 可能对 MySQL 的性能造成一定的影响;

3、限制:InnoDB Cluster 的功能对于一些特殊的应用场景可能不够灵活,需要更多的定制。

InnoDB ClusterSet

MySQL InnoDB ClusterSet 通过将主 InnoDB Cluster 与其在备用位置(例如不同数据中心)的一个或多个副本链接起来,为 InnoDB Cluster 部署提供容灾能力。

InnoDB ClusterSet 使用专用的 ClusterSet 复制通道自动管理从主集群到副本集群的复制。如果主集群由于数据中心损坏或网络连接丢失而变得无法使用,用户可以激活副本集群以恢复服务的可用性。

InnoDB ClusterSet 的特点:

1、主集群和副本集群之间的紧急故障转移可以由管理员通过 MySQL Shell,使用 AdminAPI 进行操作;

2、InnoDB ClusterSet 部署中可以拥有的副本集群的数量没有定义的限制;

3、异步复制通道将事务从主集群复制到副本集群。clusterset_replication 在 InnoDB ClusterSet 创建过程中,在每个集群上都设置了名为 ClusterSet 的复制通道,当集群是副本时,它使用该通道从主集群复制事务。底层组复制技术管理通道并确保复制始终在主集群的主服务器(作为发送方)和副本集群的主服务器(作为接收方)之间进行;

4、每个 InnoDB ClusterSet 集群,只有主集群能够接收写请求,大多数的读请求流量也会被路由到主集群,不过也可以指定读请求到其他的集群;

InnoDB ClusterSet 的限制:

1、InnoDB ClusterSet 只支持异步复制,不能使用半同步复制,无法避免异步复制的缺陷:数据延迟、数据一致性等;

2、InnoDB ClusterSet 仅支持Cluster实例的单主模式,不支持多主模式。 即只能包含一个读写主集群, 所有副本集群都是只读的, 不允许具有多个主集群的双活设置,因为在集群发生故障时无法保证数据一致性;

3、已有的 InnoDB Cluster 不能用作 InnoDB ClusterSet 部署中的副本集群。副本集群必须从单个服务器实例启动,作为新的 InnoDB 集群;

4、只支持 MySQL 8.0。

InnoDB ReplicaSet

InnoDB ReplicaSet 是 MySQL 团队在 2020 年推出的一款产品,用来帮助用户快速部署和管理主从复制,在数据库层仍然使用的是主从复制技术。

InnoDB ReplicaSet由单个主节点和多个辅助节点(传统上称为 MySQL 复制源和副本)组成。

InnoDB cluster 类似, MySQL Router 支持针对 InnoDB ReplicaSet 的引导, 这意味着可以自动配置 MySQL Router 以使用 InnoDB ReplicaSet, 而无需手动配置文件. 这使得 InnoDB ReplicaSet 成为一种快速简便的方法, 可以启动和运行 MySQL 复制和 MySQL Router, 非常适合扩展读取, 并在不需要 InnoDB 集群提供高可用性的用例中提供手动故障转移功能。

InnoDB ReplicaSet 的限制:

1、没有自动故障转移,在主节点不可用的情况下,需要使用 AdminAPI 手动触发故障转移,然后才能再次进行任何更改。但是,辅助实例仍可用于读取;

2、由于意外停止或不可用,无法防止部分数据丢失:在意外停止时未完成的事务可能会丢失;

3、在意外退出或不可用后无法防止不一致。如果手动故障转移提升了一个辅助实例,而前一个主实例仍然可用,例如,由于网络分区,裂脑情况可能会导致数据不一致;

4、InnoDB ReplicaSet 不支持多主模式。允许写入所有成员的经典复制拓扑无法保证数据一致性;

5、读取横向扩展是有限的。InnoDB ReplicaSet 基于异步复制,因此无法像 Group Replication 那样调整流量控制;

6、一个 ReplicaSet 最多由一个主实例组成。支持一个或多个辅助。尽管可以添加到 ReplicaSet 的辅助节点的数量没有限制,但是连接到 ReplicaSet 的每个 MySQL Router 都必须监视每个实例。因此,一个 ReplicaSet 中加入的实例越多,监控就越多。

使用 InnoDB ReplicaSets 的主要原因是你有更好的写性能。使用 InnoDB ReplicaSets 的另一个原因是它们允许在不稳定或慢速网络上部署,而 InnoDB Cluster 则不允许。