暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

处理从非GTID到GTID MariaDB数据库集群的复制问题

原创 Krzysztof Ksiazek 2019-12-13
1530

最近,遇到了一个有趣的客户案例,其中涉及MariaDB复制设置。我们花了很多时间研究这个问题,并认为在本博文中与您分享这个问题是值得的。

客户环境描述

问题如下:正在使用旧的(10.x之前的版本)MariaDB服务器,并尝试将数据从该服务器迁移到更新的MariaDB复制设置中。这导致使用Mariabackup重建新复制群集中的从站的问题。为了进行测试,我们在以下环境中重新创建了此行为:
image.png

数据已使用mysqldump从5.5迁移到10.4:

mysqldump --single-transaction --master-data=2 --events --routines sbtest > /root/dump.sql

这使我们能够收集主二进制日志坐标和一致的转储。结果,我们能够调配MariaDB 10.4主节点并设置旧5.5主节点与新10.4节点之间的复制。流量仍在5.5节点上运行。10.4主服务器正在生成GTID,因为它必须将数据复制到10.4从服务器。在深入研究细节之前,让我们快速看一下GTID在MariaDB中的工作方式。

MariaDB和GTID

首先,MariaDB使用与Oracle MySQL不同的GTID格式。它由三个以短划线分隔的数字组成:

0-1-345

首先是复制域,该域允许正确处理多源复制。这与我们的情况无关,因为所有节点都在同一复制域中。第二个数字是生成GTID的节点的服务器ID。第三个是序列号-它随二进制日志中存储的每个事件单调增加。

MariaDB使用多个变量来存储有关在给定节点上执行的GTID的信息。对我们来说最有趣的是:

Gtid_binlog_pos-根据文档,此变量是写入二进制日志的最后一个事件组的GTID。

Gtid_slave_pos-根据文档,此系统变量包含服务器的从属线程应用于数据库的最后一个事务的GTID。

Gtid_current_pos-根据文档,此系统变量包含最后一次应用于数据库的事务的GTID。如果在相应的GTID的SERVER_ID gtid_binlog_pos等于服务器自己 SERVER_ID,并且序列号是比在相应GTID更高 gtid_slave_pos,然后从GTID gtid_binlog_pos将被使用。否则,来自 gtid_slave_pos的GTID将用于该域。

因此,为了清楚起见,gtid_binlog_pos存储了最后一个本地执行的事件的GTID。Gtid_slave_pos通过从服务器线程和执行事件的存储GTID gtid_current_pos节目或者从值gtid_binlog_pos,如果它具有最高的序列号,它有服务器ID或g tid_slave_pos如果它具有最高的序列。请记住这一点。

问题概述

相关变量的初始状态在10.4主服务器上:

MariaDB [(none)]> show global variables like '%gtid%';
 
+-------------------------+----------+
 
| Variable_name           | Value |
 
+-------------------------+----------+
 
| gtid_binlog_pos         | 0-1001-1 |
 
| gtid_binlog_state       | 0-1001-1 |
 
| gtid_cleanup_batch_size | 64       |
 
| gtid_current_pos        | 0-1001-1 |
 
| gtid_domain_id          | 0 |
 
| gtid_ignore_duplicates  | ON |
 
| gtid_pos_auto_engines   | |
 
| gtid_slave_pos          | 0-1001-1 |
 
| gtid_strict_mode        | ON |
 
| wsrep_gtid_domain_id    | 0 |
 
| wsrep_gtid_mode         | OFF |
 
+-------------------------+----------+
 
11 rows in set (0.001 sec)

请注意gtid_slave_pos,从理论上讲,这是没有意义的-它来自同一节点,但来自于从属线程。如果您之前进行了主开关,则可能会发生这种情况。我们就是这样做的-在拥有两个10.4节点的情况下,我们将主服务器从服务器ID为1001的主机切换到服务器ID为1002的主机,然后又切换回1001。

之后,我们将复制配置从5.5配置为10.4,结果如下所示:

MariaDB [(none)]> show global variables like '%gtid%';
 
+-------------------------+-------------------------+
 
| Variable_name           | Value |
 
+-------------------------+-------------------------+
 
| gtid_binlog_pos         | 0-55-117029 |
 
| gtid_binlog_state       | 0-1001-1537,0-55-117029 |
 
| gtid_cleanup_batch_size | 64                      |
 
| gtid_current_pos        | 0-1001-1 |
 
| gtid_domain_id          | 0 |
 
| gtid_ignore_duplicates  | ON |
 
| gtid_pos_auto_engines   | |
 
| gtid_slave_pos          | 0-1001-1 |
 
| gtid_strict_mode        | ON |
 
| wsrep_gtid_domain_id    | 0 |
 
| wsrep_gtid_mode         | OFF |
 
+-------------------------+-------------------------+
 
11 rows in set (0.000 sec)

如您所见,从MariaDB 5.5复制的事件都已在gtid_binlog_pos变量中说明:所有事件的服务器ID为55。这导致了严重的问题。您可能还记得,gtid_binlog_pos应该包含在主机上本地执行的事件。在这里,它包含从具有不同服务器ID的另一台服务器复制的事件。

当您要重建10.4从站时,这使事情变得艰难,这就是原因。就像Xtrabackup一样,Mariabackup的工作方式也很简单。它在扫描重做日志并存储所有传入事务时,从MariaDB服务器复制文件。复制文件后,Mariabackup将使用带有读取锁的FLUSH TABLES或备份锁来冻结数据库,具体取决于MariaDB版本和备份锁的可用性。然后,它读取最新执行的GTID并将其与备份一起存储。然后释放锁并完成备份。备份中存储的GTID应该用作节点上最新执行的GTID。如果重建从站,它将被放置为gtid_slave_pos,然后用于启动GTID复制。该GTID来自gtid_current_pos,这很有意义-毕竟是“应用于数据库的最后一笔交易的GTID”。敏锐的读者已经可以看到问题所在。让我们展示从5.5母版复制10.4时变量的输出:

MariaDB [(none)]> show global variables like '%gtid%';
 
+-------------------------+-------------------------+
 
| Variable_name           | Value |
 
+-------------------------+-------------------------+
 
| gtid_binlog_pos         | 0-55-117029 |
 
| gtid_binlog_state       | 0-1001-1537,0-55-117029 |
 
| gtid_cleanup_batch_size | 64                      |
 
| gtid_current_pos        | 0-1001-1 |
 
| gtid_domain_id          | 0 |
 
| gtid_ignore_duplicates  | ON |
 
| gtid_pos_auto_engines   | |
 
| gtid_slave_pos          | 0-1001-1 |
 
| gtid_strict_mode        | ON |
 
| wsrep_gtid_domain_id    | 0 |
 
| wsrep_gtid_mode         | OFF |
 
+-------------------------+-------------------------+
 
11 rows in set (0.000 sec)

Gtid_current_pos设置为0-1001-1。这绝对不是正确的时间,它取自gtid_slave_pos,而之后有大量来自5.5的交易。问题是那些事务存储为gtid_binlog_pos。另一方面,计算gtid_current_pos的方式是:在gitd_binlog_pos中需要GTID的本地服务器ID 才能用作gtid_current_pos。在我们的例子中,它们具有5.5节点的服务器ID,因此它们不会被正确地视为在10.4主服务器上执行的事件。备份还原后,如果根据备份中存储的GTID状态设置从属,则最终将重新应用来自5.5的所有事件。显然,这将破坏复制。

解决方案

解决此问题的方法是采取其他一些步骤:

  1. 将复制从5.5停止到10.4。在10.4主服务器上运行STOP SLAVE
  2. 在10.4上执行任何交易-如果不存在,请创建模式错误修正-这将改变GTID的情况,如下所示:
MariaDB [(none)]> show global variables like '%gtid%';
 
+-------------------------+---------------------------+
 
| Variable_name           | Value   |
 
+-------------------------+---------------------------+
 
| gtid_binlog_pos         | 0-1001-117122   |
 
| gtid_binlog_state       | 0-55-117121,0-1001-117122 |
 
| gtid_cleanup_batch_size | 64                        |
 
| gtid_current_pos        | 0-1001-117122   |
 
| gtid_domain_id          | 0   |
 
| gtid_ignore_duplicates  | ON   |
 
| gtid_pos_auto_engines   |   |
 
| gtid_slave_pos          | 0-1001-1   |
 
| gtid_strict_mode        | ON   |
 
| wsrep_gtid_domain_id    | 0   |
 
| wsrep_gtid_mode         | OFF   |
 
+-------------------------+---------------------------+
 
11 rows in set (0.001 sec)

最新的GITD是在本地执行的,因此将其存储为gtid_binlog_pos。由于具有本地服务器ID,因此将其选择为gtid_current_pos。现在,您可以备份并使用它来从10.4主服务器上重建从服务器。完成此操作后,再次启动从属线程。

MariaDB知道存在这种错误,不幸的是到目前为止尚未修复。我们发现,此问题影响MariaDB最高为5.5。来自MariaDB 10.0的非GTID事件在10.4上正确地说明为来自从属线程,并且gtid_slave_pos已正确更新。MariaDB 5.5是一个很旧的版本(即使仍受支持),因此您可能仍会看到安装程序正在运行,并尝试从5.5迁移到支持GTID的最新MariaDB版本。更糟糕的是,根据我们发现的错误报告,这也影响了从非MariaDB服务器(Percona Server 5.6上出现的评论提及问题之一)到MariaDB的复制。

无论如何,希望此文章对您有用,并且希望您不会遇到我们刚刚描述的问题。

来源:处理从非GTID到GTID MariaDB数据库集群的复制问题
https://severalnines.com/database-blog/handling-replication-issues-non-gtid-gtid-mariadb-database-clusters

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论