全局事务认证模块
全局事务认证模块有一个消息队列,用来存放收到的消息。这些消息主要是事务的Binlog Event,也有一部分状态和控制消息。状态表replication_group_member_stats中的字段COUNT_TRANSACTIONS_IN_QUEUE指的就是这个队列中的事务数量。
全局事务认证模块的核心任务是做冲突检测,识别出那些同时修改了同样数据的事务,并做出相应的处理。冲突检测时需要的信息包括三点。
·主键信息。
·事务执行时数据库的快照版本。
·执行事务的MySQL实例的UUID。
冲突检测需要的信息
MGR的冲突检测中以数据行为单位,两个事务是不是修改了同样的数据,是通过事务所修改的主键值来判断的。当发现两个事务修改了同样的数据后,如何来判断这两个事务是不是同时执行呢?这里用到了数据库快照版本。数据库快照是数据库的一个瞬时状态,每个写操作都会导致数据库状态的变化,不同的状态用不同的快照版本来表示。快照版本是用GTID来表示的,每个写事务都会产生一个唯一的GTID,这个GTID由全局事务认证模块产生,且在事务提交时会被添加到全局变量gtid_executed中。因此,gtid_executed的内容就是MySQL数据库的快照版本。
冲突检测数据库
全局事务认证模块中还维护了一个冲突检测数据库,它是主键哈希+快照版本的列表。快照版本存储的是最后一个修改此主键事务的快照版本加上这个事务的GTID。收到事务信息后,全局事务认证模块会根据Transaction_context_log_event中的主键信息,从冲突检测数据库中检索出所有主键的快照版本和该事务的快照版本进行对比。当前事务的快照版本必须要包含检索出的所有主键快照版本中的GTID,否则就是有冲突。
冲突处理
冲突检测完成后,全局认证模块接下来的处理是有本地事务和异地事务区分的。Transaction_context_log_event中记录了产生这个事务的MySQL实例的UUID。根据这个UUID,就能判断出这是一个本地事务还是异地事务。对于本地事务处理如下。
·如果没有冲突,唤醒这个事务的线程,并且告诉它完成提交操作。
·如果有冲突,唤醒这个事务的线程,并且告诉它发生冲突,需要回滚。
·不论是否有冲突,Binlog Event都会被丢弃。
对于异地事务的处理如下。
·如果没有冲突,将这个事务的Binlog Event写入Relay log中,让group_replication_applier通道去执行。
·如果有冲突,则丢弃这个事务的Binlog Event。
冲突检测数据库的清理
随着使用时间越来越长,冲突检测数据库中维护的主键信息会越来越多,会占用大量内存。为了减少内存的使用并提高查询效率,全局事务认证模块需要定期的清理冲突检测数据库。如果一个事务已经在所有成员上执行了,其它事务的执行肯定不会和它有冲突,因此这个事务的所有主键信息就可以从冲突检测数据库中移除。主键信息的清理是依据成员上的全局变量gtid_executed中的GTID集合来做的。全局认证模块启动了一个广播线程,每60秒将自己的gtid_executed中的GTID集合广播到所有成员上。全局认证模块收到所有成员的GTID集合后,取它们的交集。这个交集中包含的就是那些已经在所有成员上执行了的事务GTID的集合,称作全局完成的GTID集合(replication_group_member_stats表中的TRANSACTIONS_COMMITTED_ALL_MEMBERS显示的就是全局完成的GTID集合。)。全局事务认证模块会将冲突检测数据库所有主键的快照版本和全局完成的GTID集合进行对比,如果快照版本GTID集合是全局完成的GTID集合的子集,则这个主键的信息就会从冲突检测数据库中清除掉。
异地事务执行模块
为了执行异地事务的Binlog Event,MGR会自动创建一个名为group_replication_applier的通道。这个通道的Receiver线程是关闭的,不会从其它成员上去复制Binlog Event。所有的Binlog Event都是由全局事务认证模块通过API写入Relay log的。
事务流程的总结
事务在MGR中的执行过程可以总结为以下三个部分。
·网络传输。
·事务在本地的执行过程。
·事务在异地的执行过程。
网络传输
MGR通过Paxos协议来传播事务信息。Paxos保障所有的事务信息按照同样的顺序传播到所有成员上。