25.7.3 NDB 集群复制已知问题
本节讨论使用 NDB 集群 replication 时出现的问题或问题。
源和副本之间的连接丢失 可能会出现源集群 SQL 节点和副本集群 SQL 节点之间的连接丢失,或者是源 SQL 节点和源集群数据节点之间的连接丢失。在后一种情况下,这可能不是由于物理连接中断(例如,网络电缆断开),而是由于数据节点事件缓冲区溢出;如果 SQL 节点响应速度太慢,它可能会被集群drop(这可以通过调整 MaxBufferedEpochs
和 TimeBetweenEpochs
配置参数来控制)。如果出现这种情况,可能会在源集群中插入新数据,而这些数据不被记录到源 SQL 节点的二进制日志中。因此,在确保高可用性时,非常重要的是维护备份复制通道,监控主要通道,并在必要时将副本集群切换到次要复制通道,以保持副本集群与源集群同步。 NDB 集群不设计来自己监控这些问题;因此,需要使用外部应用程序进行监控。
源 SQL 节点在连接或重新连接到源集群时,会发出一个“gap”事件。 (gap 事件是一种类型的“incident event,”,表示数据库内容受到影响的事件,但不能轻松地表示为一组更改。例如,服务器故障、数据库重新同步、某些软件更新和硬件变化等都是这种事件的示例。)当复制节点遇到 replication 日志中的gap 时,它将停止并出现错误信息。这条消息可以在SHOW REPLICA STATUS
的输出中找到,表明 SQL 线程因 replication 流中的事件注册而停止,并且需要人工干预。请参阅第 25.7.8 节“实现 NDB 集群复制故障转移”,了解在这种情况下所需的操作。
由于 NDB 集群本身不设计来监控复制状态或提供故障转移,如果高可用性对副本服务器或集群是一个要求,那么你必须设置多条复制线路,监控源mysqld在主复制线路上,并准备在必要时手动或通过第三方应用程序 fail over 到次要线路。关于实现这种设置的信息,请见第 25.7.7 节,“使用 NDB 集群复制的两个复制通道”和第 25.7.8 节,“使用 NDB 集群复制实现故障转移”。
如果你从独立的 MySQL 服务器到 NDB 集群进行复制,一般来说一个通道就足够了。
循环复制 NDB 集群复制支持循环复制,如下所示。复制设置涉及三个 NDB 集群,编号为 1、2 和 3,其中集群 1 作为集群 2 的 replication 源,集群 2 作为集群 3 的源,集群 3 作为集群 1 的源,从而完成循环。每个 NDB 集群都有两个 SQL 节点,其中 SQL 节点 A 和 B 属于集群 1,SQL 节点 C 和 D 属于集群 2,SQL 节点 E 和 F 属于集群 3。
在这些集群之间使用循环复制是支持的,只要满足以下条件:
-
所有源和副本集中的 SQL 节点相同。
-
所有作为源和副本的 SQL 节点都使用系统变量
log_replica_updates
启动。
这种循环复制设置方式在以下图中展示:
在这个场景中,Cluster 1 中的 SQL 节点 A 复制到 Cluster 2 中的 SQL 节点 C;SQL 节点 C 复制到 Cluster 3 中的 SQL 节点 E;SQL 节点 E 复制回 SQL 节点 A。在其他字词,这个复制线(图中用曲线箭头表示)直接连接所有用于源和副本的 SQL 节点。
也可以设置循环复制,其中不所有源 SQL 节点都是副本,如下所示:
在这个场景中,每个集群中的 SQL 节点都用于源和副本。但是,您不能启动任何 SQL 节点时启用 log_replica_updates
系统变量。这类 NDB 集群循环复制方案,在复制线(图中用曲线箭头表示)断续的情况下,应该是可能的,但是还没有经过充分测试,因此仍然需要被视为实验性质。
NDBNDB存储引擎使用idempotent执行模式,该模式抑制了否则会中断 NDB 集群循环复制的重复键和其他错误。这等同于将系统变量replica_exec_mode设置为IDEMPOTENT,虽然在 NDB 集群复制中,这不是必要的,因为 NDB 集群自动将该变量设置为 IDEMPOTENT 并忽略任何尝试设置它的操作。
NDB 集群复制和主键 在节点故障时,NDB表格没有主键的复制错误仍然可能发生,因为在这种情况下可能会插入重复行。因此,对于被复制的NDB表格,强烈建议添加明确的主键。
NDB Cluster Replication 和唯一键。 在 NDB Cluster 早期版本中,更新 NDB
表的唯一键列可能会在复制过程中导致重复键错误。这一问题在 NDB Cluster 8.4 及更高版本中被解决了,这是通过将唯一键检查延迟到所有表行更新完成后来实现的。
这种延迟约束方式目前仅支持 NDB
。因此,在从 NDB Cluster 复制到其他存储引擎,如 InnoDB
或 MyISAM
时,更新唯一键仍然不受支持。
在没有延迟检查唯一键更新的情况下,可以使用 NDB 表,如 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
语句在源端成功,因为处理的行被按照ORDER BY选项确定的顺序处理,整个表都进行了处理:
UPDATE t SET c = c - 1 ORDER BY p;
同一语句在副本上失败,因为行更新的顺序是对每个分区单独进行的,而不是对整个表进行的,这可能会导致重复键错误或其他约束违规。
每个NDB
表隐式地根据键被分区创建。请参阅第 26.2.5 节,“KEY 分区”,了解更多信息。
NDB 不支持 GTIDs。 NDB 存储引擎不兼容全球事务 ID(GTID)复制,并且不受支持。如果启用 GTIDs,可能会导致 NDB 集群复制失败。
使用--initial重启-cluster 使用--initial
选项重启集群将GCI和epoch号的顺序从0
开始。这通常适用于NDB集群,而不仅限于涉及Cluster的复制场景。参与复制的MySQL服务器应该在这个时候被重启。在这种情况下,您应该使用RESET BINARY LOGS AND GTIDS
和RESET REPLICA
语句来清除无效的ndb_binlog_index
和ndb_apply_status
表 respectively。
NDB到其他存储引擎的复制 可以将NDB表在源端复制到使用不同存储引擎的副本中,考虑以下限制:
-
多源和环形复制不受支持(源端和副本中的表都必须使用
NDB
存储引擎才能工作)。 -
在副本中使用不记录二进制日志的存储引擎需要特殊处理。
-
在副本中使用非事务存储引擎也需要特殊处理。
-
源代码mysqld必须使用
--ndb-log-update-as-write=0
或--ndb-log-update-as-write=OFF
启动。
以下几段文字提供了每个问题的详细信息。
NDB 到其他存储引擎的多源不支持. 在从NDB
到不同的存储引擎进行复制时,两个数据库之间的关系必须是 one-to-one。这意味着 NDB 集群和其他存储引擎之间不支持双向或循环复制。
此外,在从NDB
到不同的存储引擎进行复制时,不可能配置多个复制通道。 (一个 NDB 集群数据库可以同时将数据复制到多个 NDB 集群数据库。)如果源使用NDB
表,仍然可以有多个 MySQL 服务器维护所有更改的二进制日志,但要将源更改为 replica(fail over),必须在 replica 上明确定义新的源-副本关系。
NDB 表复制到不支持二进制日志存储引擎 如果您尝试从 NDB 集群复制到使用不支持自己二进制日志的存储引擎的副本,复制过程将因错误Binary logging not possible ... Statement cannot be written atomically since more than one engine involved and at least one engine is self-logging(Error 1595)而中止。可以通过以下方法解决这个问题:
-
在副本上关闭二进制日志 这可以通过设置
sql_log_bin = 0
来实现。 -
更改 mysql.ndb_apply_status 表的存储引擎 将这个表使用不支持自己二进制日志的存储引擎也可以解决冲突。这可以通过在副本上执行类似于
ALTER TABLE mysql.ndb_apply_status ENGINE=MyISAM
的语句来实现。使用其他存储引擎(除了 NDB)在副本上是安全的,因为您不需要担心多个副本保持同步。 -
过滤 MySQL 中的 mysql.ndb_apply_status 表在复制时的更改 。可以通过使用
--replicate-ignore-table=mysql.ndb_apply_status
启动复制来实现。如果您需要忽略其他表,请使用相应的--replicate-wild-ignore-table
选项。
您不应该禁用对 mysql.ndb_apply_status
表的复制或二进制日志记录,或者更改用于该表的存储引擎,在从一个 NDB 集群到另一个 NDB 集群进行复制时。请参阅NDB 集群之间的复制和二进制日志过滤规则,了解详细信息。
NDB 集群到非事务存储引擎的复制. 从 NDB
到非事务存储引擎,如MyISAM
,您可能会遇到在复制 INSERT ... ON DUPLICATE KEY UPDATE
语句时出现不必要的重复键错误。您可以使用 --ndb-log-update-as-write=0
,强制更新被记录为写操作,而不是更新操作,以避免这些错误。
NDB 集群之间的复制和二进制日志过滤规则. 如果您使用了任何选项 --replicate-do-*
、--replicate-ignore-*
、--binlog-do-db
或 --binlog-ignore-db
进行数据库或表的过滤复制,您必须小心不要阻止复制或二进制日志记录 mysql.ndb_apply_status
,因为这对于 NDB 集群之间的复制操作是必需的。在具体来说,您需要注意以下几点:
-
使用
--replicate-do-db=
(并且不使用其他db_name
--replicate-do-*
或--replicate-ignore-*
选项)意味着只有数据库db_name
中的表被复制。在这种情况下,您也应该使用--replicate-do-db=mysql
、--binlog-do-db=mysql
或--replicate-do-table=mysql.ndb_apply_status
以确保mysql.ndb_apply_status在复制服务器上被填充。使用
--binlog-do-db=
(并且不使用其他db_name
--binlog-do-db
选项)意味着只有数据库db_name
中的表的变化被写入到二进制日志中。在这种情况下,您也应该使用--replicate-do-db=mysql
、--binlog-do-db=mysql
或--replicate-do-table=mysql.ndb_apply_status
以确保mysql.ndb_apply_status在复制服务器上被填充。 -
使用
--replicate-ignore-db=mysql
意味着mysql数据库中的所有表都不被复制。在这种情况下,您也应该使用--replicate-do-table=mysql.ndb_apply_status
以确保mysql.ndb_apply_status被复制。使用
--binlog-ignore-db=mysql
意味着不将对数据库mysql的表进行更改写入到二进制日志中。在这种情况下,您也应该使用--replicate-do-table=mysql.ndb_apply_status
以确保mysql.ndb_apply_status被复制。
您也应该记住,每个复制规则都需要以下内容:
-
自己的--replicate-do-*或--replicate-ignore-*选项,并且不能在单个复制过滤选项中表达多个规则。关于这些规则的信息,请见第19.1.6节,“Replication and Binary Logging Options and Variables”。
-
自己的
--binlog-do-db
或--binlog-ignore-db
选项,并且不能在单个二进制日志过滤选项中表达多个规则。关于这些规则的信息,请见第7.4.4节,“The Binary Log”。
如果您正在将NDB集群复制到使用存储引擎不同于NDB
的副本,那么前面提到的考虑可能不适用,因为在这个部分中讨论了其他地方。
NDB 集群复制和 IPv6. NDB 8.4 中所有类型的 NDB 集群节点都支持 IPv6,这包括管理节点、数据节点和 API 或 SQL 节点。
在 NDB 8.4 中,您可以禁用 Linux 内核中的 IPv6 支持,如果您不打算使用 IPv6 地址来为任何 NDB 集群节点进行配置。
属性提升和降低. NDB 集群复制包括对属性提升和降低的支持。后者的实现区分了损失性和非损失性的类型转换,并且可以通过设置全局变量 replica_type_conversions
来控制在副本上使用它们。
关于 NDB 集群中的属性提升和降低的更多信息,请见基于行的复制:属性提升和降低。
NDB
,与InnoDB
或MyISAM
不同的是,不会将虚拟列的更改写入二进制日志;然而,这对 NDB 集群复制或 NDB 与其他存储引擎之间的复制没有不良影响。存储生成列的更改将被记录。