### 23.7.3 NDB群集复制中的已知问题

[](<>)

本节讨论在NDB群集上使用复制时的已知问题。

**源和副本之间的连接丢失。**  [](<>)在源群集SQL节点和副本群集SQL节点之间，或者在源SQL节点和源群集的数据节点之间，可能会发生连接丢失。在后一种情况下，这不仅可能是由于物理连接丢失（例如，网络电缆断开），还可能是由于数据节点事件缓冲区溢出；如果SQL节点响应太慢，它可能会被集群丢弃（通过调整[`MaxBufferedEpochs`](mysql-cluster-ndbd-definition.html#ndbparam-ndbd-maxbufferedepochs)和[`时间间隔`](mysql-cluster-ndbd-definition.html#ndbparam-ndbd-timebetweenepochs)配置参数）。如果发生这种情况，*完全可以将新数据插入源集群，而不必记录在源SQL节点的二进制日志中*。因此，为了保证高可用性，维护备份复制通道、监视主通道以及在必要时故障转移到辅助复制通道以保持副本群集与源同步非常重要。NDB集群的设计目的不是自行执行此类监控；为此，需要外部应用程序。

[](<>) [](<>)在连接或重新连接到源集群时，源SQL节点会发出“间隙”事件。（间隙事件是一种“事件事件”，它表示发生的事件会影响数据库的内容，但不能简单地表示为一组更改。事件的示例包括服务器故障、数据库重新同步、一些软件更新和一些硬件更改。）当复制副本在复制日志中遇到间隙时，它会停止并显示错误消息。此消息可在的输出中获得[`显示副本状态`](show-replica-status.html)（或MySQL 8.0.22之前的版本，[`显示奴隶身份`](show-slave-status.html))，并指示SQL线程由于复制流中注册的事件而停止，需要手动干预。看见[第23.7.8节，“使用NDB群集复制实现故障切换”](mysql-cluster-replication-failover.html)，以获取有关在这种情况下该怎么办的更多信息。

重要的

由于NDB Cluster本身并不是为监视复制状态或提供故障切换而设计的，因此，如果副本服务器或群集需要高可用性，则必须设置多条复制线路，监视源[**mysqld**](mysqld.html)在主复制线路上，并在必要时准备故障转移到辅助线路。这必须手动完成，或者可能通过第三方应用程序完成。有关实现此类设置的信息，请参阅[第23.7.7节，“使用两个复制通道进行NDB群集复制”](mysql-cluster-replication-two-channels.html)和[第23.7.8节，“使用NDB群集复制实现故障切换”](mysql-cluster-replication-failover.html).

如果要从独立的MySQL服务器复制到NDB集群，一个通道通常就足够了。

**循环复制。**  [](<>) [](<>) [](<>)NDB群集复制支持循环复制，如下一个示例所示。复制设置涉及编号为1、2和3的三个NDB群集，其中群集1充当群集2的复制源，群集2充当群集3的源，群集3充当群集1的源，从而完成了循环。每个NDB集群有两个SQL节点，其中SQL节点A和B属于集群1，SQL节点C和D属于集群2，SQL节点E和F属于集群3。

只要满足以下条件，就支持使用这些群集的循环复制：

-   所有源集群和副本集群上的SQL节点都是相同的。

-   作为源和副本的所有SQL节点都是从系统变量开始的[`日志副本更新`](replication-options-binary-log.html#sysvar_log_replica_updates)（来自MySQL 8.0.26）或[`日志_slave _更新`](replication-options-binary-log.html#sysvar_log_slave_updates)（MySQL 8.0.26之前）已启用。

    这种类型的循环复制设置如下图所示：

[](<>)

**图23.32所有源作为副本的NDB群集循环复制**

<img alt="Some content is described in the surrounding text. The diagram shows three clusters, each with two nodes. Arrows connecting SQL nodes in different clusters illustrate that all sources are also replicas." src="images/cluster-circular-replication-1.png" height="883" width="557" />

在这个场景中，集群1中的SQL节点A复制到集群2中的SQL节点C；SQL节点C复制到集群3中的SQL节点E；SQL节点E复制到SQL节点A。换句话说，复制线（由图中的曲线箭头指示）直接连接用作源和副本的所有SQL节点。

还可以设置循环复制，其中并非所有源SQL节点都是副本，如下所示：

[](<>)

**图23.33并非所有源都是副本的NDB群集循环复制**

<img alt="Some content is described in the surrounding text. The diagram shows three clusters, each with two nodes. Arrows connecting SQL nodes in different clusters illustrate that not all sources are replicas." src="images/cluster-circular-replication-2.png" height="887" width="542" />

在这种情况下，每个集群中的不同SQL节点被用作源和副本。然而，你必须*不*使用[`日志副本更新`](replication-options-binary-log.html#sysvar_log_replica_updates)或[`日志_slave _更新`](replication-options-binary-log.html#sysvar_log_slave_updates)系统变量已启用。NDB集群的这种循环复制方案是可能的，其中复制线（图中的曲线箭头再次指示）是不连续的，但应注意的是，尚未对其进行彻底测试，因此必须将其视为实验性的。

笔记

这个[`NDB`](mysql-cluster.html)存储引擎使用幂等执行模式，该模式抑制重复密钥和其他错误，否则会破坏NDB群集的循环复制。这相当于设置系统变量的全局值[`副本执行模式`](replication-options-replica.html#sysvar_replica_exec_mode)或[`从执行模式`](replication-options-replica.html#sysvar_slave_exec_mode)到`幂等元`，尽管这在NDB群集复制中不是必需的，因为NDB群集会自动设置此变量，并忽略任何显式设置它的尝试。

**NDB群集复制和主键。**  [](<>)在节点故障的情况下，复制[`NDB`](mysql-cluster.html)由于在这种情况下可能会插入重复的行，因此仍然可能出现没有主键的表。因此，强烈建议所有[`NDB`](mysql-cluster.html)正在复制的表具有显式主键。

**NDB群集复制和唯一密钥。**  [](<>)在旧版本的NDB群集中，更新[`NDB`](mysql-cluster.html)复制表时可能会导致重复的键错误。这个问题可以通过在[`NDB`](mysql-cluster.html)通过将唯一键检查推迟到所有表行更新完成后，来创建表。

目前，只有[`NDB`](mysql-cluster.html)。因此，从[`NDB`](mysql-cluster.html)到不同的存储引擎，例如[`InnoDB`](innodb-storage-engine.html)或[`米萨姆`](myisam-storage-engine.html)仍然不受支持。

在不延迟检查唯一密钥更新的情况下复制时遇到的问题可以使用[`NDB`](mysql-cluster.html)例如`t`，在源上创建并填充（并传输到不支持延迟唯一密钥更新的副本），如下所示：

```
CREATE TABLE t (
    p INT PRIMARY KEY,
    c INT,
    UNIQUE KEY u (c)
)   ENGINE NDB;

INSERT INTO t
    VALUES (1,1), (2,2), (3,3), (4,4), (5,5);
```

下面[`使现代化`](update.html)声明`t`在源上成功，因为受影响的行是按照`订购人`选项，在整个表格上执行：

```
UPDATE t SET c = c - 1 ORDER BY p;
```

由于行更新的顺序是一次针对一个分区执行的，而不是针对整个表执行的，因此同一语句在副本上出现重复键错误或其他约束冲突时失败。

笔记

每一个[`NDB`](mysql-cluster.html)表在创建时按键进行隐式分区。看见[第24.2.5节，“密钥分区”](partitioning-key.html)，以获取更多信息。

**不支持GTID。**使用全局事务ID的复制与`NDB`存储引擎，不受支持。启用GTID可能会导致NDB群集复制失败。

**不支持多线程副本。**NDB群集不支持多线程副本。这是因为，如果一个数据库中发生的事务是在同一个纪元内写入的，那么复制副本可能无法将它们从另一个数据库中分离出来。此外，由[`NDB`](mysql-cluster.html)存储引擎至少涉及两个数据库：目标数据库和`mysql`系统数据库，因为需要更新`mysql。ndb_应用_状态`表（见[第23.7.4节，“NDB群集复制模式和表”](mysql-cluster-replication-schema.html))。这反过来又打破了多线程的要求，即事务特定于给定数据库。

在NDB 8.0.26之前，设置与多线程副本相关的任何系统变量，例如[`复制并行工作人员`](replication-options-replica.html#sysvar_replica_parallel_workers)或[`奴隶工人`](replication-options-replica.html#sysvar_slave_parallel_workers)和[`副本检查点组`](replication-options-replica.html#sysvar_replica_checkpoint_group)或[`slave_checkpoint_组`](replication-options-replica.html#sysvar_slave_checkpoint_group)（或同等标准）[**mysqld**](mysqld.html)启动选项）被完全忽略，没有任何效果。

在NDB 8.0.27及更高版本中，`复制并行工作人员`必须设置为0。如果在启动时设置为任何其他值，`NDB`将其更改为0，并将消息写入[**mysqld**](mysqld.html)服务器日志文件。

**重新启动时使用--initial。**  [](<>)使用[`--首字母`](mysql-cluster-programs-ndbd.html#option_ndbd_initial)选项使GCI和历元编号的顺序从`0`（这通常适用于NDB集群，不限于涉及集群的复制场景。）在这种情况下，参与复制的MySQL服务器应该重新启动。之后，你应该使用[`重置主机`](reset-master.html)和[`重置副本`](reset-replica.html)（或MySQL 8.0.22之前的版本，[`重置从机`](reset-slave.html))清除无效数据的语句`ndb_binlog_索引`和`ndb_应用_状态`分别是表。

[](<>)**从NDB复制到其他存储引擎。**有可能复制一个[`NDB`](mysql-cluster.html)将源上的表转换为副本上使用不同存储引擎的表，并考虑以下限制：

-   不支持多源和循环复制（源和副本上的表都必须使用[`NDB`](mysql-cluster.html)存储引擎（以使其工作）。

-   使用不对副本上的表执行二进制日志记录的存储引擎需要特殊处理。

-   对副本上的表使用非事务存储引擎也需要特殊处理。

-   源头[**mysqld**](mysqld.html)必须从[`--ndb日志更新为write=0`](mysql-cluster-options-variables.html#option_mysqld_ndb-log-update-as-write)或`--ndb日志更新为注销=注销`.

    接下来的几段提供了关于刚才描述的每个问题的附加信息。

**将NDB复制到其他存储引擎时不支持多个源。**用于从复制[`NDB`](mysql-cluster.html)对于不同的存储引擎，两个数据库之间的关系必须是一对一的。这意味着NDB群集和其他存储引擎之间不支持双向或循环复制。

此外，在两个复制通道之间进行复制时，不可能配置多个复制通道[`NDB`](mysql-cluster.html)还有一个不同的存储引擎。（NDB集群数据库）*可以*同时复制到多个NDB群集数据库。）如果来源使用[`NDB`](mysql-cluster.html)表中，仍然可以让多个MySQL服务器维护所有更改的二进制日志，但对于要更改源的副本（故障转移），必须在副本上显式定义新的源-副本关系。

**将NDB表复制到不执行二进制日志记录的存储引擎。**  [](<>)如果试图从NDB群集复制到使用不处理其自身二进制日志记录的存储引擎的副本，复制过程将中止，并出现“无法进行二进制日志记录”错误。。。语句不能以原子方式编写，因为涉及多个引擎，并且至少有一个引擎是自记录的（错误1595）。可以通过以下方式之一解决此问题：

-   **关闭复制副本上的二进制日志记录。**这可以通过设置[`sql_log_bin=0`](replication-options-binary-log.html#sysvar_sql_log_bin).

-   **更改用于mysql的存储引擎。ndb\_申请\_状态表。**使此表使用不处理其自身二进制日志记录的引擎也可以消除冲突。这可以通过发布以下声明来实现：[`改变表mysql。ndb_应用_状态引擎=MyISAM`](alter-table.html)在复制品上。在使用存储引擎而非[`NDB`](mysql-cluster.html)在副本上，因为您不需要担心保持多个副本同步。

-   **过滤对mysql的更改。ndb\_申请\_复制副本上的状态表。**这可以通过使用启动复制副本来完成[`--replicate ignore table=mysql。ndb_应用_状态`](replication-options-replica.html#option_mysqld_replicate-ignore-table)。如果复制需要忽略其他表，您可能希望使用适当的[`--复制野生忽略表`](replication-options-replica.html#option_mysqld_replicate-wild-ignore-table)而不是选择。

重要的

你应该*不*禁用的复制或二进制日志记录`mysql。ndb_应用_状态`或者在从一个NDB群集复制到另一个NDB群集时更改用于此表的存储引擎。看见[NDB集群之间具有复制功能的复制和二进制日志过滤规则](mysql-cluster-replication-issues.html#mysql-cluster-replication-issues-filtering)，以获取详细信息。

[](<>)**从NDB复制到非事务存储引擎。**当从[`NDB`](mysql-cluster.html)到非事务存储引擎，例如[`米萨姆`](myisam-storage-engine.html)，复制时可能会遇到不必要的重复密钥错误[`插入关于重复密钥更新`](insert-on-duplicate.html)声明。可以使用[`--ndb日志更新为write=0`](mysql-cluster-options-variables.html#option_mysqld_ndb-log-update-as-write)，强制将更新记录为写入，而不是更新。

[](<>)**复制和二进制日志过滤规则，以及NDB群集之间的复制。**如果您正在使用任何选项`--复制-*`, `--复制忽略-*`, [`--binlog do db`](replication-options-binary-log.html#option_mysqld_binlog-do-db)或[`--binlog忽略数据库`](replication-options-binary-log.html#option_mysqld_binlog-ignore-db)要筛选正在复制的数据库或表，必须注意不要阻止数据库或表的复制或二进制日志记录`mysql。ndb_应用_状态`，这是NDB群集之间的复制正常运行所必需的。特别是，你必须记住以下几点：

1.  使用[`--复制do数据库=*`db\_名称`*`](replication-options-replica.html#option_mysqld_replicate-do-db)（除此之外`--复制-*`或`--复制忽略-*`选项）意味着*只有*数据库中的表*`db_名称`*都是复制的。在这种情况下，还应该使用[`--复制do db=mysql`](replication-options-replica.html#option_mysqld_replicate-do-db), [`--binlog do db=mysql`](replication-options-binary-log.html#option_mysqld_binlog-do-db)或[`--replicate do table=mysql。ndb_应用_状态`](replication-options-replica.html#option_mysqld_replicate-do-table)为了确保`mysql。ndb_应用_状态`在副本上填充。

    使用[`--binlog do db=*`db\_名称`*`](replication-options-binary-log.html#option_mysqld_binlog-do-db)（除此之外[`--binlog do db`](replication-options-binary-log.html#option_mysqld_binlog-do-db)选项）意味着*只有*到数据库中的表*`db_名称`*写入二进制日志。在这种情况下，还应该使用[`--复制do db=mysql`](replication-options-replica.html#option_mysqld_replicate-do-db), [`--binlog do db=mysql`](replication-options-binary-log.html#option_mysqld_binlog-do-db)或[`--replicate do table=mysql。ndb_应用_状态`](replication-options-replica.html#option_mysqld_replicate-do-table)为了确保`mysql。ndb_应用_状态`在副本上填充。

2.  使用[`--复制忽略db=mysql`](replication-options-replica.html#option_mysqld_replicate-ignore-db)也就是说没有桌子`mysql`数据库被复制。在这种情况下，还应该使用[`--replicate do table=mysql。ndb_应用_状态`](replication-options-replica.html#option_mysqld_replicate-do-table)为了确保`mysql。ndb_应用_状态`是复制的。

    使用[`--binlog ignore db=mysql`](replication-options-binary-log.html#option_mysqld_binlog-ignore-db)意味着中的表没有更改`mysql`数据库被写入二进制日志。在这种情况下，还应该使用[`--replicate do table=mysql。ndb_应用_状态`](replication-options-replica.html#option_mysqld_replicate-do-table)为了确保`mysql。ndb_应用_状态`是复制的。

    您还应该记住，每个复制规则都需要以下条件：

3.  它自己的`--复制-*`或`--复制忽略-*`选项，并且不能在单个复制筛选选项中表达多个规则。有关这些规则的信息，请参阅[第17.1.6节，“复制和二进制日志记录选项和变量”](replication-options.html).

4.  它自己的[`--binlog do db`](replication-options-binary-log.html#option_mysqld_binlog-do-db)或[`--binlog忽略数据库`](replication-options-binary-log.html#option_mysqld_binlog-ignore-db)选项，并且不能在单个二进制日志筛选选项中表达多个规则。有关这些规则的信息，请参阅[第5.4.4节，“二进制日志”](binary-log.html).

    如果要将NDB群集复制到使用存储引擎而不是[`NDB`](mysql-cluster.html)如本节其他部分所述，上述考虑可能不适用。

[](<>)**NDB群集复制和IPv6。**从NDB 8.0.22开始，所有类型的NDB集群节点都支持IPv6；这包括管理节点、数据节点和API或SQL节点。

在NDB 8.0.22之前，NDB API和MGM API（以及数据节点和管理节点）不支持IPv6，尽管MySQL服务器（包括在NDB集群中充当SQL节点的服务器）可以使用IPv6与其他MySQL服务器联系。在8.0.22之前的NDB Cluster版本中，您可以使用IPv6在集群之间进行复制，以连接充当源和副本的SQL节点，如下图中的虚线箭头所示：

[](<>)

**图23.34使用IPv6连接的SQL节点之间的复制**

<img alt="Most content is described in the surrounding text. The dotted line representing a MySQL-to-MySQL IPv6 connection is between two nodes, one each from the source and replica clusters. All connections within the cluster, such as data node to data node or data node to management node, are connected with solid lines to indicate IPv4 connections only." src="images/cluster-replication-ipv6.png" height="426" width="516" />

在NDB 8.0.22之前，所有连接都源自*在内部*NDB集群（在上图中用实心箭头表示）必须使用IPv4。换句话说，所有NDB群集数据节点、管理服务器和管理客户端都必须可以通过IPv4相互访问。此外，SQL节点必须使用IPv4与集群通信。在NDB 8.0.22及更高版本中，这些限制不再适用；此外，使用NDB和MGM API编写的任何应用程序都可以在只使用IPv6的环境下编写和部署。

**属性升级和降级。**NDB群集复制包括对属性升级和降级的支持。后者的实现区分有损和无损类型转换，它们在副本上的使用可以通过设置系统变量的全局值来控制[`副本类型转换`](replication-options-replica.html#sysvar_replica_type_conversions)（来自MySQL 8.0.26）或[`从属类型转换`](replication-options-replica.html#sysvar_slave_type_conversions)（MySQL 8.0.26之前）。

有关NDB集群中属性升级和降级的更多信息，请参阅[基于行的复制：属性升级和降级](replication-features-differing-tables.html#replication-features-attribute-promotion).

`NDB`不像[`InnoDB`](innodb-storage-engine.html)或[`米萨姆`](myisam-storage-engine.html)，不会将对虚拟列的更改写入二进制日志；但是，这对NDB群集复制或之间的复制没有不利影响`NDB`以及其他存储引擎。记录对存储的生成列的更改。
