1.原理
增强半同步复制虽然解决了HA切换之后的幻读问题,也从一定程度上使得主从实例 之间的数据一致性保障得到增强,但是仍然还有很多问题需要解决。
例如:
HA切换程度需要依赖于MySQL服务器之外的第三方程序实现,维护十分繁琐, 当发生HA切换之后,原主库重新加入集群还需要处理其上的一些多余数据(在半同步复制下,主库的最后一个binlog事务或最后一个binlog队列中的事务可能从库并未收到(大概率),当原主库崩溃恢复之后,MySQL服务器会根据binlog中已经落盘的内容对这些事 务进行重新提交,而这些事务在新主库中并不存在,需要对这些事务进行回滚处理)。
无法很好地解决写节点多活问题,主从复制架构虽然可以通过搭建双主(两个实例互为主从)架构来实现在任意一个节点中的数据变更都可以同步到互为主从的节点中, 但是如果两个节点同时对一条数据做修改,将产生相互覆盖且结果不可预期的现象,无法做到有效的事务冲突检测 为了解决上述棘手的问题,组复制技术应运而生。
Oracle MySQL 官方基于主从复制 基础架构实现的组复制(MySQL Group Repliation,MGR,以下提到MGR都是指官方集群复制技术),是当下主流的集群复制架构之一,当然还有其他集群复制技术[例如: Percona Server分支基于第三方的Galera复制插件实现的集群复制技术 Percona Xtradb Cluster(PXC);
MariaDB 分支基于第三方的Galera复制插件实现的集群复制技术 MariaDB Galera Cluster(MGC),这里不展开介绍了,有兴趣的读者请自行研究]。 那么问题来了,MGR是如何解决上述两个棘手的问题的呢?首先,我们来看看MGR 的应用架构,如下图所示(该图来自Oracle MySQL 官方),至少需要3个节点(建议最多不要超过8个,因为节点越多写性能越差)。
为什么至少需要3个节点呢?因为实现集群复制技术的组复制插件是基于Paxos 协议实现的,而Paxos协议提供了一种仲裁机制,用于在写节点崩溃之后,通过集群内部节点之间的仲裁来决定是否需要剔除故障节点,并选举出新的写节点,类似于下图1所示(该图来自Oracle MySQL官方)。
当S1节点崩溃之后,在集群内部重新选举S2作为写节点, 发起写请求的客户端就可以继续对集群发起写请求了。整个写请求故障转移的过程都是在组复制插件内部自动完成的,无须人工干预(注意:这里的无须人工干预指的是数据库集群自身的可用性,而不是应用的写请求路由,应用的写请求发往哪个节点的路由还是需要依赖第三方路由插件或者使用智能DNS解析的)。
在单节点写模式下,故障自动转移示意图,如下图所示。
在多节点写模式下,自动故障转移示意图如下图所示。
通过上述功能MGR解决了故障自动转移的问题,那么多节点写的事务冲突是如何解决的呢?请见下图(该图来自Oracle MySQL官方)。
前面说过,MGR是基于主从复制基础架构实现的,主要是在事务提交的过程中嵌入单独的binlog封装逻辑,并通过专门的 group_replication_recovery复制通道进行数据传输,组复制插件使用Paxos协议的原子广播特性来保证集群内的大多数节点都能接收到数据包,当节点接收到write set(写集)之后,每个节点上的分布式状态机按照相同的规则对事务进行排序,并进行事务的冲突认证检测。
对于写节点(主节点)而言,当冲突认证检测通过之后,将数据变更写入自身的 binlog中,然后在存储引擎层进行提交(如果发现事务冲突,则进行事务回滚);对于读 节点(从节点)而言,当冲突认证检测通过之后,就把主库发送过来的binlog写入自身的 relay log中,然后SQL线程读取relay log进行重放,并把重放的binlog写入自身的binlog 中,接下来在存储引擎内部进行提交(如果发现事务冲突,则丢弃主库发送过来的binlog)。
2.配置示例
(1)写节点(主节点)
(2)读节点(从节点)