ITPub博客

首页 > 数据库 > > 16.1.3 使用全局事务标识符进行复制

16.1.3 使用全局事务标识符进行复制

作者:飘絮絮絮丶 时间:2020-05-11 13:54:48 0 删除 编辑

参考官方文档:
dev.mysql.com/doc/refma




本节介绍使用全局事务标识符(GTID)的基于事务的复制。 在使用GTID时,每个事务都可以被识别和跟踪,因为它是源服务器上提交并由任何slave服务器应用的; 这意味着在启动新的从站或故障转移到新的主站时使用GTID来引用日志文件或这些文件中的位置是没有必要的,这极大地简化了这些任务。 因为基于GTID的复制完全是基于事务的,所以很容易确定主机和从机是否一致; 只要在主设备上承诺的所有事务也都在从设备上进行,两者之间的一致性就能得到保证。 您可以对GTID使用基于语句或基于行的复制(请参见第16.2.1节“复制格式”); 但是,为获得最佳结果,我们建议您使用基于行的格式。


GTID始终保存在master和slave之间。 这意味着您可以通过检查其二进制日志来确定应用于任何slave的任何事务的来源。 另外,一旦给定GTID的事务在给定的服务器上被提交,任何具有相同GTID的后续事务都会被该服务器忽略。 因此,在主站上承诺的事务不能在从站上应用一次,这有助于保证一致性。


本节讨论以下主题:


  • 如何定义和创建GTID,以及它们在MySQL服务器中的表示方式(请参见第16.1.3.1节“GTID格式和存储”)。
  • 设置和启动基于GTID的复制的一般过程(请参见第16.1.3.2节“使用GTID设置复制”)。


  • 使用GTID时配置新复制服务器的建议方法(请参见第16.1.3.3节“将GTID用于故障转移和扩展”)。


  • 使用基于GTID的复制时应注意的限制和限制(请参见第16.1.3.4节“使用GTID复制的限制”)。






16.1.3.1 GTID 格式和存储


全局事务标识符(GTID)是创建的唯一标识符,并与源(主)服务器上提交的每个事务相关联。 此标识符不但是其源自的服务器是唯一的,而且在给定复制拓扑中的所有服务器上都是唯一的。




GTID分配区分在主站上提交的客户端事务和在从站上重现的复制事务。 在主服务器上提交客户端事务时,如果将事务写入二进制日志,则会为其分配新的GTID。 客户事务保证在产生的数字之间无间隙地单调增加GTID。 如果客户端事务未写入二进制日志(例如,因为事务已被过滤掉,或者事务是只读的),在源服务器上不会分配GTID。


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




GTID的自动跳过功能意味着在主站上提交的事务不能在从站上应用c超过一次,这有助于保证一致性。 一旦给定GTID的事务已经在给定的服务器上提交,任何尝试使用相同的GTID执行后续事务的操作都会被该服务器忽略。 没有错误发生,并且事务中没有语句被执行。




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


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


GTID = source_id:transaction_id




source_id标识始发服务器。 通常,服务器的server_uuid用于此目的。 transaction_id是一个顺序号,由该服务器上的事务提交顺序决定; 例如,要提交的第一个事务具有1作为其transaction_id,并且要在同一始发服务器上提交的第十个事务被指定为10的transaction_id。对于事务来说,不可能将0作为序列号GTID。 例如,原来在服务器上使用UUID 3E11FA47-71CA-11E1-9E33-C80AA9429562承诺的第二十三个事务具有此GTID:


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


刚刚显示的示例表示源自MySQL服务器的第一个到第五个事务,其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正在使用时,从机不需要任何非本地数据,例如主机上文件的名称和该文件中的位置。 所有与主设备同步所需的信息都直接从复制数据流中获取。 GTID替换之前所需的文件偏移对,以确定启动,停止或恢复主站和从站之间数据流的点。 因此,不要在CHANGE MASTER TO语句中包含MASTER_LOG_FILE或MASTER_LOG_POS选项,该语句用于指示从设备从给定主设备进行复制; 相反,只需要启用MASTER_AUTO_POSITION选项。




GTID的产生和生命周期由以下步骤组成:


1.事务在主服务器上执行并提交。


此事务使用主服务器的UUID和尚未在此服务器上使用的最小非零事务序列号分配GTID; GTID被写入到master的二进制日志中(紧接在日志中的事务本身之前)


2.在将二进制日志数据发送到从站并存储在从站的中继日志中(使用此过程的已建立机制 - 有关详细信息,请参见第16.2节“复制实现”)后,从站读取GTID并设置其gtid_next的值 系统变量作为这个GTID。 这告诉slave 下一个事务 必须使用此GTID 来log。




注意到slave在会话上下文中设置gtid_next非常重要。




3.从服务器验证此GTID尚未用于在其自己的二进制日志中记录事务。 如果这个GTID没有被使用,那么从设备写入GTID,应用事务并将事务写入其二进制日志。 通过首先读取和检查事务的GTID,在处理事务本身之前,从服务器不仅保证不具有此GTID的以前事务已经应用于从服务器,而且还确保没有其他会话已经读取了该GTID但尚未提交 相关的事务。 换句话说,多个客户端不允许同时应用相同的事务。




4.因为gtid_next不为空,所以从机不会尝试为该事务生成GTID,而是将存储在该变量中的GTID(即从主机获取的GTID)立即写入二进制日志中。


mysql.gtid_executed Table


从MySQL 5.7.5开始,GTID存储在mysql数据库的名为gtid_executed的表中。 对于每个GTID或其所代表的GTID集合,此表中的一行包含始发服务器的UUID以及该集合的起始和结束事务标识; 对于仅引用单个GTID的行,这最后两个值是相同的。


当安装或升级MySQL服务器时,使用类似于此处显示的CREATE TABLE语句创建mysql.gtid_executed表(如果它尚不存在的话):


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表允许从服务器在从服务器上禁用二进制日志记录时使用GTID,并且可以在二进制日志丢失时保留GTID历史记录。




只有在gtid_mode为ON或ON_PERMISSIVE时,GTID才存储在mysql.gtid_executed表中。 GTID位置的存储取决于二进制日志记录是启用还是禁用:

  • 如果禁用二进制日志记录(log_bin为OFF),或者如果禁用log_slave_updates,则服务器将属于每个事务的GTID与事务一起存储在表中。 另外,该表以用户可配置的速率周期性压缩; 这种情况只适用于禁用二进制日志记录或从属更新日志记录的复制从站。 它不适用于复制主服务器,因为在主服务器上,必须启用二进制日志记录才能进行复制。
  • 如果启用二进制日志记录(log_bin为ON),则无论何时二进制日志被轮换或关闭服务器,服务器都会将写入前一个二进制日志的所有事务的GTID写入mysql.gtid_executed表。 这种情况适用于启用了二进制日志记录的复制主节点或复制从节点。


如果服务器意外停止,则当前二进制日志中的一组GTID没有保存在mysql.gtid_executed表中。 在这种情况下,这些GTID会在恢复过程中添加到表中并添加到gtid_executed系统变量中的一组GTID中。


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


mysql.gtid_executed表由RESET MASTER复位。




mysql.gtid_executed表压缩


随着时间的推移,mysql.gtid_executed表可能会被许多行填充,这些行涉及源自同一服务器上的单个GTID,并且其事务ID构成一个序列,类似于此处显示的内容:


mysql> SELECT * FROM mysql.gtid_executed;



如果通过用跨越事务标识符的整个间隔的单个行替换每个这样的行集合来周期性地压缩此表,则可以节省大量的空间,如下所示:
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
|--------------------------------------+----------------+--------------
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 43 |
...


当启用GTID时,服务器会定期在mysql.gtid_executed表上执行这种类型的压缩。 您可以通过设置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的输出中列出,但它可以在线程表中查看为一行,如下所示:


mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G




thread/sql/compress_gtid_table 线程 通常会休眠,直到执行gtid_executed_compression_period事务,然后唤醒以执行前面所述的对mysql.gtid_executed表的压缩。 然后休眠,直到发生另一个gtid_executed_compression_period事务,然后醒来再次执行压缩,无限期地重复此循环。 禁用二进制日志记录时将此值设置为0意味着线程始终处于睡眠状态并且永不会唤醒。





16.1.3.2 使用GTIDs 设置复制




本节介绍在MySQL 5.7中配置和启动基于GTID的复制的过程。 这是一个“冷启动”过程,假定您是首次启动复制主节点,还是可以停止复制主节点; 有关使用来自运行主服务器的GTID设置复制从服务器的信息,请参见第16.1.3.3节“使用GTID进行故障切换和扩展”。 有关在线服务器上更改GTID模式的信息,请参见第16.1.5节“更改联机服务器上的复制模式”。




最简单的GTID复制拓扑的启动过程中的关键步骤(包括一个主站和一个从站)如下所示:


1.如果复制已在运行,则通过将它们设置为只读来同步这两个服务器。


2.停止这两个服务器


3.重新启动两台启用了GTID的服务器并配置正确的选项。


本节后面的示例中将讨论启动服务器所需的mysqld选项。




注意:
server_uuid必须存在才能使GTID正常工作。




4.指示从服务器将主服务器用作复制数据源并使用自动定位。 完成此步骤所需的SQL语句在本节后面的示例中进行了介绍。


5.采取新的备份。 包含没有GTID的事务的二进制日志不能在启用了GTID的服务器上使用,因此在此点之前进行的备份不能用于新配置。


6.启动从站,然后在两台服务器上再次禁用只读模式,以便它们可以接受更新。


在以下示例中,使用MySQL的基于二进制日志位置的复制协议,两台服务器已经作为主服务器和从服务器运行。 如果从新服务器开始,请参见第16.1.2.2节“为复制创建用户”以获取有关为复制连接添加特定用户的信息,以及有关设置server_id的信息,请参见第16.1.2.1节“设置复制主配置” 变量。 以下示例显示如何将mysqld启动选项存储在服务器的选项文件中,请参见第4.2.6节“使用选项文件”以获取更多信息。 或者,您可以在运行mysqld时使用启动选项。


以下大多数步骤都需要使用MySQL root帐户或具有SUPER权限的其他MySQL用户帐户。 mysqladmin shutdown需要SUPER特权或SHUTDOWN特权。




Step1 :同步服务器


只有在不使用GTID的情况下复制服务器时才需要执行此步骤。 对于新服务器,请继续执行步骤3.通过发出以下命令,通过将每个服务器上的read_only系统变量设置为ON来使服务器变为只读:


mysql> SET @@global.read_only = ON;


等待所有正在进行的事务提交或回滚。 然后,让slave赶上master。 在继续之前,确保从服务器已处理所有更新是非常重要的。


如果您将二进制日志用于复制以外的其他任何事情,例如执行时间点备份和还原,请等到您不需要包含那些没有GTID的事务的旧的二进制日志。 理想情况下,等待服务器清除所有二进制日志,并等待任何现有备份到期。




重要:
理解包含没有GTID的事务的日志不能在启用GTID的服务器上使用,这一点很重要。 继续之前,您必须确保没有GTID的事务不存在于拓扑中的任何位置。




步骤2: 停止两个服务器


如下所示,使用mysqladmin停止每台服务器,其中username是具有足够权限关闭服务器的MySQL用户的用户名:


shell> mysqladmin -uusername -p shutdown


然后在提示时提供该用户的密码。






步骤3:启动启用了GTID的两台服务器


要启用基于GTID的复制,必须通过将gtid_mode变量设置为ON启用GTID模式,并启用enforce_gtid_consistency变量以确保只记录对于基于GTID的复制安全的语句。 另外,在配置从站设置之前,您应该使用--skip-slave-start选项启动从站。


由于在MySQL 5.7.5中增加了mysql.gtid_executed表,因此使用GTID,启用二进制日志记录并不重要。 这意味着您可以使用GTID的slave服务器,但不使用二进制日志记录。 为了能够复制,主设备必须始终启用二进制日志记录。 例如,要启动启用了GTID但没有二进制日志记录的从站,请在服务器的选项文件中配置这些变量:


gtid_mode=ON
enforce-gtid-consistency=true


根据您的配置,为mysqld提供更多选项。






步骤4:配置slave以使用基于GTID的自动定位


告诉slave使用基于GTID事务的主数据作为复制数据源,并使用基于GTID的自动定位而不是基于文件的定位。 在slave上发出CHANGE MASTER TO语句,其中包括语句中的MASTER_AUTO_POSITION选项,以告诉slave,master的事务由GTID标识




您可能还需要为主服务器的主机名和端口号以及用于复制用户帐户的用户名和密码提供适当的值,从服务器可以使用该帐户连接主服务器; 如果在步骤1之前已经设置了这些参数,并且不需要做进一步的修改,那么可以从这里显示的语句中安全地省略相应的选项。


mysql> CHANGE MASTER TO > MASTER_HOST = host,
> MASTER_PORT = port,
> MASTER_USER = user,
> MASTER_PASSWORD = password,
> MASTER_AUTO_POSITION = 1;




MASTER_LOG_FILE选项和MASTER_LOG_POS选项都不能与MASTER_AUTO_POSITION设置为1一起使用。尝试这样做会导致CHANGE MASTER TO语句失败并出现错误。




步骤5:完成一个新备份


启用GTID之前创建的现有备份现在不能再用于这些服务器,因为您已启用GTID。 在这一点上做一个新的备份,这样你就不会没有可用的备份。


例如,您可以在要备份的服务器上执行FLUSH LOGS。 然后,明确地进行备份或等待您可能已经设置的任何定期备份例程的下一次迭代。




步骤:启动slave 并禁用只读模式。


mysql> START SLAVE;


只有在步骤1中将服务器配置为只读时,才需要执行以下步骤。要允许服务器再次开始接受更新,请发出以下语句:


mysql> SET @@global.read_only = OFF;




现在应该运行基于GTID的复制,并且可以像以前一样开始(或恢复)主机上的活动。






16.1.3.3 为外部扩展和故障转移 使用GTIDs


将全局事务标识符(GTID)用于MySQL Replication时,有许多技术用于配置新的从站,然后可用于扩展,并根据故障转移的需要提升为主站。 本节介绍以下技术:




全局事务标识符已添加到MySQL复制中,以便简化复制数据流的一般管理,尤其是故障转移活动的一般管理。 每个标识符唯一标识一组构成事务的二进制日志事件。 GTID在将更改应用到数据库中起着关键作用:服务器会自动跳过任何具有服务器识别为之前处理过的标识符的事务。 此行为对于自动复制定位和正确的故障转移至关重要。


在二进制日志中捕获标识符和包含给定事务的事件集合之间的映射。 使用来自其他现有服务器的数据配置新服务器时,这会带来一些挑战。 要重现在新服务器上设置的标识符,必须将标识符从旧服务器复制到新服务器,并保留标识符与实际事件之间的关系。 这对于恢复作为候选者立即可用的从站成为故障切换或切换的新主站是必要的。


简单复制
在新服务器上再现所有标识符和事务的最简单方法是将新服务器置于具有全部执行历史记录的主服务器的从服务器中,并在两台服务器上启用全局事务标识符。


一旦复制启动,新服务器将从主服务器复制整个二进制日志,从而获得有关所有GTID的所有信息。


这种方法简单而有效,但要求从机从主机读取二进制日志; 有时需要较长的时间才能让新的从服务器跟上主服务器,所以这种方法不适用于快速故障切换或从备份恢复。 本节介绍如何通过将二进制日志文件复制到新服务器来避免从主服务器获取所有执行历史记录。




将数据和事务复制到从站。


当源服务器先前处理了大量事务时,执行整个事务历史记录可能非常耗时,而这可能是设置新复制从属服务器时的主要瓶颈。 为了消除这种需求,可以将源服务器包含的数据集,二进制日志和全局事务信息的快照导入到新的从服务器。 源服务器可以是主服务器或从服务器,您必须确保源在复制数据之前处理了所有必需的事务。




这种方法有几种不同的方式,区别在于数据转储和二进制日志事务转移到从服务器的方式,如下所述:


1.数据集:

  • 使用mysql客户端导入使用mysqldump创建的转储文件。 在源服务器上使用--master-data选项来包含二进制日志记录信息和--set-gtid-purged为AUTO(默认)或ON,以包含有关转储中已执行事务的信息。 然后使用mysql客户端在目标服务器上导入转储文件。
  • 使用原始数据文件创建源服务器的数据快照,然后按照第16.1.2.4节“选择数据快照的方法”中的说明将这些文件复制到目标服务器。 如果使用InnoDB表,则可以使用MySQL Enterprise Backup组件中的mysqlbackup命令生成一致的快照。 此命令记录与从站上使用的快照对应的日志名称和偏移量。



  • 停止源服务器和目标服务器,将源数据目录的内容复制到新的从属数据目录,然后重新启动slave服务器。 如果使用此方法,则必须将从站配置为基于GTID的复制,换句话说,使用gtid_mode = ON。





2.事务历史

  • 使用mysqlbinlog将来自源服务器的二进制日志导入到新的从服务器,使用 --read-from-remote-server 和--read-from-remote-master选项。
  • 将源的二进制日志文件复制到slave。 您可以使用mysqlbinlog --read-from-remote-server --raw.。 这些可以通过以下任一方式读入从站:
    • 更新从站的binlog.index文件以指向复制的日志文件。 然后在mysql客户端中执行CHANGE MASTER TO语句以指向第一个日志文件,然后START SLAVE来读取它们。
    • 使用mysqlbinlog>file(不带--raw选项)将二进制日志文件导出到SQL客户端可以处理的SQL文件中。



例如:
shell> mysqlbinlog copied-binlog.000001 copied-binlog.000002 | mysql -u root -p


--也可以参考使用mysqlbinlog 来备份二进制日志文件


这种方法的优点是几乎可以立即提供新的服务器; 只有那些在重播快照或转储文件时提交的事务仍然需要从现有主服务器获取。 这意味着从设备的可用性不是即时的 - 但从设备只需要相对较短的时间就可以赶上这几个剩余的事务。




预先通过二进制日志复制到目标服务器通常比实时从主服务器读取整个事务执行历史记录要快。 但是,由于大小或其他考虑因素,在需要时将这些文件移动到目标可能并不总是可行的。 本节讨论的另外两个用于配置新从站的方法使用其他方法将有关事务的信息传输到新从站。




注入空的事务。


主站的全局gtid_executed变量包含在主站上执行的所有事务的集合。 在拍摄快照以配置新服务器时,不用复制二进制日志,而是注意拍摄快照的服务器上的gtid_executed内容。 在将新服务器添加到复制链之前,只需在新服务器上为主服务器的gtid_executed中包含的每个事务标识符提交一个空事务,如下所示:


SET GTID_NEXT='aaa-bbb-ccc-ddd:N';
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';


一旦所有事务标识符以这种方式使用空事务恢复后,您必须刷新并清除slave服务器的二进制日志,如下所示,其中N是当前二进制日志文件名的非零后缀:


FLUSH LOGS;
PURGE BINARY LOGS TO 'master-bin.00000N';



您应该这样做,以防止此服务器在事后将其提升为主服务器时使用作物的事务复制流。 (FLUSH LOGS语句强制创建新的二进制日志文件; PURGE BINARY LOGS清除空的事务,但保留其标识符。)



这种方法创建了一个基本上是快照的服务器,但随着其二进制日志历史记录与复制流的历史趋于一致(即,它赶上了主服务器或主服务器),该服务器能够成为主服务器。 这一结果与使用剩余供应方法所获得的结果类似,我们在接下来的几段中讨论这一方法。




使用 gtid_purged 排除事务


主站的全局gtid_purged变量包含已从主站的二进制日志中清除的所有事务的集合。 与前面讨论的方法一样(请参阅注入空事务),您可以在从其创建快照的服务器上记录gtid_executed的值(代替将二进制日志复制到新服务器)。 与以前的方法不同,不需要提交空的事务(或者发出PURGE BINARY LOGS); 相反,您可以直接在从属设备上设置gtid_purged,具体取决于从中备份或拍摄快照的服务器上的gtid_executed值
--这个方法简单


与使用空事务的方法一样,此方法创建一个功能上为快照的服务器,但随着其二进制日志历史记录与复制主服务器或组的复制日志历史趋于一致,它可以及时成为主服务器。




重建 GTID模式 slave


当在GTID基础复制设置恢复slave遇到错误时,注入空事务可能无法解决问题,因为事件没有GTID。


使用mysqlbinlog查找下一个事务,这可能是事件发生后的下一个日志文件中的第一个事务。 将所有内容复制到该事务的COMMIT中,确保包含SET @@ SESSION.GTID_NEXT。 即使您没有使用基于行的复制,仍然可以在命令行客户端中运行二进制日志行事件。




停止从服务器并运行您复制的事务。 mysqlbinlog输出将分隔符设置为/ *!* /,因此将其设置回来:


mysql> DELIMITER ;


自动从正确位置重新启动复制:


mysql> SET GTID_NEXT=automatic;
mysql> RESET SLAVE;
mysql> START SLAVE;






16.1.3.4 GTID下的复制限制


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




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




此限制是由于以下事实:对使用非事务性存储引擎的表进行的更新与在同一事务中使用事务性存储引擎的表的更新混合在一起会导致将多个GTID分配给同一事务。




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




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




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


Temporary 表。使用GTID时(即使用--enforce-gtid-consistency选项启动服务器时),事务内部不支持CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE语句。可以在启用GTID的情况下使用这些语句,但只能在任何事务之外使用,并且只能使用autocommit = 1。


防止执行不受支持的语句。为了防止执行会导致基于GTID的复制失败的语句,启用GTID时必须使用--enforce-gtid-consistency选项启动所有服务器。这会导致本节前面讨论的任何类型的语句失败并显示错误。


请注意,如果二进制日志记录发生在语句中,那么--enforce-gtid-consistency才会生效。如果在服务器上禁用了二进制日志记录,或者由于语句被过滤器删除而未将语句写入二进制日志,则未检查或强制执行未记录的语句的GTID一致性。


有关启用GTID时需要的其他启动选项的信息,请参见第16.1.3.2节“使用GTID设置复制”。


使用GTID时,不支持sql_slave_skip_counter。如果您需要跳过事务处理,请改用master的gtid_executed变量的值;有关更多信息,请参阅注入空白事务。


GTID模式和mysqldump。只要目标服务器的二进制日志中没有GTID,就可以将使用mysqldump创建的转储导入启用GTID模式的MySQL服务器。


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




GTID 生命周期


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


1.事务在主服务器上执行并提交。 此客户端事务被分配一个GTID,该GTID由主服务器的UUID和此服务器上尚未使用的最小非零事务序列号组成。 GTID被写入主服务器的二进制日志(紧接在日志中的事务本身之前)。 如果未将客户端事务写入二进制日志(例如,因为事务已被过滤掉,或者事务是只读的),则不会为其分配GTID。




2.如果为事务分配了GTID,则GTID通过在事务开始,自动的在提交的时候将其写入二进制日志(作为Gtid_log_event)保留。 无论何时轮询二进制日志或关闭服务器,服务器都会将写入先前二进制日志文件的所有事务的GTID写入mysql.gtid_executed表。




3.如果为事务分配了GTID,则通过将GTID添加到gtid_executed系统变量(@@ global.gtid_executed)中的GTID集合,非原子的(在提交事务后不久)将GTID外部化。 此GTID集包含所有已提交的GTID事务集的表现。 启用二进制日志记录(根据主服务器的要求),gtid_executed系统变量中的GTID集是应用事务的完整记录,但mysql.gtid_executed表不是,因为最新的历史记录仍在当前二进制日志文件中。




4.在将二进制日志数据传输到从站并存储在从站的中继日志中之后(使用已建立的此过程机制,请参见第16.2节“复制实现”,详细信息),从站读取GTID并设置gtid_next系统变量的值作为此GTID。 这告诉从服务器必须使用此GTID log下一个事务。 请务必注意,slave在会话上下文中设置gtid_next。




5.从站验证,没有线程还在gtid_next中获得GTID的所有权来处理事务。在处理事务本身之前,通过首先读取和检查复制事务的GTID,从设备不仅保证在从设备上没有应用具有此GTID的更早的事务,而且还保证没有其他会话已经读取此GTID但尚未 提交了的事务。 因此,如果多个客户端尝试同时应用同一事务,则服务器只允许其中一个执行,从而解决此问题。 从站的gtid_owned系统变量(@@ global.gtid_owned)显示当前正在使用的每个GTID以及拥有它的线程的ID。 如果已经使用了GTID,则不会引发错误,并且使用自动跳过功能来忽略该事务。




6.如果未使用GTID,则slave应用被复制的事务。 由于gtid_next设置为主服务器已分配的GTID,因此从服务器不会尝试为此事务生成新的GTID,而是使用存储在gtid_next中的GTID。




7.如果在slave 上启用了二进制日志,则GTID通过在事务开始,自动的在提交的时候将其写入二进制日志(作为Gtid_log_event)保留。 无论何时轮询二进制日志或关闭服务器,服务器都会将写入先前二进制日志文件的所有事务的GTID写入mysql.gtid_executed表。




8.如果在从站上禁用了二进制日志记录,则通过将GTID直接写入mysql.gtid_executed表来原子性地保留GTID。 MySQL在事务中附加一条语句,将GTID插入表中。 在这种情况下,mysql.gtid_executed表是从站上应用的事务的完整记录。 请注意,在MySQL 5.7中,将GTID插入表中的操作对于DML语句是原子操作,但对于DDL语句则不是,因此如果服务器在涉及DDL语句的事务之后意外退出,则GTID状态可能会变得不一致。 从MySQL 8.0开始,对于DDL语句和DML语句,操作都是原子操作。



9.在从属设备上提交复制事务后不久,GTID通过将其添加到slave的gtid_executed系统变量(@@ global.gtid_executed)中的GTID集合来完成非原子化外部化。 对于master,此GTID集包含所有已提交的GTID事务集。 如果在从站上禁用了二进制日志记录,则mysql.gtid_executed表也是在从站上应用的事务的完整记录。 如果在从站上启用了二进制日志记录,这意味着某些GTID仅记录在二进制日志中,则gtid_executed系统变量中的GTID集是唯一的完整记录。




在主服务器上完全过滤掉未分配GTID的客户端事务,因此它们不会添加到gtid_executed系统变量中的事务集中,也不会添加到mysql.gtid_executed表中。 但是,在从服务器上完全过滤掉的复制事务将保持不变。 如果在从站上启用了二进制日志记录,则过滤掉的事务将作为Gtid_log_event写入二进制日志,后跟仅包含BEGIN和COMMIT语句的空事务。 如果禁用二进制日志记录,则已过滤掉的事务的GTID将写入mysql.gtid_executed表。 为过滤掉的事务保留GTID可确保可以压缩gtid_executed系统变量中的mysql.gtid_executed表和GTID集。 它还确保如果从站重新连接到主站,则不会再次检索过滤掉的事务。




在多线程复制从站(slave_parallel_workers> 0)上,可以并行应用事务,因此复制的事务可以无序提交(除非设置了slave_preserve_commit_order = 1)。 当发生这种情况时,gtid_executed系统变量中的GTID集合将包含多个GTID范围,它们之间存在间隙。 (在主服务器或单线程复制从服务器上,将会有单调增加的GTID,数字之间没有间隙。)多线程复制从服务器上的间隙仅发生在最近应用的事务中,并在复制过程中填充。 当使用STOP SLAVE语句干净地停止复制线程时,将应用正在进行的事务以填补空白。如果发生关闭(例如服务器故障或使用KILL语句停止复制线程),则可能任然存在间隙。


客户端可以通过在执行事务之前将变量@@ session.gtid_next设置为有效的GTID(由UUID和事务序列号组成,用冒号分隔)来模拟复制的事务。 mysqlbinlog使用此技术生成二进制日志的转储,客户端可以重放该转储以保留GTID。 通过客户端提交的模拟复制事务完全等同于通过复制线程提交的复制事务,并且事后无法区分它们。




gtid_purged


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


  • 在从站上禁用二进制日志记录时提交的复制事务的GTID
  • 已写入已清除的二进制日志文件的事务的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集,并在清除二进制日志文件时维护该集。





GTID 自动-定位




GTID替换先前所需的文件偏移对,以确定启动,停止或恢复主设备和从设备之间的数据流的点。 当使用GTID时,从设备需要与主设备同步的所有信息都直接从复制数据流中获取。




要使用基于GTID的复制启动从站,请不要在CHANGE MASTER TO语句中包含MASTER_LOG_FILE或MASTER_LOG_POS选项,以指示从站从给定主站复制。 这些选项指定日志文件的名称和文件中的起始位置,但是对于GTID,从站不需要这些非本地数据。 相反,您需要启用MASTER_AUTO_POSITION选项。




默认情况下禁用MASTER_AUTO_POSITION选项。 如果在从属设备上启用了多源复制,则需要为每个适用的复制通道设置选项。 再次禁用MASTER_AUTO_POSITION选项会使从站恢复为基于文件的复制,在这种情况下,您还必须指定MASTER_LOG_FILE或MASTER_LOG_POS选项中的一个或两个。




当复制从站启用GTID(GTID_MODE = ON,ON_PERMISSIVE或OFF_PERMISSIVE)并启用MASTER_AUTO_POSITION选项时,将激活自动定位以连接到主站。 主设备必须设置GTID_MODE = ON才能使连接成功。 在初始握手中,从站发送一个GTID集,其中包含已经收到,已提交或两者都已完成的事务。 此GTID集等于gtid_executed系统变量(@@ global.gtid_executed)中GTID集的并集,以及作为接收事务记录在Performance Schema replication_connection_status表中的GTID集(SELECT RECEIVED_TRANSACTION_SET FROM)PERFORMANCE_SCHEMA.replication_connection_status 语句的结果)。




主设备通过发送其GTID不包括在从设备发送的GTID集中的二进制日志中记录的所有事务来响应。 此交换确保主服务器仅使用GTID发送事务,该GTID尚未记录或已提交。 如果从站接收来自多个主站的事务,如菱形拓扑的情况,则自动跳过功能可确保事务不会应用两次。 (自动跳过功能还可确保主设备在初始握手时跳过从设备发送的事务。)




如果主服务器应发送的任何事务已从主服务器的二进制日志中清除,或者通过其他方法添加到gtid_purged系统变量中的GTID集中,则主服务器将错误ER_MASTER_HAS_PURGED_REQUIRED_GTIDS发送给从服务器,并且复制不会开始。 从站无法自动从此错误中恢复,因为已清除了赶上主站所需的部分事务历史记录。 尝试在未启用MASTER_AUTO_POSITION选项的情况下重新连接只会导致从属设备上的已清除事务丢失。 从这种情况中恢复的正确方法是从服务器从另一个源复制丢失的事务,或者从更新的备份创建的新从服务器替换从服务器。 考虑修改主服务器上的二进制日志有效期,以确保不再发生这种情况。




如果在事务交换期间发现从属设备已在GTID中记录或提交了主设备UUID的事务,但主设备本身尚未提交它们,则主设备将错误ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER发送给从设备,并且复制不会启动。 如果将从站设置为新主站,但您尚未验证该从站是否比其他从站更新,则会出现这种情况。 从这种情况中恢复的正确方法是手动检查主服务器和从服务器是否已有偏差,并根据需要对各个事务执行手动冲突解决,或从复制拓扑中删除主服务器或从服务器。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3138929/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-09-09

  • 博文量
    2646
  • 访问量
    42233