1. GTID的格式和存储

GTID即全局事务ID(global transaction identifier),GTID实际上是由server_uuid:transaction_id组成的。其中server_uuid是一个MySQL实例的唯一标识,存放在数据目录的auto.cnf文件下,transaction_id代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。

1.1 GTID 集

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_executedgtid_purged系统变量存储的值表示为GTID集。 此外,函数GTID_SUBSET()GTID_SUBTRACT()需要GTID集作为输入。 当从服务器变量返回GTID集时,UUID按字母顺序排列,数值间隔按升序合并。

1.2 mysql.gtid_executed 表

GTID存储在mysql数据库中名为gtid_executed的表中。 对于它表示的每个GTID或GTID集合,该表中的一行包含原始服务器的UUID,以及该集合的起始和结束事务ID; 对于仅引用单个GTID的行,这两个最后两个值是相同的。

当slave禁用binlog时,mysql.gtid_executed表使slave能够使用GTID,并且它可以在二进制日志丢失时保留GTID历史记录。

当gtid_mode为ON或ON_PERMISSIVE时,GTID仅存储在mysql.gtid_executed表中,存储GTID的位置取决于是启用还是禁用binlog:

  • 如果禁用二进制日志记录(log_bin为OFF),或者如果禁用log_slave_updates,则服务器将属于每个事务的GTID与表中的事务一起存储。 此外,该表可以定期压缩; 此情况仅不适用于复制中的master,因为在主服务器上,必须启用二进制日志记录才能进行复制。

  • 如果启用了二进制日志记录(log_bin为ON),则无论何时轮询二进制日志或关闭服务器,服务器都会将写入先前二进制日志的所有事务的GTID写入mysql.gtid_executed表。 这种情况适用于复制主服务器或启用了二进制日志记录的复制从服务器。

    如果服务器意外停止,则当前二进制日志中的GTID集不会保存在mysql.gtid_executed表中。 在这种情况下,这些GTID会在恢复期间添加到表和gtid_executed系统变量中的GTID集合中。

    启用二进制日志记录时,mysql.gtid_executed表不会为所有已执行的事务提供GTID的完整记录。 该信息由gtid_executed系统变量的全局值提供。

命令RESET MASTER将重置mysql.gtid_executed表。

1.3 mysql.gtid_executed 表压缩

启用GTID时,服务器会定期在mysql.gtid_executed表上执行此类压缩。 通过设置gtid_executed_compression_period系统变量,您可以控制压缩表之前允许的事务数,从而控制压缩率。 该变量的默认值为1000; 这意味着,默认情况下,在每1000次事务之后执行表的压缩。 将gtid_executed_compression_period设置为0可以防止执行压缩; 但是,如果执行此操作,您应该为gtid_executed表可能需要的磁盘空间量的大幅增加做好准备。

【注意】:

启用binlog时,且不使用gtid_executed_compression_period的值,会在每个binlog轮换时压缩mysql.gtid_executed表。

压缩前:

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 |
...

mysql.gtid_executed表的压缩由名为thread/sql/compress_gtid_table的专用前台线程执行。 该线程未在SHOW PROCESSLIST的输出中列出,但可以将其视为performance_schema.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线程通常会休眠,直到执行了gtid_executed_compression_period事务,然后唤醒以执行mysql.gtid_executed表的压缩,如前所述。 然后它休眠直到另一个gtid_executed_compression_period事务发生,然后唤醒再次执行压缩,无限期地重复此循环。 禁用二进制日志记录时将此值设置为0意味着线程始终处于休眠状态且从不唤醒。

2. GTID 生命周期

GTID的生命周期包括以下步骤:

  1. Master产生GTID:在Master端产生一个GTID的信息,并保存到binlog中。
  2. 发送Binlog信息到从库上,将binlog信息发送到SLAVE所在的服务器上。将SLAVE中的gtid_next的值设置为GTID的值。
  3. SLAVE执行GTID。SLAVE首先验证是否在自己的二进制日志中使用了这个GTID号
  4. SLAVE不生成GTID。由于GTID不为空,SLAVE不会尝试为该事务生成新的GTID,而是从gtid_next 中读取GTID值,写入二进制日志中,来标识一个事务的GTID的值。

gtid_purged

gtid_purged系统变量(@@global.gtid_purged)中的GTID集包含已在服务器上提交但在服务器上的任何二进制日志文件中不存在的所有事务的GTID。 以下类别的GTID在此集合中:

  • 在slave上禁用binlog提交的复制事务的GTID
  • 已写入已清除的binlog的事务的GTID
  • 由语句SET @@global.gtid_purged明确添加到集合中的GTID

服务器启动时,将初始化gtid_purged系统变量中的GTID集。 每个二进制日志文件都以事件Previous_gtids_log_event开头,该事件包含所有先前二进制日志文件中的GTID集(由前一个文件的Previous_gtids_log_event中的GTID和文件本身中每个Gtid_log_event的GTID组成)。 最旧的二进制日志文件中的Previous_gtids_log_event的内容用于在服务器启动时初始化gtid_purged集,并在清除二进制日志文件时维护该集。

3. 使用GTID搭建主从

GTID使用master_auto_position=1代替了基于binlog和position号的主从复制搭建方式,更便于主从复制的搭建。

3.1 环境准备

类型 ip prot server-id 是否开启binlog binlog格式 log_slave_updates参数
master 192.168.56.100 3307 1003307 log-bin = /data/mysql/mysql3307/logs/my3307_binlog binlog_format = row log_slave_updates=1
slave 192.168.56.200 3307 2003307 log-bin = /data/mysql/mysql3307/logs/my3307_binlog binlog_format = row log_slave_updates=1

3.2 配置GTID主从的参数

  • server_id: 设置MySQL实例的server_id,每个server_id不能一样
  • gtid_mode=ON: MySQL实例开启GTID模式
  • enforce_gtid_consitency=ON:使用GTID模式复制时,需要开启参数,用来保证数据的一致性。
  • log-bin: MySQL必须要开启binlog
  • log-slave-updates=1:决定SLAVE从Master接收到更新且执行是否记录到SLAVE的binlog中
  • binlog_format=ROW: binlog格式为row
  • skip-slave-start=1(可选): 当SLAVE数据库启动的时候,SLAVE不会启动复制

3.3 在master上操作

1) 创建复制账号

create user 'repl'@'%' identified by 'wanbin';

grant replication slave on *.* to 'repl'@'%';

2) master数据库利用xtrabackup备份至slave上


innobackupex --defaults-file=/etc/my3307.cnf -uroot -pmysql --stream=tar ./ |ssh root@mysqldb2 "cat - > /data/backup/dbback`date +%Y%m%d_%H%M%S`.tar"

3.4 在slave上操作

  1. 解压备份
mkdir dbback20181012_151213

tar -xvf dbback20181012_151213.tar -C dbback20181012_151213
  1. prepare备份
innobackupex --apply-log /data/backup/dbback20181012_151213/
  1. 恢复备份
innobackupex --defaults-file=/etc/my3307.cnf --copy-back /data/backup/dbback20181012_151213/

chown -R mysql:mysql /data/mysql/mysql3307/data

mysqld --defaults-file=/etc/my3307.cnf &
  1. 过滤掉已执行过的gtid
1)查看xtrabackup_info文件中的gtid信息
cat xtrabackup_info|grep binlog_pos
binlog_pos = filename 'my3307_binlog.000002', position '2401', GTID of the last change '3a068bf8-cdeb-11e8-8176-080027b0b461:1-10' 2)查看slave已执行的gtid是否为空,如果不为空,需要执行reset MASTER进行清理,否则无法设置gtid。
root@localhost [(none)] 15:50:41>show master status \G;
*************************** 1. row ***************************
File: my3307_binlog.000002
Position: 234
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 3a068bf8-cdeb-11e8-8176-080027b0b461:1-10,
ffe86a27-cdef-11e8-bb92-0800275b8a9a:1-2
1 row in set (0.00 sec) 3)执行reset master
root@localhost [(none)] 15:50:52>reset master;
Query OK, 0 rows affected (0.04 sec) root@localhost [(none)] 15:53:18>show master status\G
*************************** 1. row ***************************
File: my3307_binlog.000001
Position: 154
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec) 4)执行GTID_PURGED
root@localhost [(none)] 15:56:32>set session sql_log_bin = 0;
root@localhost [(none)] 15:56:53>set global gtid_purged='3a068bf8-cdeb-11e8-8176-080027b0b461:1-10';
root@localhost [(none)] 15:57:58>set session sql_log_bin = 1;
  1. 配置主从
执行help change master to 可以获取change master to命令

CHANGE MASTER TO
MASTER_HOST='192.168.56.100',
MASTER_USER='repl',
MASTER_PASSWORD='wanbin',
MASTER_PORT=3307,
master_auto_position=1;
  1. 开始主从复制
start slave;

#如果想分别指定启动线程,可以使用如下命令
START SLAVE IO_THREAD;
START SLAVE SQL_THREAD; #同样关闭命令:
STOP SLAVE; #分别关闭命令:
STOP SLAVE IO_THREAD;
STOP SLAVE SQL_THREAD;

4. 使用gtid进行复制的限制

由于基于GTID的复制依赖于事务,因此在使用时不支持MySQL中可用的某些功能。本节提供有关使用GTID进行复制的限制和限制的信息。

4.1 非事务性存储引擎的更新

使用GTID时,使用非事务性存储引擎(如MyISAM)对表的更新不能在与使用事务性存储引擎(如InnoDB)的表的更新相同的语句或事务中进行。

此限制是由于对使用非事务性存储引擎的表的更新与对同一事务中使用事务存储引擎的表的更新混合可能导致将多个GTID分配给同一事务。

当master和slave使用不同的存储引擎用于同一个表的相应版本时,也会发生这样的问题,其中一个存储引擎是事务性的而另一个不是。 还要注意,定义为在非事务性表上运行的触发器可能是导致这些问题的原因。

在刚刚提到的任何一种情况下,事务和GTID之间的一对一对应关系被破坏,结果是基于GTID的复制无法正常运行。

4.2 CREATE TABLE … SELECT 语句

CREATE TABLE … SELECT对于基于语句的复制是不安全的。 使用基于行的复制时,此语句实际上记录为两个单独的事件 - 一个用于创建表,另一个用于将源表中的行插入刚刚创建的新表中。 当在事务中执行此语句时,在某些情况下,这两个事件可能会接收相同的事务标识符,这意味着slave将跳过包含插入的事务。 因此,使用基于GTID的复制时不支持CREATE TABLE … SELECT。

4.3 临时表

使用GTID时(即,enforce_gtid_consistency系统变量设置为ON时),事务,过程,函数和触发器内不支持CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE语句。 可以在启用GTID的情况下使用这些语句,但仅限于任何事务之外,并且仅使用autocommit = 1。

4.4 防止执行不受支持的语句

要防止执行会导致基于GTID的复制失败的语句,必须在启用GTID时使用–enforce-gtid-consistency选项启动所有服务器。

4.5 跳过事务

使用GTID时不支持sql_slave_skip_counter。 如果您需要跳过事务,请使用master的gtid_executed变量的值; 有关详细信息,请参考

https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-failover.html#replication-gtids-failover-empty

4.6 Ignoring servers

使用GTID时,不推荐使用CHANGE MASTER TO语句的IGNORE_SERVER_IDS选项,因为已经应用的事务会自动被忽略。 在启动基于GTID的复制之前,请检查并清除之前在相关服务器上设置的所有忽略的服务器ID列表。 可以为各个通道发出的SHOW_SLAVE_STATUS语句显示已忽略的服务器ID列表(如果有)。 如果没有列表,则Replicate_Ignore_Server_Ids字段为空。

4.7 GTID mode and mysqldump

如果目标服务器的二进制日志中没有GTID,则可以将使用mysqldump创建的转储导入到启用了GTID模式的MySQL服务器中。

4.8 GTID mode and mysql_upgrade

当服务器在启用全局事务标识符(GTID)的情况下运行时(gtid_mode = ON),请不要通过mysql_upgrade启用二进制日志记录(–write-binlog选项)。

MySQL 使用GTID进行复制的更多相关文章

  1. MYSQL 基于GTID的复制

    1.概述 从MYSQL5.6 开始,mysql开始支持GTID复制. 基于日志点复制的缺点: 从那个二进制日志的偏移量进行增量同步,如果指定错误会造成遗漏或者重复,导致数据不一致. 基于GTID复制: ...

  2. 解决mysql开启GTID主从同步出现1236错误问题【转】

    最近遇到mysql开启gtid做复制时,从库出现1236错误,导致同步无法进行,本文就这问题记录下处理步骤,有关gtid知识在这里不做介绍,mysql版本为5.7.16. 一.错误原因分析 错误信息如 ...

  3. 解决mysql开启GTID主从同步出现1236错误问题

    解决mysql开启GTID主从同步出现1236错误问题     最近遇到mysql开启gtid做复制时,从库出现1236错误,导致同步无法进行,本文就这问题记录下处理步骤,有关gtid知识在这里不做介 ...

  4. MySQL的GTID复制与传统复制的相互转换

    主库:192.168.225.128:3307从库1:192.168.225.129:3307 Gtid作为5.6版本以来的杀手级特性,却因为不支持拓扑结构内开关而饱受诟病.如果你需要从未开启GTID ...

  5. Mysql基于GTID复制模式-运维小结 (完整篇)

    先来看mysql5.6主从同步操作时遇到的一个报错:mysql> change master to master_host='192.168.10.59',master_user='repli' ...

  6. 详解MySQL主从复制实战 - 基于GTID的复制

    基于GTID的复制 简介 基于GTID的复制是MySQL 5.6后新增的复制方式. GTID (global transaction identifier) 即全局事务ID, 保证了在每个在主库上提交 ...

  7. MySQL的GTID复制

    从mysql5.6开始引入全局事务标识符(GTID),即每个事务都有一个唯一的标识符.服务器上的每个事务都被分配一个唯一的事务标识符,这是一个64位非零的数值,根据事务提交的顺序分配.GTID的构成是 ...

  8. mysql的GTID复制和多源复制

    配置基于GTID的复制--------------------------------------------在参数文件/etc/my.cnf增加下面内容:主库master_info_reposito ...

  9. MySQL的GTID复制与传统复制的相互切换

    MySQL的GTID复制与传统复制的相互转换 1. GTID复制转换成传统复制 1.1 环境准备 1.2 停止slave 1.3 查看当前主从状态 1.4 change master 1.5 启动主从 ...

随机推荐

  1. oracle merge 目标表以及源表存在重复列的问题(转)

    SQL> select * from t_source;                                                                      ...

  2. 引入clipboard.js

    引入clipboard.js var clipboardJS = new ClipboardJS('#accept-data'); // 括号内的是选择器

  3. 练习三十:Python回文数判断编程练习。

    说到回文数,大家可能会比较的陌生,但是在我们的日常生活中常会遇到这样的数字,只是你不知道它是回文数罢了. 例如:12321,这组数字就是回文数. 设n是一任意自然数.若将n的各位数字反向排列所得自然数 ...

  4. Ubuntu同时忘记用户密码和root密码

    在设置密码的时候,用到了小键盘,重启后再次用小键盘输入密码时,发现输入的并不是数字,而是其他符号.所以在设置关键信息的时候,小键盘还是得慎用啊. 解决方案: 在引导界面也就是开机倒计时的时候,按下 e ...

  5. 牛客网Java刷题知识点之什么是异常、异常处理的原理是什么、为什么要使用异常、异常体系、运行时异常、普通异常、自定义异常、异常链

    不多说,直接上干货! 在这个世界不可能存在完美的东西,不管完美的思维有多么缜密,细心,我们都不可能考虑所有的因素,这就是所谓的智者千虑必有一失.同样的道理,计算机的世界也是不完美的,异常情况随时都会发 ...

  6. kindeditor 修改上传图片的路径的方法

    默认情况下kindeditor上传的图片在编辑器的根目录/attached/目录下.以日期建一个目录,然后保存文件.有些时候大概我们并不想这样.考虑到更新编辑器,或更换编辑器不太方便.比如我现在想把上 ...

  7. CallContext的LogicalCallContext在多线程环境下面公用变量

    压根名听说过这个类的看这里:如何实现对上下文(Context)数据的统一管理 原来以为CallContext就可以直接在多线程环境下面共享使用的,今天突然想到:Asp.Net环境下面,设置来设置去的, ...

  8. 开机报错 the connected AC adapter has a lower wattage than the recommended model which was shipped with the system。

    机型:联想Thinkpad T410 报错场景:在电脑插上电源充电情况下开机,会自动进入bios setup utility提示你需要重新设置日期时间.date/time 报错提示:The conne ...

  9. 通过Maven构建打包Spring boot,并将config配置文件提取到jar文件外

    如果通过不同的IDE打包,着实会觉得依赖性太大,并且容易出现错误,操作也比较复杂 同时,spring-boot-maven-plugin的使用感觉,相关配置太少,并且无法满足方便部署和运行的需求. 这 ...

  10. hystrix 给方法加断路器

    添加依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>s ...