MGR的主要逻辑可以划分为两部分:事务的执行逻辑和成员的管理逻辑。下面看看成员的管理逻辑。



组视图


成员管理中一个很重要的概念叫做组视图(Group View),或者简称为视图(View)。视图是指组在一段时间内的成员状态。在这个时间段内没有成员变化,即没有成员加入也没有成员退出。如果成员发生了变化,成员状态就变化了,于是它就进入另外一个视图。不同的视图之间通过视图ID(View ID)来进行区分。视图随时间的变化有先后顺序,因此View ID也有先后顺序的。View ID被定义为两个部分。


·前缀固定部分:是一个随机数,这个值在组初始化时产生,之后,所有View的前缀部分都是用这个随机数。

·顺序号变动部分:初始化时,第一个视图的顺序号从1开始,以后每次视图变化顺序号递增。


可以通过performance_schema.replication_group_member_stats.VIEW_ID查看当时的View ID,显示格式为15684692122392840:7。



加入组时视图的切换


当一个MySQL实例加入组时,group_replication插件首先会根据group_replication_group_seeds的内容和一个种子成员建立TCP连接。而种子成员会根据自己的IP白名单检查是否允许其接入。连接建立后,新成员会发送一个加入请求给种子成员。收到请求后,种子成员广播视图变化的消息给所有成员(包括申请加入的成员)。各个成员收到消息后开始做视图切换。首先,每个成员都会广播一个状态交换消息出去。接着,各个成员开始接收状态交换消息。状态交换消息中包含了成员的当前状态和信息。成员收到状态交换信息后,将消息中的成员信息更新到自己的成员列表中。当收到所有成员中的最后一个状态交换消息时,通信模块将完整的新视图以视图数据包的形式返回给全局事务认证模块进行处理。整个视图的切换过程至此结束,视图切换的整个过程不影响在线成员对外提供服务。离开组时的视图切换和加入组时的视图切换过程基本一样,这里略。


View_change_log_event


状态交换消息和事务数据包一样都是通过Paxos协议发送的,因此它们之间也是有序的。事务数据包以视图数据包为分界线,划分到不同的视图中。它前面的事务数据包属于前一个视图的事务,而后面的数据包都是属于当前视图中的事务。全局事务认证模块会对每一个视图数据包创建一个View_change_log_event,这个Event会被写入Relay log,然后被执行,最终会出现在Binlog中,因此Binlog里的Event也被View_change_log_event划分到不同的视图中。View_change_log_event里面记录了当前的View ID,还有冲突检测数据库的信息。当记录View_change_log_event到Binlog中时,它会封装到一个事务中,并且有自己的GTID,包括以下几个Event。


Gtid_log_event;

Query_log_event("BEGIN");

View_change_log_event;

Query_log_event("COMMIT")



恢复


视图切换完成后,成员就正式加入到组内。它可以接收到当前视图任务事务的数据包,但是视图切换前的数据包是收不到的。所以,在MySQL实例加入组后,不能立即对外提供服务,而需要执行一些操作将自己缺失的数据从其它成员上复制过来,这个过程叫作恢复(Recovery)。一个成员加入后,会立即将自己的状态设置为RECOVERING,开始执行恢复的过程。恢复的过程分为本地恢复、全局恢复和缓存事务执行三个步骤。


本地恢复


如果这个成员曾经加入过这个组,它的group_replication_applier通道的Relay log可能还有一些Event没有被执行到数据库中。因此,group_replication插件首先会启动group_replication_applier通道,将本地的Binlog Event执行完毕。


全局恢复


本地恢复执行完毕后,开始进行全局恢复。全局恢复是通过group_replication_recovery进行的。group_replication插件会随机选择一个在线成员作为这个通道的Master,这个被选择的成员叫作Donor。group_replication插件会自动配置group_replication_recovery通道,并且启动这个通道进行复制。在启动group_replication_recovery通道时,group_replication插件会告诉它:当碰到View ID等于当前View ID的View_change_log_event时停止。当执行完这个View_change_log_event后,group_replication_recovery通道会将这个Event中的冲突检测数据库初始化到group_replication插件中,然后停止运行。


[root@mysql.sock][(none)]> show slave status for channel 'group_replication_recovery'\G

***************** 1. row **********

Slave_IO_State: Queueing master event to the relay log

Master_Host: mysql03.com

Master_User: rpl_user

Master_Port: 3308

Master_Log_File: bin.000008

Read_Master_Log_Pos: 1057323816

Relay_Log_File: relay-group_replication_recovery.000003

Relay_Log_Pos: 66466195

Relay_Master_Log_File: bin.000008

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

Exec_Master_Log_Pos: 825117649

Relay_Log_Space: 298672913

Until_Condition: SQL_VIEW_ID

Until_Log_File:


缓存事务执行


在执行全局恢复过程的同时,成员间的通信模块还会收到当前视图中产生的事务数据包。这些数据包会被缓存起来直到全局恢复执行完毕后,全局事务认证模块才开始处理这些事务。当缓存的事务全部执行完毕后,该成员才能设置为ONLINE状态。当然用户也可以让成员在缓存的事务执行之前就上线,MGR提供了group_replication_recovery_complete_at(其值为TRANSACTIONS_APPLIED、TRANSACTIONS_CERTIFIED)来控制上线的时间。上线不仅仅是状态的改变,在多主模式下,上线意味着只读模式会被关闭,上线后成员就能够接收用户的写操作了。