Mysql MGR解析
为了创建高可用数据库系统,传统的实现方式是创建一个或多个备用的数据库实例,原有的数据库实例通常称为主库(master),其它备用的数据库实例称为备机或从库(slave)。当master发生故障无法正常工作时,slave就会接替其工作,保证整个数据库系统不会对外中断服务。
一、MySQL的传统主从复制机制
MySQL传统的高可用解决方案是通过binlog复制来搭建主从或一主多从的数据库集群。主从之间的复制模式支持异步模式(async replication)和半同步模式(semi-sync replication)。无论哪种模式下,都是主库master提供读写事务的能力,而slave只能提供只读事务的能力。在master上执行的更新事务通过binlog复制的方式传送给slave,slave收到后将事务先写入relay log,然后重放事务,即在slave上重新执行一次事务,从而达到主从事务一致的效果。
上图是异步复制(Async replication)的示意图,在master将事务写入binlog后,将新写入的binlog事务日志传送给slave节点,但并不等待传送的结果,就会在存储引擎中提交事务。
基于异步复制的高可用方案存在主从不一致乃至丢失事务的风险,原因在于当master将事务写入binlog,然后复制给slave后并不等待slave回复即进行提交,若slave因网络延迟或其它问题尚未收到binlog日志,而此时master故障,应用切换到slave时,本来在master上已经提交的事务就会丢失,因其尚未传送到slave,从而导致主从之间事务不一致。
上图是半同步复制(Semi-sync replication)的示意图,在master将事务写入binlog后,将新写入的binlog事务日志传送给slave节点,但需要等待slave返回传送的结果;slave收到binlog事务后,将其写入relay log中,然后向master返回传送成功ACK;master收到ACK后,再在存储引擎中提交事务。 MySQL基于两种复制模式都可以搭建高可用数据库集群,也能满足大部分高可用系统的要求,但在对事务一致性要求很高的系统中,还是存在一些不足,主要的不足就是主从之间的事务不能保证时刻完全一致。
基于semi-sync复制的高可用方案也存在主备不一致的风险,原因在于当master将事务写入binlog,尚未传送给slave时master故障,此时应用切换到slave,虽然此时slave的事务与master故障前是一致的,但当主机恢复后,因最后的事务已经写入到binlog,所以在master上会恢复成已提交状态,从而导致主从之间的事务不一致。
二、MySQL Group Replication(MGR)
为了应对事务一致性要求很高的系统对高可用数据库系统的要求,并且增强高可用集群的自我管理能力,避免节点故障后的failover需要人工干预或其它辅助工具干预,MySQL 5.7引入了Group Replication高可用集群框架,用于搭建更高事务一致性的高可用数据库集群系统。基于Group Replication搭建的系统,不仅可以自动进行failover,而且同时保证系统中多个节点之间的事务一致性,避免因节点故障或网络问题而导致的节点间事务不一致。此外还提供了节点管理的能力,真正将整个集群作为一个整体对外提供服务。
1. 实现原理
Group Replication由至少3个或更多个节点共同组成一个数据库集群,事务的提交必须经过半数以上节点同意方可提交,在集群中每个节点上都维护一个数据库状态机,保证节点间事务的一致性。Group Replication基于分布式一致性算法Paxos实现,允许部分节点故障,只要保证半数以上节点存活,就不影响对外提供数据库服务,是一个真正可用的高可用数据库集群技术。Group Replication支持两种模式,单主模式和多主模式。在同一个group内,不允许两种模式同时存在,并且若要切换到不同模式,必须修改配置后重新启动集群。在单主模式下,只有一个节点可以对外提供读写事务的服务,而其它所有节点只能提供只读事务的服务,这也是官方推荐的Group Replication复制模式。
2. 复制模式
(1)单主模式
在此模式下,该组包含具有读写能力的单主服务器,组中的所有其他成员都设置为只读模式(超级只读模式super_read_only),所有其他加入的节点自动识别主节点并设置自己为只读。单主模式选主过程如下图所示:
在单主机模式下,将禁用在多主机模式下部署的某些检查,因为系统会强制每次只有一个写入节点。例如,允许对具有级联外键的表进行更改,而在多主模式下不允许。在主节点故障或者主机点从组中删除时,自动选举机制选择下一个主节点。通过按字典顺序(使用其UUID)排序并选择列表中的第一个节点作为下一个主节点,可通过group_replication_member_weight此参数影响选主。一旦选择了新的主节点,其他节点将设置为从节点,从节点为只读。
(2)多主模式
在多主模式下,没有单个主模式的概念,也没有选举程序,因为没有节点发挥任何特殊的作用。加入组时,所有服务器都设置为读写模式。在多主模式下部署时,将检查语句以确保他们与模式兼容,以多主模式部署组复制时进行以下检查:
a. 如果一个事务在SERIALIZABLE隔离级别下执行,那么当它自己与该组同步时,它的提交失败。
b. 如果事务针对具有级联约束的外键的表执行,则在与组自身同步时,事务无法提交。
这些检查可以通过设置选项来禁用。多住模式客户端故障转移如下图所式。
3. 具体实现
MySQL Group Replication是建立在已有MySQL复制框架的基础之上,通过新增Group Replication Protocol协议及Paxos协议实现,形成的整体高可用解决方案。与原有复制方式相比,主要增加了certify的概念,如下图所示,certify模块主要负责检查事务是否允许提交,是否与其它事务存在冲突,如两个事务可能修改同一行数据。在单机系统中,两个事务的冲突可以通过封锁来避免,但在多主模式下,不同节点间没有分布式锁,所以无法使用封锁来避免。为提高性能,Group Replication乐观地来对待不同事务间的冲突,乐观的认为多数事务在执行时是没有并发冲突的。事务分别在不同节点上执行,直到准备提交时才去判断事务之间是否存在冲突。
MySQL Group Replication是建立在基于Paxos的XCOM之上的,正因为有了XCOM基础设施,保证数据库状态机在节点间的事务一致性,才能在理论和实践中保证数据库系统在不同节点间的事务一致性。MySQL Group Replication对于通讯基础设施还有一些更高的要求,最终选择自研的XCOM,包括以下特性:
闭环(closed group):只有组内成员才能给组成员发送消息,不接受组外成员的消息。
消息全局有序(total order):所有XCOM传递的消息是全局有序(在多主集群中或是偏序),这是构建MySQL一致性状态机的基础。
消息的安全送达(Safe Delivery):发送的消息必须传送给所有非故障节点,必须在多数节点确认收到后方可通知上层应用。
视图同步(View Synchrony):在成员视图变化之前,每个节点都以相同的顺序传递消息,这保证在节点恢复时有一个同步点。实际上,组复制并不强制要求消息传递必须在同一个节点视图中。
(1)XCOM消息传递机制
XCOM是一个基于paxos协议的分布式同步组件,Group Replication通过它将一个节点上的事务(事务采用binlog来表示),传递到整个分布式系统中的多数节点,保证所有节点最终都会收到此事务,并且不改变事务的执行顺序。Server在事务提交之前,将事务的binlog打包,并添加此事务执行过程中产生的writeset及基于group replication的全局GTID。然后将其发送给本机的XCOM线程。XCOM组件内部有一个任务Task线程,主线程通过Task调度队列来调度执行Task,重要的Task有:
tcp_server 监听xcom端口,当有新连接时为其创建acceptor_learner_task任务
tcp_reaper_task 关闭长时间未使用的连接
acceptor_learner_task 此任务是XCOM的核心任务,实现基于paxos协议的消息流转过程,并最终决定accept还是deny此消息。
proposer_task 从server的消息请求队列中读取一条消息,封装为paxos的proposal消息,发送给其它节点,尝试此消息被paxos系统accept。每个节点可以有多个proposer_task,XCOM并不保证多个proposer_task以server发出同步消息的顺序来发送proposal消息。当一个消息被accepted后,通过learn消息通知到每个节点,成为learned消息。
executor_task 监听learned消息,若此消息尚未被应用,则通知server应用此消息。
detector_task 周期性的检测与其它节点间的连接可用性。若有连接不可用,通知server。
alive_task 产生心跳消息。
消息被acceptor的过程,如下图所示:
a. 源节点的proposal_task从server的消息队列中提取一个消息,若是3phase,封装为prepare消息,开始acceptor的阶段一,将prepare消息发送给的所有acceptor节点;若是2phase,则封装为proposal消息,将proposal消息发送给所有acceptor节点,此时会跳到阶段二;
b. acceptor节点的acceptor_learner_task收到prepare消息后,判断是否可以阶段一的accept,然后返回ACK;
c. 源节点的acceptor_learner_task收到ACK后,更新收到ACK的节点位图,若已经收到多数acceptor的ACK后,进入阶段二,向所有acceptor节点发送proposal消息;
d. acceptor节点的acceptor_learner_task收到proposal消息后,判断是否可以阶段二的accept,然后返回ACK;
e. 源节点的acceptor_learner_task收到ACK后,更新收到ACK的节点位图,若已经收到多数acceptor的ACK后,说明此消息已经被paxos系统accept,然后将此消息通知所有节点,向所有节点发出learn消息;
f. 所有节点的acceptor_learner_task收到learn消息后,将此消息加入到当前节点的learned消息中。
g. 每个节点的executor_task检测本节点是否有新的learned消息,若有则将其通知server层,进行后续处理。
(2)无缝连接的回调机制
Group Replication是通过MySQL的插件方式实现的,基本上不影响MySQL的原有事务处理过程,只是在流程中选择性的插入一些Group Replication的特殊处理方法,为了尽可能减少对原有代码的影响,采用了回调函数的机制来实现对Group Replication的支持。其中最重要的两个回调函数集如下所示:
节点状态相关的回调函数集 Server_state_observer server_state_observer = { sizeof(Server_state_observer),group_replication_before_handle_connection, //client连接到服务器之前 group_replication_before_recovery, //故障恢复之前 group_replication_after_engine_recovery, //引擎恢复之后 group_replication_after_recovery, //故障恢复之后 group_replication_before_server_shutdown, //server关闭之前 group_replication_after_server_shutdown, //server关闭之后 };
事务处理相关的回调函数集 Trans_observer trans_observer = { sizeof(Trans_observer), group_replication_trans_before_dml, //DML语句执行之前,条件检查 group_replication_trans_before_commit, //事务提交之前 ,节点间事务同步 group_replication_trans_before_rollback, //事务回滚之后 group_replication_trans_after_commit, //事务提交之后 group_replication_trans_after_rollback, //事务回滚之后 };
其中最重要的回调函数是group_replication_trans_before_dml,用于执行条件检查,判断是否符合Group Replication的限制条件。group_replication_trans_before_commit在binlog已经写入cache,准备提交之前通过XCOM组件进行事务的节点间同步。
(3)节点间事务的同步
在Group Replication中,若用户在一个节点执行一条SQL,如一条Insert语句,在提交之前已经生成此语句的binlog,并将其写入cache,此时需要通过XCOM来进行节点的事务同步,将此事务同步到多数节点,并判断此事务与其它节点的事务之间是否存在冲突,若存在冲突,此事务是否需要回滚等。
MySQL Group Replication在提交事务之前通过XCOM来进行节点间事务的同步,保证事务提交前,多数节点上已经保存此事务相关的binlog event,从而保证节点间事务的一致性。为降低MySQL与XCOM代码的耦合性,采用消息通知、回调函数等机制有效的对不同模块进行隔离。
想了解更多精彩内容,请扫码关注【HW云数据库】
- 点赞
- 收藏
- 关注作者
评论(0)