【MySQL】深入学习GTID(一)

前言:今天听张同学在群里分享了GTID,对我自己而言,也算是一次重新认识GTID的机会,看了张同学的分享,相对来说比较简单精炼,晚上在回家的路上,我就在思考今天的文章写点什么东西,那么我想了想,打算从官网翻译一些关于GTID的文章作为GTID学习的系列文章吧。

  • GTID的概念
    • GTID sets
    • mysql.gtid_executed Table
    • mysql.gtid_executed Table Compression

    GTID是由源库(主库)每次事务提交产生的唯一标识,这个GTID不仅是单实例的唯一标识,而且在一组主从结构中也是唯一标识,并且所有的GTID和所有的事务都是一对一的关系。
GTID格式如下:

GTID = source_id:transaction_id

    sourceid表示源库,通常来说,服务器的server_uuid主要就是为了这个目的。transaction_id是由事务提交的顺序产生的一个连续的数字。例如,第一个提交的事务的事务号就是1,第十个提交的事务产生的事务号就是10,并且,GTID不可能为0.例如,server_uuid为3E11FA47-71CA-11E1-9E33-C80AA9429562的第23个事务的GTID就表示为如下:

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

    以上的GTID表示可以在SHOW SLAVE STATUS或者在binlog中看到。可以通过命令mysqlbinlog --base64-output=DECODE-ROWS或者SHOW BINLOG EVENTS解析binlog文件见到。
    例如,我们通过SHOW MASTER STATUS或SHOW SLAVE STATUS见到如下格式:

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

    这个例子显示server_uuid为3E11FA47-71CA-11E1-9E33-C80AA9429562的第一到第五个事务。这个表达式也用于启动复制START SLAVE时的选项SQL_BEFORE_GTIDS和SQL_AFTER_GTIDS。

  • GTID sets
    一个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)

    GTID集在MySQL中有多种用途。例如,.gtid_executed和.gtid_purged系统变量也保存了GTID的值。此外,函数GTID_SUBSET()和GTID_SUBTRACT()也需要GTID作为输入参数。系统变量返回GTID时,UUID的字母和数字是按升序的方式排列的。

    GTID通常出现在主从结构中。这就表示我们可以通过解析binlog获取到在从库上应用任何事务的来源。此外,一旦给定的GTID的事务已经在给定的数据库上执行过以后,相同的GTID的事务将不再执行。因此,相同GTID的事务在从库上只能执行一次,这就保证了数据的一致性。

    一旦主从结构采用了GTID,我们就不再需要主库的binlogfile名和复制的位置点。所有同步所需要的主库的信息直接从复制的数据流中就可以得到。GTID代替了传统复制所需要的文件偏移量。因此,在change master的时候不需要MASTER_FILE和MASTER_LOG_POS选项,只需要开启MASTER_AUTO_POSITION即可。

GTID的产生由下面几步产生:
1.一个事务在主库上执行并提交。
这个事务由主库的UUID和未在该实例内使用过的最小非零事务序列号标识。GTID写入主库的binlog。

2.binlog传输到从库上以后存入从库的relay log,slave读取GTID然后设置自己的gtid_next的值,这个值告诉slave下一个事务必须使用这个GTID。
提醒:slave 设置gtid_next是一个会话级的变量

3.slave会去确认这个GTID的事务是否已经执行过了并且其他会话也没有读过该GTID,如果这个GTID没有用过,那么slave就会去写GTID,应用该事务然后写改事务到自身的binlog中。简而言之就是,多个客户端不允许同时应用同一个事务。

4.因为.gtid_next是非空,slave不会主动去为某个事务去生成一个GTID,而是把GTID存在.gtid_next这个变量中,也就是说从master获取到GTID,然后写入到该变量中,最后才写binlog。

  • mysql.gtid_executed Table
    从MySQL5.7.5开始,GTID信息存储在gtid_executed表内(mysql库)。该表的每一行存储了每个GTID的信息,源库的uuid,开始和结束的事务编号。
    MySQL安装或升级后,mysql.gtid_executed表会自动创建,建表SQL如下:
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.gtid_executed表允许slave在没有开启binlog的情况下使用GTID,并且即使是binlog丢失的情况,也会保留GTID的历史信息。 只有当GTID_MODE或者ON_PERMISSIVE时GTID才会存储在该表中,至于哪个GTID会存储在表中取决于binlog是否开启。

  • 如果binlog关闭,或者log_slave_updates关闭,那么数据库会将GTID连同表中的事务一起存储。此外,该表会以用户配置的频率来压缩该表。这种情况只可能应用在binlog后者slave update logging都关闭的slave上而不会出现在master上,因为master必须开启binlog主从才能复制。
  • 如果binlog开启的话。无论binlog被切割或者服务被重启了,mysql会把之前所有写入binlog事务的GTID写入gtid_executed表。这种情况应用于主从复制的主库上,或者开启binlog的从苦苦。
    如果服务器意外关闭,当前binlog的GTID没有存储到gtid_executed表,在这种情况下,当mysql在恢复的时候,会将GTID写入该表和gtid_executed变量。 开启binlog时,mysql.gtid_execute表不提供所有已执行事务的GTID的完整记录,而是由全局值gtid_executed记录。mysql.gtid_executed表通过RESET MASTER来重置。
  • mysql.gtid_executed Table Compression
        随着时间的推移,mysql.gtid_Executed表可以填充许多行,这些行引用来自同一服务器上的单个gtid,其事务ID组成一个序列,类似于这里所示:
mysql> SELECT * FROM mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| 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           |
...

如果通过用跨事务标识符整个间隔的单个行替换每一组这样的行来定期压缩表,则可以节省相当大的空间,如下所示:

+--------------------------------------+----------------+--------------+
| source_uuid                          | interval_start | interval_end |
|--------------------------------------+----------------+--------------|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37             | 43           |
...

    当启用gtids时,服务器会周期性地对mysql.gtid_Executed表执行这种类型的压缩。您可以通过设置已执行的gtids压缩_周期系统变量来控制允许在表压缩之前经过的事务数,从而控制压缩率。此变量的默认值是1000;这意味着默认情况下,表的压缩是在每1000次事务之后执行的。压缩是完全不执行的;但是,如果这样做,您应该准备好可能需要大量增加gtid_Executed表所需的磁盘空间。

    mysql.gtid_Executed表的压缩由一个名为线程/sql/compress_gtid_table的专用前台线程执行。这个线程没有列在显示处理列表的输出中,但它可以被看作线程表中的一行,如下所示:

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

    线程/sql/compress_gtid_table线程通常处于休眠状态,直到执行了gtids压缩期事务,然后醒来执行前面描述的mysql.gtid_Executed表的压缩。然后,它会休眠,直到发生了另一个执行的gtids压缩期事务,然后醒来再次执行压缩,重复这个循环不确定。当二进制日志记录被禁用时,将这个值设置为0意味着线程总是休眠,永远不会醒来。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容