本节讨论使用 NDB 集群复制时已知的问题或故障。
源与副本之间连接断开。 连接断开可能发生在源集群 SQL 节点和副本集群 SQL 节点之间,也可能发生在源 SQL 节点和源集群的数据节点之间。在后一种情况下,这不仅可能由于物理连接断开(例如,网线断裂)而发生,也可能由于数据节点事件缓冲区溢出而发生;如果 SQL 节点的响应速度过慢,它可能会被集群丢弃(这可以通过调整 MaxBufferedEpochs
和 TimeBetweenEpochs
配置参数在一定程度上控制)。如果发生这种情况,完全有可能将新数据插入到源集群中,而不会记录在源 SQL 节点的二进制日志中。因此,为了保证高可用性,维护一个备份复制通道、监控主通道并在必要时故障转移到辅助复制通道以保持副本集群与源同步是非常重要的。NDB 集群本身并非为执行此类监控而设计的;为此,需要一个外部应用程序。
源 SQL 节点在连接或重新连接到源集群时会发出一个 “间隙” 事件。(间隙事件是一种 “事件事件”, 它表示发生的事件会影响数据库的内容,但不能轻易地表示为一组更改。事件的示例包括服务器故障、数据库重新同步、某些软件更新和某些硬件更改。)当副本在复制日志中遇到间隙时,它会停止并显示一条错误消息。此消息在 SHOW REPLICA STATUS
的输出中提供,并指示 SQL 线程已因复制流中注册的事件而停止,并且需要手动干预。有关在这种情况下该怎么办的更多信息,请参见 第 25.7.8 节,“使用 NDB 集群复制实现故障转移”。
因为 NDB 集群本身并非为监控复制状态或提供故障转移而设计的,所以如果副本服务器或集群需要高可用性,则必须设置多条复制线,监控主复制线上的源 mysqld,并在必要时准备故障转移到辅助线。这必须手动完成,或者可能通过第三方应用程序完成。有关实现此类设置的信息,请参见 第 25.7.7 节,“为 NDB 集群复制使用两个复制通道” 和 第 25.7.8 节,“使用 NDB 集群复制实现故障转移”。
如果要从独立的 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 节点都在启用了系统变量
log_replica_updates
的情况下启动。
这种类型的循环复制设置如下图所示
在这种情况下,集群 1 中的 SQL 节点 A 复制到集群 2 中的 SQL 节点 C;SQL 节点 C 复制到集群 3 中的 SQL 节点 E;SQL 节点 E 复制到 SQL 节点 A。换句话说,复制线(在图中由弯曲箭头指示)直接连接用作源和副本的所有 SQL 节点。
还应该可以设置并非所有源 SQL 节点也都是副本的循环复制,如下所示
在这种情况下,每个集群中的不同 SQL 节点用作源和副本。但是,你必须 不要 在启用了 log_replica_updates
系统变量的情况下启动任何 SQL 节点。这种类型的 NDB 集群循环复制方案(其中复制线(同样由图中的弯曲箭头指示)是不连续的)应该是可能的,但应该注意的是,它尚未经过全面测试,因此必须仍然被认为是实验性的。
NDB
存储引擎使用 幂等执行模式,这会抑制重复键和其他错误,否则这些错误会破坏 NDB 集群的循环复制。这等效于将系统变量 replica_exec_mode
的全局值设置为 IDEMPOTENT
,尽管这在 NDB 集群复制中是不必要的,因为 NDB 集群会自动设置此变量并忽略任何显式设置它的尝试。
NDB 集群复制和主键。 如果节点发生故障,复制没有主键的 NDB
表时仍然可能发生错误,因为在这种情况下可能会插入重复的行。因此,强烈建议所有要复制的 NDB
表都具有显式主键。
NDB 集群复制和唯一键。 在旧版本的 NDB 集群中,更新 NDB
表的唯一键列的值的操作在复制时可能会导致重复键错误。通过将唯一键检查推迟到所有表行更新都执行之后,可以解决 NDB
表之间的复制问题。
目前只有 NDB
支持以这种方式推迟约束。因此,从 NDB
复制到其他存储引擎(如 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);
t
上的以下 UPDATE
语句在源上成功,因为受影响的行是按照 ORDER BY
选项确定的顺序处理的,并在整个表上执行
UPDATE t SET c = c - 1 ORDER BY p;
相同的语句在副本上失败并出现重复键错误或其他约束冲突,因为行更新的排序是对一个分区一次执行的,而不是对整个表执行的。
每个 NDB
表在创建时都会按键隐式分区。有关更多信息,请参见 第 26.2.5 节,“KEY 分区”。
不支持 GTID。 使用全局事务 ID 的复制与 NDB
存储引擎不兼容,因此不受支持。启用 GTID 可能会导致 NDB 集群复制失败。
使用 --initial 重新启动。 使用 --initial
选项重新启动集群会导致 GCI 和纪元号序列从 0
开始。(这通常适用于 NDB 集群,而不限于涉及集群的复制场景。)在这种情况下,应重新启动参与复制的 MySQL 服务器。在此之后,你应该使用 RESET BINARY LOGS AND GTIDS
和 RESET REPLICA
语句分别清除无效的 ndb_binlog_index
和 ndb_apply_status
表。
从 NDB 复制到其他存储引擎。 可以将源上的 NDB
表复制到副本上使用不同存储引擎的表,同时考虑到此处列出的限制
不支持多源和循环复制(源和副本上的表必须使用
NDB
存储引擎才能使其工作)。对副本上的表使用不执行二进制日志记录的存储引擎需要特殊处理。
对副本上的表使用非事务性存储引擎也需要特殊处理。
源 mysqld 必须使用
--ndb-log-update-as-write=0
或--ndb-log-update-as-write=OFF
启动。
接下来的几段将提供有关刚刚描述的每个问题的更多信息。
将 NDB 复制到其他存储引擎时不支持多个源。 从 NDB
到不同存储引擎的复制,两个数据库之间的关系必须是一对一的。这意味着 NDB Cluster 和其他存储引擎之间不支持双向或循环复制。
此外,在 NDB
和不同存储引擎之间进行复制时,无法配置多个复制通道。(NDB Cluster 数据库 可以 同时复制到多个 NDB Cluster 数据库。)如果源使用 NDB
表,则仍然可以有多个 MySQL 服务器维护所有更改的二进制日志,但要使副本更改源(故障转移),必须在副本上显式定义新的源-副本关系。
将 NDB 表复制到不执行二进制日志记录的存储引擎。 如果您尝试从 NDB Cluster 复制到使用不处理自身二进制日志记录的存储引擎的副本,则复制过程将中止并显示错误 无法进行二进制日志记录 ... 由于涉及多个引擎且至少一个引擎是自记录的,因此无法原子地写入语句(错误 1595)。可以通过以下方式之一解决此问题
关闭副本上的二进制日志记录。 这可以通过设置
sql_log_bin = 0
来实现。更改 mysql.ndb_apply_status 表使用的存储引擎。 使此表使用不处理自身二进制日志记录的引擎也可以消除冲突。这可以通过在副本上发出如下语句来完成:
ALTER TABLE mysql.ndb_apply_status ENGINE=MyISAM
。在副本上使用NDB
以外的存储引擎时,这样做是安全的,因为您无需担心保持多个副本同步。过滤掉副本上对 mysql.ndb_apply_status 表的更改。 这可以通过使用
--replicate-ignore-table=mysql.ndb_apply_status
启动副本。如果您需要忽略其他表进行复制,则可能需要使用适当的--replicate-wild-ignore-table
选项。
在将一个 NDB Cluster 复制到另一个 NDB Cluster 时,您 不应 禁用 mysql.ndb_apply_status
的复制或二进制日志记录,也不应更改用于此表的存储引擎。有关详细信息,请参阅 NDB Cluster 之间复制的复制和二进制日志过滤规则。
从 NDB 到非事务性存储引擎的复制。 从 NDB
复制到非事务性存储引擎(例如 MyISAM
)时,在复制 INSERT ... ON DUPLICATE KEY UPDATE
语句时,您可能会遇到不必要的重复键错误。您可以使用 --ndb-log-update-as-write=0
来抑制这些错误,这会强制将更新记录为写入,而不是更新。
NDB 复制和文件系统加密 (TDE)。 使用加密文件系统对 NDB 复制没有任何影响。支持以下所有场景
将具有加密文件系统的 NDB Cluster 复制到文件系统未加密的 NDB Cluster。
将文件系统未加密的 NDB Cluster 复制到文件系统已加密的 NDB Cluster。
将文件系统已加密的 NDB Cluster 复制到使用未加密的
InnoDB
表的独立 MySQL 服务器。将具有未加密文件系统的 NDB Cluster 复制到使用文件系统加密的
InnoDB
表的独立 MySQL 服务器。
NDB Cluster 之间复制的复制和二进制日志过滤规则。 如果您正在使用任何 --replicate-do-*
、--replicate-ignore-*
、--binlog-do-db
或 --binlog-ignore-db
选项来过滤要复制的数据库或表,则必须注意不要阻止 mysql.ndb_apply_status
的复制或二进制日志记录,这对于 NDB Cluster 之间的复制才能正常运行。特别地,您必须记住以下几点
使用
--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 节“复制和二进制日志记录选项和变量”。它自己的
--binlog-do-db
或--binlog-ignore-db
选项,并且不能在单个二进制日志过滤选项中表达多个规则。有关这些规则的信息,请参阅 第 7.4.4 节“二进制日志”。
如果要将 NDB Cluster 复制到使用 NDB
以外的存储引擎的副本,则前面给出的注意事项可能不适用,如本节其他地方所述。
NDB Cluster 复制和 IPv6。 所有类型的 NDB Cluster 节点在 NDB 8.4 中都支持 IPv6;这包括管理节点、数据节点和 API 或 SQL 节点。
在 NDB 8.4 中,如果您不打算对任何 NDB Cluster 节点使用 IPv6 地址,则可以在 Linux 内核中禁用 IPv6 支持。
属性提升和降级。 NDB Cluster 复制包含对属性提升和降级的支持。后者的实现区分了有损和无损类型转换,并且可以通过设置系统变量 replica_type_conversions
的全局值来控制它们在副本上的使用。
有关 NDB Cluster 中属性提升和降级的更多信息,请参阅 基于行的复制:属性提升和降级。
与 InnoDB
或 MyISAM
不同,NDB
不会将虚拟列的更改写入二进制日志;但是,这对 NDB Cluster 复制或 NDB
和其他存储引擎之间的复制没有任何不利影响。存储的生成列的更改会被记录。