GTID的生命周期由以下步骤组成:
事务在源上执行并提交。此客户机事务被分配一个GTID,由源的UUID和此服务器上尚未使用的最小非零事务序列号组成。GTID被写入源的二进制日志(紧接在日志中事务本身的前面)。如果客户端事务没有写入二进制日志(例如,因为事务被过滤掉了,或者事务是只读的),则不会为其分配GTID。
如果为事务分配了GTID,则在提交时通过将其写入事务开始的二进制日志(作为一个
Gtid_log_event
).每当旋转二进制日志或服务器关闭时,服务器都会将写入前一个二进制日志文件中的所有事务的gtid写入mysql.gtid_executed
表格如果为事务分配了GTID,则将GTID非原子地外部化(在事务提交后不久),方法是将其添加到
gtid_executed
系统变量(@@GLOBAL.gtid_executed
).这个GTID集合包含所有已提交GTID事务集合的表示,它在复制中用作表示服务器状态的令牌。启用二进制日志记录(根据源程序的要求)后,gtid_executed
系统变量是应用事务的完整记录,但是mysql.gtid_executed
表不是,因为最近的历史记录仍然在当前二进制日志文件中。在将二进制日志数据传输到副本并将其存储在副本的中继日志中(使用此过程已建立的机制,请参见第17.2节“复制的实施”,副本读取GTID并设置其值
gtid_next
系统变量如GTID。这告诉副本必须使用这个GTID记录下一个事务。重要的是要注意副本集gtid_next
在会话上下文中。副本验证还没有线程获得GTID的所有权
gtid_next
以便处理事务。在处理事务本身之前,通过首先读取和检查复制事务的GTID,副本不仅保证没有具有此GTID的前一个事务被应用到副本上,而且还保证没有其他会话已经读取了此GTID但尚未提交关联的事务。因此,如果多个客户机试图并发应用同一个事务,服务器将通过只让其中一个执行来解决此问题。的gtid_owned
系统变量(@@GLOBAL.gtid_owned
),显示当前正在使用的每个GTID以及拥有它的线程的ID。如果GTID已经被使用,则不会引发错误,并使用自动跳过功能忽略事务。如果GTID未被使用,副本将应用复制的事务。因为
gtid_next
设置为源已经分配的GTID时,副本不会尝试为这个事务生成一个新的GTID,而是使用存储在gtid_next
.如果在副本上启用了二进制日志记录,则GTID在提交时通过在事务开始时将其写入二进制日志(作为一个
Gtid_log_event
).每当旋转二进制日志或服务器关闭时,服务器都会将写入前一个二进制日志文件中的所有事务的gtid写入mysql.gtid_executed
表格如果在副本上禁用了二进制日志记录,则通过将GTID直接写入
mysql.gtid_executed
表格MySQL将一条语句添加到事务中,将GTID插入到表中。从MySQL 8.0开始,这个操作对于DDL语句和DML语句都是原子的。在这种情况下,mysql.gtid_executed
表是应用于副本上的事务的完整记录。在副本上提交复制事务后不久,将GTID非原子地外部化,将其添加到
gtid_executed
系统变量(@@GLOBAL.gtid_executed
)下载副本。至于源,这个GTID集合包含所有已提交GTID事务集合的表示。如果在副本上禁用了二进制日志记录,则mysql.gtid_executed
表也是应用于副本上的事务的完整记录。如果在副本上启用了二进制日志记录,这意味着某些gtid只记录在二进制日志中,则gtid_executed
系统变量是唯一完整的记录。
在源上完全过滤掉的客户端事务不会被分配GTID,因此它们不会被添加到gtid_executed
系统变量,或添加mysql.gtid_executed
表格但是,在复制上被完全过滤掉的复制事务的gtid将被持久化。如果在副本上启用了二进制日志记录,则过滤掉的事务将作为Gtid_log_event
后面是一个空事务,只包含开始
而且提交
语句。如果禁用二进制日志记录,则过滤掉的事务的GTID将写入mysql.gtid_executed
表格为过滤掉的事务保留gtid可以确保mysql.gtid_executed
表和gtid的集合gtid_executed
可以压缩系统变量。它还确保在副本重新连接到源时不会再次检索过滤掉的事务,如中所解释的第17.1.3.3节“GTID自动定位”.
在多线程副本上(使用replica_parallel_workers > 0
或slave_parallel_workers > 0
),事务可以并行应用,因此复制的事务可以乱序提交(除非replica_preserve_commit_order = 1
或slave_preserve_commit_order = 1
设置)。当这种情况发生时,gtid的集合gtid_executed
系统变量包含多个GTID范围,它们之间有间隔。(在源或单线程副本上,gtid是单调递增的,数字之间没有间隔。)多线程副本上的空白只发生在最近应用的事务之间,并随着复制的进行而填充。方法干净地停止复制线程时停止复制
语句中,正在进行的事务将被应用,以便填补空白。在停机的情况下,如服务器故障或使用杀了
语句来停止复制线程,则间隙可能仍然存在。
典型的场景是,服务器为提交的事务生成一个新的GTID。然而,gtid也可以分配给事务之外的其他更改,在某些情况下,单个事务可以分配多个gtid。
写入二进制日志的每个数据库更改(DDL或DML)都被分配一个GTID。这包括自动提交的更改,以及使用开始
而且提交
或开始事务
语句。GTID还被分配给数据库的创建、更改或删除,以及非表数据库对象(如过程、函数、触发器、事件、视图、用户、角色或授权)。
为非事务性更新和事务性更新分配gtid。此外,对于非事务性更新,如果在试图写入二进制日志缓存时发生了磁盘写失败,并因此在二进制日志中创建了一个间隙,则为产生的事件日志事件分配一个GTID。
当一个表被二进制日志中生成的语句自动删除时,将为该语句分配一个GTID。当复制开始应用来自刚刚启动的源的事件时,以及使用基于语句的复制时,临时表将自动删除(binlog_format =声明
),打开临时表的用户会话断开。使用内存
在服务器启动后第一次访问存储引擎时将自动删除它们,因为行可能在关闭期间丢失。
当事务没有写入源服务器上的二进制日志时,服务器不会为它分配GTID。这包括回滚的事务和在源服务器上禁用二进制日志记录时执行的事务,或者全局事务(与——skip-log-bin
在服务器的配置中指定)或用于会话(设置@@SESSION。sql_log_bin = 0
).这还包括在使用基于行的复制时的无操作事务(binlog_format =行
).
XA事务被分配为单独的gtidXA准备
事务的阶段和XA提交
或XA回滚
事务的阶段。XA事务是持久准备的,以便用户在出现故障(在复制拓扑中可能包括故障转移到另一台服务器)时提交或回滚它们。因此,事务的两个部分是分别复制的,因此它们必须有自己的GTID,即使回滚的非xa事务不会有GTID。
在以下特殊情况下,单个语句可以生成多个事务,因此被分配多个gtid:
调用一个存储过程来提交多个事务。为过程提交的每个事务生成一个GTID。
一个多表
删除表
语句删除不同类型的表。如果任何表使用不支持原子DDL的存储引擎,或者任何表是临时表,则可以生成多个gtid。一个
创建表……选择
语句在使用基于行的复制时发出(binlog_format =行
).生成一个GTID创建表
操作,并为行插入操作生成一个GTID。
默认情况下,对于用户会话中提交的新事务,服务器会自动生成并分配一个新的GTID。当事务应用于副本时,来自源服务器的GTID将被保留。控件的会话值可以更改此行为gtid_next
系统变量:
当
gtid_next
被设置为自动
当事务被提交并写入二进制日志时,服务器会自动生成并分配一个新的GTID。如果事务因为其他原因被回滚或没有写入二进制日志,服务器就不会生成和分配GTID。如果你设置
gtid_next
到一个有效的GTID(由一个UUID和一个事务序列号组成,由冒号分隔),服务器将该GTID分配给您的事务。分配并添加这个GTIDgtid_executed
即使事务没有写入二进制日志,或者事务为空。
注意,设置后gtid_next
到一个特定的GTID,并且事务已经提交或回滚,显式设置@@SESSION.gtid_next
声明必须在任何其他声明之前发出。您可以使用此命令将GTID值设置回自动
如果您不想显式分配任何gtid。
当复制应用程序线程应用复制事务时,它们使用此技术设置@@SESSION.gtid_next
在源服务器上指定的复制事务的GTID。这意味着来自源服务器的GTID被保留,而不是由副本生成和分配一个新的GTID。这也意味着GTID被添加到gtid_executed
即使在副本上禁用了二进制日志记录或副本更新日志记录,或者事务为无操作或在副本上被过滤掉。
客户机可以通过设置来模拟复制的事务@@SESSION.gtid_next
到一个特定的GTID,然后再执行事务。这种技术被用于mysqlbinlog生成二进制日志的转储,客户机可以重播该转储以保存gtid。通过客户端提交的模拟复制事务与通过复制应用程序线程提交的复制事务完全等价,并且在事后无法区分它们。
的gtid集合gtid_purged
系统变量(@@GLOBAL.gtid_purged
)包含服务器上已提交的所有事务的gtid,但不存在于服务器上的任何二进制日志文件中。gtid_purged
是gtid_executed
.以下是gtid的类别gtid_purged
:
在副本上禁用二进制日志记录的情况下提交的复制事务的gtid。
写入现在已被清除的二进制日志文件的事务的gtid。
由语句显式添加到集合的gtid
设置@@GLOBAL.gtid_purged
.
的值可以更改gtid_purged
以便在服务器上记录某个GTID集中的事务已被应用,尽管它们不存在于服务器上的任何二进制日志中。当您添加gtid到gtid_purged
,它们也被添加到gtid_executed
.此操作的一个示例用例是,当您恢复服务器上一个或多个数据库的备份,但没有包含服务器上事务的相关二进制日志时。在MySQL 8.0之前,您只能更改的值gtid_purged
当gtid_executed
(因此gtid_purged
)是空的。从MySQL 8.0开始,这个限制不适用,您还可以选择是否替换整个GTID集gtid_purged
使用指定的GTID集,或将指定的GTID集添加到已存在的GTID中gtid_purged
.有关如何做到这一点的详细信息,请参见gtid_purged
.
gtid的集合gtid_executed
而且gtid_purged
在服务器启动时初始化系统变量。每个二进制日志文件都以事件开始Previous_gtids_log_event
,它包含以前所有二进制日志文件中的gtid集合(由前面文件中的gtid组成)Previous_gtids_log_event
,和gtid的每Gtid_log_event
在前面的文件本身)。的内容Previous_gtids_log_event
在最老的和最新的二进制日志文件中用于计算gtid_executed
而且gtid_purged
在服务器启动时设置:
gtid_executed
计算为?中的gtid的并集Previous_gtids_log_event
在最近的二进制日志文件中,该二进制日志文件中事务的gtid,以及存储在mysql.gtid_executed
表格这个GTID集包含已经使用(或显式添加到)的所有GTIDgtid_purged
),无论它们当前是否在服务器上的二进制日志文件中。它不包括当前正在服务器上处理的事务的gtid (@@GLOBAL.gtid_owned
).gtid_purged
的计算方法是先将gtid加在Previous_gtids_log_event
以及该二进制日志文件中事务的gtid。此步骤给出当前或曾经记录在服务器二进制日志中的gtid集(gtids_in_binlog
).接下来,gtidPrevious_gtids_log_event
在最老的二进制日志文件中减去gtids_in_binlog
.此步骤给出当前记录在服务器二进制日志中的gtid集(gtids_in_binlog_not_purged
).最后,gtids_in_binlog_not_purged
减去从gtid_executed
.结果是服务器上已经使用的gtid的集合,但目前没有记录在服务器上的二进制日志文件中,这个结果用于初始化gtid_purged
.
如果从MySQL 5.7.7或更老版本的二进制日志涉及到这些计算中,则可能计算不正确的GTID集gtid_executed
而且gtid_purged
,即使服务器稍后重新启动,它们仍然是错误的。详细信息请参见binlog_gtid_simple_recovery
系统变量,它控制如何迭代二进制日志来计算GTID集。如果这里描述的情况之一适用于服务器,则设置binlog_gtid_simple_recovery = FALSE
在服务器的配置文件中。该设置使服务器迭代所有二进制日志文件(不仅仅是最新和最早的),以查找GTID事件开始出现的位置。如果服务器有大量没有GTID事件的二进制日志文件,这个过程可能需要很长时间。
如果需要重置服务器上GTID的执行历史,请使用重置的主人
声明。例如,在执行测试查询以验证新的启用gtid的服务器上的复制设置之后,或者当您希望将新服务器加入复制组,但其中包含group replication不接受的一些不必要的本地事务时,您可能需要执行此操作。
使用重置的主人
小心避免丢失任何想要的GTID执行历史和二进制日志文件。
在发出之前重置的主人
的全局值中保存的GTID集,确保您已经备份了服务器的二进制日志文件和二进制日志索引文件(如果有的话)gtid_executed
系统变量(例如,通过发出一个选择@@GLOBAL.gtid_executed
语句并保存结果)。如果要从该GTID集中删除不需要的事务,请使用mysqlbinlog检查事务的内容,以确保它们没有价值,不包含必须保存或复制的数据,并且不会导致服务器上的数据更改。
当你的问题重置的主人
,执行以下重置操作:
的值
gtid_purged
系统变量设置为空字符串(”
).的全局值(而不是会话值)
gtid_executed
系统变量被设置为空字符串。的
mysql.gtid_executed
表被清除(参见。mysql.gtid_executedTable).如果服务器启用了二进制日志记录,则删除现有的二进制日志文件并清除二进制日志索引文件。
请注意,重置的主人
是重置GTID执行历史的方法,即使服务器是一个副本,其中二进制日志记录被禁用。重置副本
对GTID的执行历史没有影响。