Master-Slave(MS)架构高可用概述
MS架构高可用基础
高可用MySQL是依赖复制(Replication)技术实现的,复制解决的基本问题就是,让一台数据库服务器的数据同步到其它服务器上。MySQL数据库的复制有如下三个步骤。
- 在主库上把数据更改记录到二进制日志(Binary Log)中(这些记录被称为二进制日志事件)。
- 备库将主库上的日志复制到自己的中继日志(Relay Log)中。
- 备库读取中继日志中的事件(Event),将其回放到备库数据之上。
以上只是概述,实际上每一步都很复杂。
复制的主要目的是,保障数据库的可用性,和数据一致性。可用性是指,系统提供的服务一直处于可用状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。一致性是指,数据在多个节点之间是否能够保持一致的特性。在高可用数据库进行Failover时,数据一致性往往会受到比较大的挑战,而数据一致性又极其依赖复制技术本身,其属于数据库的硬核能力。我们的快乐,和不快乐有好大一部分来自数据一致性的问题。数据一致性使用RPO(Recovery Point Objective)来衡量,MySQL的复制也一直在追求着RPO=0的境界。
MS架构围绕着复制方式实现高可用,复制的痛点主要围绕着数据一致性。如果第一个节点的数据进行了更新操作并且更新成功后,却没有使得第二个节点上的数据得到相应的更新,于是在对第二个节点的数据进行读取操作时,获取的依然是老数据,这就是典型的数据不一致的问题。
在高可用数据库进行Failover时,可能数据还没有复制完毕,这样就出现了数据不一致的风险,反应在实际业务上可能是数据丢失了,或错乱了。MySQL在数据复制上进行了旷日持久的改进,由异步复制(Asynchronous Replication)到半同步复制(Semisynchronous Replication),再到增强半同步复制(Enhanced Semisynchronous Replication),几近使RPO趋于0,直至组复制(Group Replication)的出现。
异步复制
MySQL默认的复制就是异步复制,主库在执行完用户提交的事务后,将事务事件写入到Binlog文件中,这时主库只会通知Dump线程发送这些新的Binlog,然后主库就会继续处理用户的提交,而不会保证Binlog传送到任何一个备库上。
若主库发生Crash,其上已经提交的事务可能并没有传送到备库上,此时Failover,可能就会导致新主库上的数据不完整,出现了数据不一致性的问题。
半同步复制
半同步复制与异步复制不同的是,其在主库执行完用户提交的事务后,等待至少一个备库将接收到的Binlog写入Relay Log后,并返回给主库ACK,主库才会继续处理用户的提交。这里主库等待备库返回ACK的时间点,由参数rpl_semi_sync_master_wait_point=AFTER_COMMIT设置;等待几个备库返回ACK,由参数rpl_semi_sync_master_wait_for_slave_count=1设置。其中还有一个半同步超时的设置,由参数rpl_semi_sync_master_timeout=100控制,超时后半同步复制退化为异步复制。
半同步复制提高了数据的安全性,同时也会造成一定程度的延迟,该延迟至少是一个RTT(Round Trip Time)。
增强半同步复制
增强半同步复制
增强半同步复制与半同步复制的不同之处是,其等待备库返回ACK的时间点不同。在MySQL中一个Commit过程由三个步骤组成:第一,Prepare the transaction in the storage engine (InnoDB);第二,Write the transaction to the binary logs;第三,Complete the transaction in the storage engine。增强半同步复制等待备库ACK的时间点,由参数rpl_semi_sync_master_wait_point=AFTER_SYNC配置,是在Commit的第二,和第三步骤之间。不同于半同步复制等待备库ACK的时间点,是在Commit的第三步骤之后。试想对于增强半同步复制,在主库等待备库返回ACK时发生了Crash,由于该Commit还没最终结束,用户在主库上不会看到变更。当Failover后,用户在新主库上也不会看到变更,不存在数据不一致的问题。而对于半同步复制,由于该Commit已结束,用户在主库上会看到变更。当Failover后,用户在新主库上反而看不到变更,出现了数据不一致的情况。可见增强半同步复制,比半同步复制,在保证数据一致性上又前进了一步。
在增强半同步复制中,可以配置超时参数很大,如rpl_semi_sync_master_timeout=999999,这样主库在未收到备库ACK之前,用户的提交是被挂起的,这样更进一步保证了数据一致性,只是在可用性方面大打折扣了。
MGR
MySQL Group Replication(后简称MGR)的出现让大家眼前一亮,其建设性的以插件(Plugin)的方式添加到MySQL现有体系架构中,基于原生复制技术,使用了Binary Log,Row-based logging,和GTID等特性,使用了Paxos一致性协议的数据复制逻辑,保证了数据的一致性。
显示了MGR与普通MySQL复制模式的区别,在MGR中提交事务时,事务在引擎层完成Prepare,写Binlog之前会被MySQL预设的钩子(Hook)before_commit拦截,进入到MGR层,其将事务执行相关的信息打包,通过Paxos一致性协议(Consensus)进行全局排序后发送给MGR各个节点,当超过半数(N/2+1)的节点(包括它自己)回应后,发送消息告诉所有节点,这个数据包同步成功。各节点独自进行认证(Certify)。若认证通过,本地节点写Binlog完成提交。异地节点写Relay Log,由建立的复制通道(Replication Channel)group_replication_applier完成事务并行回放。若认证不通过,就会进行回滚(Rollback)。
但同样MGR也有一些缺点,在前面的文章中有对应描述