MySQL 包含一些用于基于 GTID 的复制的内置(本机)函数。这些功能如下:
-
GTID_SUBSET(
set1
,set2
) 给定两组全局事务标识符
set1
和set2
,如果所有 GTIDset1
也在 中 ,则返回 trueset2
。否则返回假。-
GTID_SUBTRACT(
set1
,set2
) 给定两组全局事务标识符
set1
和set2
,仅返回那些不在set1
中 的 GTIDset2
。-
WAIT_FOR_EXECUTED_GTID_SET(
gtid_set
[,timeout
]) 等到服务器应用了全局事务标识符包含在 中的所有事务
gtid_set
。可选的超时会在指定的秒数过去后停止函数等待。-
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(
gtid_set
[,timeout
][,channel
]) 类似
WAIT_FOR_EXECUTED_GTID_SET(),
但对于单个启动的复制通道。改为使用WAIT_FOR_EXECUTED_GTID_SET()
以确保在所有状态下覆盖所有频道。
有关这些函数的详细信息,请参阅 第 12.19 节,“与全局事务标识符 (GTID) 一起使用的函数”。
您可以定义自己的存储函数来使用 GTID。有关定义存储函数的信息,请参阅
第 23 章,存储对象。以下示例显示了一些有用的存储函数,这些函数可以基于内置
函数GTID_SUBSET()
和
GTID_SUBTRACT()
函数创建。
注意,在这些存储函数中,已经使用delimiter命令将MySQL语句分隔符改为竖线,如下:
mysql> delimiter |
所有这些函数都将 GTID 集的字符串表示形式作为参数,因此在与它们一起使用时必须始终引用 GTID 集。
如果两个 GTID 集是同一组,即使它们的格式不同,此函数也会返回非零值 (true)。
CREATE FUNCTION GTID_IS_EQUAL(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS INT
RETURN GTID_SUBSET(gtid_set_1, gtid_set_2) AND GTID_SUBSET(gtid_set_2, gtid_set_1)|
如果两个 GTID 集不相交,则此函数返回非零值 (true)。
CREATE FUNCTION GTID_IS_DISJOINT(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS INT
RETURN GTID_SUBSET(gtid_set_1, GTID_SUBTRACT(gtid_set_1, gtid_set_2))|
如果两个 GTID 集不相交,并且sum
是两个集的并集,则此函数返回非零值 (true)。
CREATE FUNCTION GTID_IS_DISJOINT_UNION(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT, sum LONGTEXT)
RETURNS INT
RETURN GTID_IS_EQUAL(GTID_SUBTRACT(sum, gtid_set_1), gtid_set_2) AND
GTID_IS_EQUAL(GTID_SUBTRACT(sum, gtid_set_2), gtid_set_1)|
此函数返回 GTID 集的规范化形式,全部大写,没有空格,也没有重复项。UUID 按字母顺序排列,间隔按数字顺序排列。
CREATE FUNCTION GTID_NORMALIZE(g LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(g, '')|
此函数返回两个 GTID 集的并集。
CREATE FUNCTION GTID_UNION(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_NORMALIZE(CONCAT(gtid_set_1, ',', gtid_set_2))|
此函数返回两个 GTID 集的交集。
CREATE FUNCTION GTID_INTERSECTION(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gtid_set_1, GTID_SUBTRACT(gtid_set_1, gtid_set_2))|
该函数返回两个GTID集合之间的对称差异,即存在于
gtid_set_1
但不
存在的GTID,以及存在于但不
gtid_set_2
存在的GTID
。
gtid_set_2
gtid_set_1
CREATE FUNCTION GTID_SYMMETRIC_DIFFERENCE(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(CONCAT(gtid_set_1, ',', gtid_set_2), GTID_INTERSECTION(gtid_set_1, gtid_set_2))|
此函数从 GTID 集中删除来自指定来源的所有 GTID,并返回剩余的 GTID(如果有)。UUID 是发起事务的服务器使用的标识符,通常是
server_uuid
值。
CREATE FUNCTION GTID_SUBTRACT_UUID(gtid_set LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gtid_set, CONCAT(UUID, ':1-', (1 << 63) - 2))|
此函数反转前面列出的函数,仅返回 GTID 集中源自具有指定标识符 (UUID) 的服务器的那些 GTID。
CREATE FUNCTION GTID_INTERSECTION_WITH_UUID(gtid_set LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gtid_set, GTID_SUBTRACT_UUID(gtid_set, uuid))|
示例 16.1 验证副本是否是最新的
内置函数GTID_SUBSET
可
GTID_SUBTRACT
用于检查副本是否至少应用了源已应用的每个事务。
要使用 执行此检查GTID_SUBSET
,请在副本上执行以下语句:
SELECT GTID_SUBSET(source_gtid_executed, replica_gtid_executed)
如果返回 0 (false),则 中的某些 GTID
source_gtid_executed
不存在于 中replica_gtid_executed
,因此源应用了一些副本未应用的事务,因此副本不是最新的。
要使用 执行检查GTID_SUBTRACT
,请在副本上执行以下语句:
SELECT GTID_SUBTRACT(source_gtid_executed, replica_gtid_executed)
此语句返回任何在
source_gtid_executed
但不在中的
GTID replica_gtid_executed
。如果返回任何 GTID,则源应用了一些副本未应用的事务,因此副本不是最新的。
示例 16.2 备份和恢复场景
存储的函数GTID_IS_EQUAL
、
GTID_IS_DISJOINT
和
GTID_IS_DISJOINT_UNION
可用于验证涉及多个数据库和服务器的备份和恢复操作。在此示例场景中,
server1
包含 database
db1
,并且server2
包含 database db2
。目标是将数据库复制
db2
到server1
,结果server1
应该是两个数据库的并集。使用的过程是
server2
使用mysqlpump或
mysqldump进行备份,然后在
server1
.
如果备份程序的选项
--set-gtid-purged
设置为
ON
或默认值AUTO
,则程序的输出包含一条SET
@@GLOBAL.gtid_purged
语句,将
gtid_executed
集合 from
添加server2
到
gtid_purged
集合 on
server1
。该
gtid_purged
集合包含已在服务器上提交但不存在于服务器上的任何二进制日志文件中的所有事务的 GTID。将数据库db2
复制到
server1
时,提交的事务的 GTID(server2
不在 上的二进制日志文件中server1
)必须添加到gtid_purged
集合中
server1
才能使集合完整。
存储的函数可用于协助执行此场景中的以下步骤:
用于
GTID_IS_EQUAL
验证备份操作是否为SET @@GLOBAL.gtid_purged
语句计算了正确的 GTID 集。在 上 ,从mysqlpump或mysqldumpserver2
输出中提取该语句 ,并将 GTID 集存储到局部变量中,例如. 然后执行如下语句:$gtid_purged_set
server2> SELECT GTID_IS_EQUAL($gtid_purged_set, @@GLOBAL.gtid_executed);
如果结果为 1,则两个 GTID 集合相等,并且该集合已被正确计算。
用于
GTID_IS_DISJOINT
验证mysqlpump或 mysqldumpgtid_executed
输出中设置的 GTID 是否与 上的设置 重叠server1
。如果有任何重叠,由于某种原因在两台服务器上都存在相同的 GTID,则复制数据库db2
会server1
产生错误。如上所述,要检查、onserver1
、提取gtid_purged
集合并将其从输出中存储到局部变量中,然后执行以下语句:server1> SELECT GTID_IS_DISJOINT($gtid_purged_set, @@GLOBAL.gtid_executed);
如果结果为 1,则两个 GTID 集之间没有重叠,因此不存在重复的 GTID。
用于
GTID_IS_DISJOINT_UNION
验证还原操作是否在 上产生了正确的 GTID 状态server1
。在恢复备份之前,在 上,通过执行以下语句server1
获取现有 集:gtid_executed
server1> SELECT @@GLOBAL.gtid_executed;
将结果存储在局部变量
$original_gtid_executed
中。还gtid_purged
如上所述将集合存储在局部变量中。当备份从server2
恢复到 上server1
时,执行以下语句以验证 GTID 状态:server1> SELECT GTID_IS_DISJOINT_UNION($original_gtid_executed, $gtid_purged_set, @@GLOBAL.gtid_executed);
如果结果为 1,则存储函数已验证来自 ( ) 的原始 集合
gtid_executed
和来自server1
($original_gtid_executed
)gtid_purged
添加的集合没有重叠,并且现在更新 的集合 由先前的 集合 from 加上来自的 集合组成 ,这是期望的结果。确保在 上进行任何进一步交易之前执行此检查,否则集合中的新交易会 导致失败。server2
$gtid_purged_set
gtid_executed
server1
gtid_executed
server1
gtid_purged
server2
server1
gtid_executed
示例 16.3 为手动故障转移选择最新的副本
存储函数GTID_UNION
可用于从一组副本中识别最新的副本,以便在复制源服务器意外停止后执行手动故障转移操作。如果某些副本遇到复制延迟,则可以使用此存储函数计算最新的副本,而无需等待所有副本应用其现有的中继日志,从而最大限度地减少故障转移时间。该函数可以返回
gtid_executed
每个副本上的集合与副本接收到的交易集合的并集,该集合记录在性能模式表中
replication_connection_status
. 您可以比较这些结果以找出哪个副本的事务记录是最新的,即使尚未提交所有事务。
在每个副本上,通过发出以下语句来计算交易的完整记录:
SELECT GTID_UNION(RECEIVED_TRANSACTION_SET, @@GLOBAL.gtid_executed)
FROM performance_schema.replication_connection_status
WHERE channel_name = 'name';
然后你可以比较每个副本的结果,看看哪个副本有最新的事务记录,并使用这个从服务器作为新的复制源服务器。
示例 16.4 检查副本上的无关事务
存储的函数GTID_SUBTRACT_UUID
可用于检查副本是否已收到并非源自其指定来源的交易。如果有,则可能是您的复制设置或代理、路由器或负载平衡器有问题。此函数的工作原理是从 GTID 集中删除来自指定原始服务器的所有 GTID,并返回剩余的 GTID(如果有)。
对于具有单一来源的副本,发出以下语句,给出原始来源的标识符,通常是
server_uuid
值:
SELECT GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed, server_uuid_of_source);
如果结果不为空,则返回的交易是不是来自指定来源的额外交易。
对于多源复制拓扑中的副本,重复该功能,例如:
SELECT GTID_SUBTRACT_UUID(GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed,
server_uuid_of_source_1),
server_uuid_of_source_2);
如果结果不为空,则返回的交易是并非来自任何指定来源的额外交易。
示例 16.5 验证复制拓扑中的服务器是只读的
存储的函数
GTID_INTERSECTION_WITH_UUID
可用于验证服务器没有发起任何 GTID 并且处于只读状态。该函数仅返回来自具有指定标识符的服务器的 GTID 集中的那些 GTID。如果服务器集合中的任何事务
gtid_executed
具有服务器自己的标识符,则服务器本身会发起这些事务。您可以在服务器上发出以下语句进行检查:
SELECT GTID_INTERSECTION_WITH_UUID(@@GLOBAL.gtid_executed, my_server_uuid);
示例 16.6 验证多源复制设置中的附加副本
存储的函数
GTID_INTERSECTION_WITH_UUID
可用于查明附加到多源复制设置的副本是否应用了源自一个特定源的所有事务。在这种情况下,source1
和source2
既是来源又是副本,并且相互复制。source2
也有自己的复制品。source1
副本还接收并应用来自ifsource2
配置为的
事务,但如果使用
log_slave_updates=ON
则它不会这样做。不管怎样,我们目前只想知道副本是否是最新的。在这种情况下,存储函数
source2
log_slave_updates=OFF
source2
GTID_INTERSECTION_WITH_UUID
可用于识别source2
起源的事务,丢弃
source2
从复制
的事务source1
。GTID_SUBSET
然后可以使用内置函数
将结果gtid_executed
与副本上的集合进行比较。如果副本是最新的
source2
,
gtid_executed
则副本上的集合包含交集中的所有事务(源自 的事务
source2
)。
要执行此检查,请将source2
的
gtid_executed
集合、
source2
的服务器 UUID 和副本的
gtid_executed
集合存储到客户端变量中,如下所示:
$source2_gtid_executed :=
source2> SELECT @@GLOBAL.gtid_executed;
$source2_server_uuid :=
source2> SELECT @@GLOBAL.server_uuid;
$replica_gtid_executed :=
replica> SELECT @@GLOBAL.gtid_executed;
然后使用GTID_INTERSECTION_WITH_UUID
and
GTID_SUBSET
with 这些变量作为输入,如下:
SELECT GTID_SUBSET(GTID_INTERSECTION_WITH_UUID($source2_gtid_executed,
$source2_server_uuid),
$replica_gtid_executed);
服务器标识符 from source2
( $source2_server_uuid
) 用于
GTID_INTERSECTION_WITH_UUID
识别和仅返回那些源自source2
的
gtid_executed
集合的 GTID source2
,忽略那些源自的 GTID source1
。然后将生成的 GTID 集与副本上所有已执行的 GTID 集进行比较,使用GTID_SUBSET
. 如果此语句返回非零值 (true),则来自(第一组输入)的所有已识别 GTID
source2
也在副本的gtid_executed
集合(第二组输入)中,这意味着副本已复制了源自 的所有事务
source2
。