mysql gtid格式和存储

什么是 GTID

从MySQL 5.6.5 开始新增了一种基于 GTID 的复制方式。通过 GTID 保证了每个在主库上提交的事务在集群中有一个唯一的ID。这种方式强化了数据库的主备一致性,故障恢复以及容错能力。

GTID (Global Transaction ID)是全局事务ID,当在主库上提交事务或者被从库应用时,可以定位和追踪每一个事务,对DBA来说意义就很大了,我们可以适当的解放出来,不用手工去可以找偏移量的值了,而是通过CHANGE MASTER TO MASTER_HOST=‘xxx’,MASTER_AUTO_POSITION=1的即可方便的搭建从库,在故障修复中也可以采用MASTER_AUTO_POSITION=‘X’的方式。

gtid可以用来做什么

在mysql官网上(版本是5.7),经过搜索,在Replication目录下找到gtid相关介绍,Replication地址,由此可看出gtid是复制过程中使用到的,官网gtid位置

GTID的Format and Storage

全局事务标识符(GTID)是创建的唯一标识符,并且与在源服务器(主服务器)上提交的每个事务相关联。该标识符不仅对于它起源的服务器(主服务器)是唯一的,而且在给定复制拓扑中的所有服务器上(从服务器)也是唯一的。

GTID分配区分在主服务器上提交的客户端事务和在从服务器上复制的复制事务。如果将客户端事务提交到主服务器上,则将为其分配一个新的GTID,前提是该事务已写入二进制日志中。保证客户交易的GTID单调增加,生成的数字之间没有间隙。如果没有将客户事务写入二进制日志中(例如,由于该事务已被滤除或该事务为只读),则不会在原始服务器上为其分配GTID。

复制的事务保留与原始服务器上分配给该事务的GTID相同的GTID。GTID在复制的事务开始执行之前就存在,并且即使复制的事务未写入从属服务器上的二进制日志中或在从属服务器上被过滤掉,GTID也会保留。MySQL系统表mysql.gtid_executed用于保留MySQL服务器上应用的所有事务的已分配GTID,但存储在当前活动的二进制日志文件中的事务除外。

GTID的自动跳过功能意味着在主服务器上提交的事务只能在从服务器上应用一次,这有助于确保一致性。一旦将具有给定GTID的事务提交到给定服务器上,则该服务器将忽略执行具有相同GTID的后续事务的任何尝试。不会引发错误,并且不会执行事务中的任何语句。

如果具有给定GTID的事务已开始在服务器上执行,但尚未提交或回滚,则在具有相同GTID的服务器上启动并发事务的任何尝试都将被阻止。服务器既不开始执行并发事务,也没有将控制权返回给客户端。一旦对事务的第一次尝试提交或回滚,在同一GTID上阻塞的并发会话可能会继续进行。如果第一次尝试回滚,则一个并发会话将继续尝试事务,并且在同一GTID上阻塞的任何其他并发会话将保持阻塞状态。如果进行了第一次尝试,则所有并发会话都将停止阻塞,并自动跳过事务的所有语句。

GTID表示为一对坐标,并用冒号(:)分隔,如下所示:

GTID = source_id:transaction_id

该source_id指发生事务的源服务器的唯一标识。通常情况下,server_uuid被用作source_id。而transaction_id是通过在事务提交主服务器上的顺序确定一个序列号。例如,要提交的第一个事务使用1作为 transaction_id,并且同一台服务器上被提交的第十个事务的transaction_id是10。GTID的序列号中不可能存在0,也就是说transaction是从1开始的。例如,在服务器上使用UUID(3E11FA47-71CA-11E1-9E33-C80AA9429562)提交的第23个事务 具有以下GTID:

3E11FA47-71CA-11E1-9E33-C80AA9429562:23

事务的GTID会显示的输出到mysqlbinlog日志文件中 ,它用于识别performance_schema中各表中的单个事务,例如下图中各表所示:
在这里插入图片描述 gtid_next 系统变量(@@GLOBAL.gtid_next)存储的值是单个GTID。

GTID Sets

一个GTID set 包含一个或多个GTID或一系列GTID的集,GTID set在MySQL服务器中以多种方式使用。例如,由gtid_executed(MySQL数据库已经执行了哪些GTID事务,处于内存中。show slave status中的executed_gtid_set也取自这里)和 gtid_purged(由于BINLOG文件的删除(如purge binary logfiles或者超过expire_logs_days设置)已经丢失的GTID事务,同时在搭建备库的我们使用set global gtid_purged变量来提示MySQL哪些GTID事务我已经执行过了)系统变量存储的值 是GTID set。start slave操作规定UNTIL SQL_BEFORE_GTIDS和 UNTIL SQL_AFTER_GTIDS,也就是说会开启一个GTID set中的第一个gtid,或者停止一个GTID set中的最后一个gtid,内置的函数GTID_SUBSET()和 GTID_SUBTRACT()需要GTID set作为参数输入。

可以将源自同一服务器的一系列GTID使用一个表达式表示,如下所示(表示UUID为3E11…这台服务器上的第1-5共5个事务,事务的gtid为1-5):

3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5

来自同一个服务器的多个不连续的gtid也可以使用一个表达式来表示,如下所示:

3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49

一个GTID set也可以包括单个GTID和GTID范围的任意组合,并且可以包括源自不同服务器的GTID。下面这个示例表示GTID set存储了多个主机的事务的从服务器上的 gtid_executed系统变量值(@@GLOBAL.gtid_executed)中:

2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19

在从服务器上查询GTID set时,UUID按字母顺序排列,并且数字间隔按升序合并,如下所示:

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存储在mysql.gtid_executed表中。该表中的一行包含它代表的每个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状态。请注意,如果你执行了reset maser,则mysql.gtid_executed 表记录会被清除。

mysql.gtid_executed 仅在gtid_mode 设置为ON或ON_PERMISSIVE时才会存储GTID。GTID的存储依赖于是否启用了二进制日志记录:

如果禁用了二进制日志记录(log_bin is OFF),或者如果 log_slave_updates is disabled,则服务器将属于每个事务的GTID与该事务一起存储在表中。此外,该表会以用户可配置的速率定期压缩。有关更多信息,请参见 mysql.gtid_executed Table Compression。这种情况仅适用于从数据库。它不适用于主数据库,因为在主数据库上,必须启用二进制日志记录才能进行复制。

如果启用了二进制日志记录(log_bin is ON),则每当旋转二进制日志(每个binlog文件都有固定大小,超过固定大小会新起一个binlog进行记录)或关闭服务器时,服务器都会将写入前一个二进制日志的所有事务的GTID写入mysql.gtid_executed表中。这种情况适用于启用了二进制日志记录的复制主机或复制从属。

如果服务器意外停止,则当前二进制日志文件中的GTID集不会保存在 mysql.gtid_executed表中。在恢复期间,这些GTID从二进制日志文件添加到表中。假如重新启动服务器时未启用二进制日志记录。在这种情况下,服务器无法访问二进制日志文件以恢复GTID,因此无法启动复制。

启用二进制日志记录后,该 mysql.gtid_executed表不会保存所有已执行事务的GTID的完整记录。该信息由gtid_executed系统变量的全局值提供 。始终使用 @@GLOBAL.gtid_executed,在每次提交后更新,以表示MySQL服务器的GTID状态,并且不查询 mysql.gtid_executed表。

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 server 使用范围值来压缩表mysql.gtid_executed table,如下所示:

+--------------------------------------+----------------+--------------+
| 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 table在每次旋转binlog文件时被压缩。

表mysql.gtid_executed的压缩由名为thread/sql/compress_gtid_table的前台线程执行。该线程未在SHOW PROCESSLIST中输出,但可以在threads表中的一行中查看 ,如下所示:

mysql> SELECT * FROM performance_schema.threads WHERE 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通常sleep,直到 gtid_executed_compression_period 记录的阈值数达到时执行,那么唤醒线程压缩mysql.gtid_executed后继续休眠,直到再次达到gtid_executed_compression_period 的阈值为止 ,然后唤醒以再次执行压缩,并无限重复此循环。禁用二进制日志记录时将此值设置为0意味着线程始终处于休眠状态,并且永远不会唤醒。
参考官网地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值