GTID格式和存储
全局事务标识符(GTID)是创建的唯一标识符,并且与在源服务器(主服务器)上提交的每个事务相关联。该标识符不仅对于它起源的服务器是唯一的,而且在给定复制拓扑中的所有服务器上也是唯一的。
GTID分配区分在主服务器上提交的客户端事务和在从服务器上复制的复制事务。如果将客户端事务提交到主服务器上,则将为其分配一个新的GTID,前提是该事务已写入二进制日志中。保证客户交易的GTID单调增加,生成的数字之间没有间隙。如果没有将客户事务写入二进制日志中(例如,由于该事务已被滤除或该事务为只读),则不会在原始服务器上为其分配GTID。
复制的事务保留与原始服务器上分配给该事务的GTID相同的GTID。GTID在复制的事务开始执行之前就存在,并且即使复制的事务未写入从属服务器上的二进制日志中或在从属服务器上被过滤掉,GTID也会保留。MySQL系统表mysql.gtid_executed
用于保留MySQL服务器上应用的所有事务的已分配GTID,但存储在当前活动的二进制日志文件中的事务除外。
The auto-skip function for GTIDs means that a transaction committed on the master can be applied no more than once on the slave, which helps to guarantee consistency. Once a transaction with a given GTID has been committed on a given server, any attempt to execute a subsequent transaction with the same GTID is ignored by that server. No error is raised, and no statement in the transaction is executed.
如果具有给定GTID的事务已开始在服务器上执行,但尚未提交或回滚,则在具有相同GTID的服务器上启动并发事务的任何尝试都将被阻止。服务器既不开始执行并发事务,也没有将控制权返回给客户端。一旦对事务的第一次尝试提交或回滚,在同一GTID上阻塞的并发会话可能会继续进行。如果第一次尝试回滚,则一个并发会话将继续尝试事务,并且在同一GTID上阻塞的任何其他并发会话将保持阻塞状态。如果进行了第一次尝试,则所有并发会话都将停止阻塞,并自动跳过事务的所有语句。
GTID表示为一对坐标,并用冒号(:
)分隔,如下所示:
GTID = source_id:transaction_id
该source_id
标识的原始服务器。通常情况下,母版server_uuid
用于此目的。的transaction_id
是通过在事务提交主服务器上的顺序确定一个序列号。例如,要提交的第一个事务具有1
其transaction_id
,并且被分配一个相同的始发服务器上被提交第十交易transaction_id
的10
。事务不可能0
在GTID中具有序列号。例如,最初要在服务器上使用UUID提交的第二十三笔交易3E11FA47-71CA-11E1-9E33-C80AA9429562
具有以下GTID:
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
事务的GTID显示在mysqlbinlog的输出中,它用于识别性能模式复制状态表中的单个事务,例如replication_applier_status_by_worker
。gtid_next
系统变量(@@GLOBAL.gtid_next
)存储的值是单个GTID。
GTID集
GTID集是包括一个或多个单个GTID或一系列GTID的集。GTID集在MySQL服务器中以多种方式使用。例如,由gtid_executed
和gtid_purged
系统变量存储的值是GTID集。该START SLAVE
条款UNTIL SQL_BEFORE_GTIDS
并UNTIL SQL_AFTER_GTIDS
可以用来做一个奴隶交易过程最多只在GTID集中的最后GTID后在GTID组第一GTID,或停止。内置的功能GTID_SUBSET()
和GTID_SUBTRACT()
需要GTID集作为输入。
可以将源自同一服务器的一系列GTID折叠为一个表达式,如下所示:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
上面的例子表示第一至MySQL服务器,其上第五交易始发server_uuid
是3E11FA47-71CA-11E1-9E33-C80AA9429562
。源自同一服务器的多个单个GTID或GTID范围也可以包含在单个表达式中,且GTID或范围用冒号分隔,如以下示例所示:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49
GTID集可以包括单个GTID和GTID范围的任意组合,并且可以包括源自不同服务器的GTID。此示例显示了GTID集,该GTID集存储在已应用了多个主机的事务的从机的gtid_executed
系统变量(@@GLOBAL.gtid_executed
)中:
2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19
从服务器变量返回GTID集时,UUID按字母顺序排列,并且数字间隔按升序合并。
GTID集的语法如下:
gtid_set: uuid_set [, uuid_set] ... | '' uuid_set: uuid:interval[:interval]... uuid: hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh h: [0-9|A-F] interval: n[-n] (n >= 1)
mysql.gtid_exected表
GTID存储在数据库中名为的表gtid_executed
中mysql
。该表中的一行包含它代表的每个GTID或一组GTID,始发服务器的UUID以及该组的起始和结束事务ID。对于仅引用单个GTID的行,最后两个值相同。
在mysql.gtid_executed
安装或升级MySQL Server时,使用CREATE TABLE
类似于以下所示的语句创建该表(如果尚不存在):
CREATE TABLE gtid_executed ( source_uuid CHAR(36) NOT NULL, interval_start BIGINT(20) NOT NULL, interval_end BIGINT(20) NOT NULL,PRIMARY KEY (source_uuid, interval_start) )
警告与其他MySQL系统表一样,请勿尝试自己创建或修改该表。
该mysql.gtid_executed
表供MySQL服务器内部使用。当从属服务器上禁用二进制日志记录时,它使从属服务器可以使用GTID,而当二进制日志丢失时,它可以保留GTID状态。请注意,mysql.gtid_executed
如果您发出该表,则会将其清除RESET MASTER
。
GTID mysql.gtid_executed
仅在gtid_mode
is ON
或时存储在表中ON_PERMISSIVE
。如果禁用了二进制日志记录(log_bin
is OFF
),或者如果log_slave_updates
禁用了二进制日志记录,则服务器将mysql.gtid_executed
在事务提交时将属于每个事务的GTID与事务一起存储在表中。另外,如mysql.gtid_executed表压缩中所述,该表以用户可配置的速率定期压缩。
如果二进制日志被启用(log_bin
是ON
),从MySQL 8.0.17为InnoDB
唯一的存储引擎,服务器更新mysql.gtid_executed
以同样的方式当二进制日志或从更新日志被禁用表,存储GTID在事务中的每个事务提交时。但是,在MySQL 8.0.17之前的版本中,对于其他存储引擎,服务器仅在mysql.gtid_executed
旋转二进制日志或关闭服务器时更新表。在这些时候,服务器将所有写入前一个二进制日志的事务的GTID写入到mysql.gtid_executed
表。这种情况适用于MySQL 8.0.17之前的复制主服务器,或者适用于启用了二进制日志记录的MySQL 8.0.17之前的复制从属服务器,或者除以外的其他存储引擎InnoDB
,它具有以下后果:
- 如果服务器意外停止,则当前二进制日志文件中的GTID集不会保存在
mysql.gtid_executed
表中。在恢复期间,这些GTID从二进制日志文件添加到表中,以便复制可以继续。例外情况是,如果在服务器重新启动时(使用--skip-log-bin
或--disable-log-bin
)禁用了二进制日志记录。在这种情况下,服务器无法访问二进制日志文件以恢复GTID,因此无法启动复制。 - 该
mysql.gtid_executed
表未保存所有已执行事务的GTID的完整记录。该信息由gtid_executed
系统变量的全局值提供。在MySQL 8.0.17之前的版本中,并且存储引擎不是InnoDB
,请始终使用@@GLOBAL.gtid_executed
,它在每次提交后都会更新,以表示MySQL服务器的GTID状态,而不是查询mysql.gtid_executed
表。
mysql.gtid_executed
即使服务器处于只读或超级只读模式,MySQL服务器也可以写入表。在MySQL 8.0.17之前的版本中,这确保了二进制日志文件仍可以在这些模式下旋转。如果mysql.gtid_executed
无法访问该表进行写操作,并且二进制日志文件由于达到最大文件大小(max_binlog_size
)以外的任何原因进行了轮换,则将继续使用当前的二进制日志文件。将错误消息返回给请求轮换的客户端,并在服务器上记录警告。如果mysql.gtid_executed
无法访问该表以进行写入并访问该表max_binlog_size
,则服务器将根据其binlog_error_action
设置进行响应。如果IGNORE_ERROR
设置为时,将在服务器上记录错误,并停止二进制日志记录;如果ABORT_SERVER
已设置,则服务器将关闭。
mysql.gtid_exected表压缩
随着时间的流逝,该mysql.gtid_executed
表可能会充满很多行,这些行引用源自同一服务器的各个GTID,并且它们的事务ID构成一个范围,类似于此处显示的内容:
+-------------------------------------- +---------------- +-------------- + | source_uuid | interval_start | interval_end | |-------------------------------------- +---------------- +--------------| | 3E11FA47 -71CA -11E1 -9E33 -C80AA9429562 | 37 | 37 | | 3E11FA47 -71CA -11E1 -9E33 -C80AA9429562 | 38 | 38 | | 3E11FA47 -71CA -11E1 -9E33 -C80AA9429562 | 39 | 39 | | 3E11FA47 -71CA -11E1 -9E33 -C80AA9429562 | 40 | 40 | | 3E11FA47 -71CA -11E1 -9E33 -C80AA9429562 | 41 | 41 | | 3E11FA47 -71CA -11E1 -9E33 -C80AA9429562 | 42 | 42 | | 3E11FA47 -71CA -11E1 -9E33 -C80AA9429562 | 43 | 43 | ...
为了节省空间,MySQL服务器mysql.gtid_executed
通过用横跨事务标识符整个间隔的单行替换每组这样的行来定期压缩表,如下所示:
+--------------------------------------+----------------+--------------+ | source_uuid | interval_start | interval_end | |--------------------------------------+----------------+--------------| | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 43 | ...
通过设置gtid_executed_compression_period
系统变量,可以控制在压缩表之前允许经过的事务数,从而控制压缩率。此变量的默认值为1000,这意味着默认情况下,每1000个事务处理后将执行表压缩。设置gtid_executed_compression_period
为0根本无法执行压缩,并且如果这样做,您应该准备增加gtid_executed
表可能需要的磁盘空间量。
注意当启用二进制日志,价值
gtid_executed_compression_period
是不使用,并且mysql.gtid_executed
表上的每个二进制日志旋转压缩。
该mysql.gtid_executed
表的压缩由名为的专用前台线程执行thread/sql/compress_gtid_table
。该线程未在的输出中列出SHOW PROCESSLIST
,但可以在threads
表中的一行中参见,如下所示:
mysql>SELECT *FROM performance_schema.threadsWHERE NAME LIKE '%gtid%'\G *************************** 1. row *************************** THREAD_ID : 26 NAME : thread/sql/compress_gtid_table TYPE : FOREGROUND PROCESSLIST_ID : 1 PROCESSLIST_USER : NULL PROCESSLIST_HOST : NULL PROCESSLIST_DB : NULL PROCESSLIST_COMMAND : Daemon PROCESSLIST_TIME : 1509 PROCESSLIST_STATE : Suspending PROCESSLIST_INFO : NULL PARENT_THREAD_ID : 1 ROLE : NULL INSTRUMENTED : YES HISTORY : YES CONNECTION_TYPE : NULL THREAD_OS_ID : 18677
的thread/sql/compress_gtid_table
螺纹通常休眠,直到gtid_executed_compression_period
交易已经被执行,那么唤醒到的执行压缩mysql.gtid_executed
如前所述表。然后休眠,直到发生其他gtid_executed_compression_period
事务为止,然后唤醒以再次执行压缩,并无限重复此循环。禁用二进制日志记录时将此值设置为0意味着线程始终处于休眠状态,并且永远不会唤醒。
在启动服务器实例并启动thread/sql/compress_gtid_table
线程时,在大多数服务器配置中,将对该mysql.gtid_executed
表执行压缩。在启用了二进制日志记录的MySQL 8.0.17之前的版本中,压缩是通过在启动时旋转二进制日志来触发的。在MySQL 8.0.20发行版中,压缩是由线程启动触发的。在中间版本中,启动时不会进行压缩。