### 23.7.4 NDB 集群复制模式和表

[](<>)[](<>)[](<>)

-   [数据库\_申请\_状态表](mysql-cluster-replication-schema.html#ndb-replication-ndb-apply-status)

-   [数据库\_二进制日志\_索引表](mysql-cluster-replication-schema.html#ndb-replication-ndb-binlog-index)

-   [数据库\_复制表](mysql-cluster-replication-schema.html#ndb-replication-ndb-replication)

    NDB Cluster 中的复制利用了`mysql`每个 MySQL 服务器实例上的数据库在被复制的集群和副本中都充当 SQL 节点。无论副本是单个服务器还是集群，这都是正确的。

    这`ndb_binlog_index`和`ndb_apply_status`表是在`mysql`数据库。用户不应明确复制它们。通常不需要用户干预来创建或维护这些表中的任何一个，因为这两个表都由[`新开发银行`](mysql-cluster.html)二进制日志（binlog）注入器线程。这保留了源[**mysqld**](mysqld.html)过程更新为由执行的更改[`新开发银行`](mysql-cluster.html)存储引擎。这[`新开发银行`](mysql-cluster.html)binlog 注入器线程直接从[`新开发银行`](mysql-cluster.html)存储引擎。这[`新开发银行`](mysql-cluster.html)注入器负责捕获集群内的所有数据事件，并确保所有更改、插入或删除数据的事件都记录在`ndb_binlog_index`桌子。副本 I/O（接收者）线程将事件从源的二进制日志传输到副本的中继日志。

    这`ndb_replication`必须手动创建表。用户可以更新此表以执行按数据库或表的过滤。看[数据库\_复制表](mysql-cluster-replication-schema.html#ndb-replication-ndb-replication)， 了解更多信息。`ndb_replication`也用于 NDB Replication 冲突检测和解决，用于冲突解决控制；看[冲突解决控制](mysql-cluster-replication-conflict-resolution.html#conflict-resolution-control).

    虽然`ndb_binlog_index`和`ndb_apply_status`是自动创建和维护的，建议检查这些表的存在和完整性，作为准备 NDB Cluster 以进行复制的初始步骤。可以通过查询来查看二进制日志中记录的事件数据`mysql.ndb_binlog_index`表直接放在源上。这也可以使用[`显示 BINLOG 事件`](show-binlog-events.html)源或副本 SQL 节点上的语句。（看[第 13.7.7.2 节，“SHOW BINLOG EVENTS 语句”](show-binlog-events.html).)

    您还可以从输出中获取有用的信息[`显示引擎 NDB 状态`](show-engine.html).

笔记

在执行架构更改时[`新开发银行`](mysql-cluster.html)表，应用程序应该等到[`更改表`](alter-table.html)在尝试使用表的更新定义之前，该语句已在发出该语句的 MySQL 客户端连接中返回。

#### 数据库\_申请\_状态表

[](<>)[](<>)

`ndb_apply_status`用于记录已从源复制到副本的操作。如果`ndb_apply_status`副本上不存在表，[**数据库\_恢复**](mysql-cluster-programs-ndb-restore.html)重新创建它。

与情况不同`ndb_binlog_index`，此表中的数据不特定于（副本）集群中的任何一个 SQL 节点，因此`ndb_apply_status`可以使用`NDBCLUSTER`存储引擎，如下所示：

```
CREATE TABLE `ndb_apply_status` (
    `server_id`   INT(10) UNSIGNED NOT NULL,
    `epoch`       BIGINT(20) UNSIGNED NOT NULL,
    `log_name`    VARCHAR(255) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
    `start_pos`   BIGINT(20) UNSIGNED NOT NULL,
    `end_pos`     BIGINT(20) UNSIGNED NOT NULL,
    PRIMARY KEY (`server_id`) USING HASH
) ENGINE=NDBCLUSTER   DEFAULT CHARSET=latin1;
```

这`ndb_apply_status`表仅在副本上填充，这意味着，在源上，此表从不包含任何行；因此，没有必要分配任何[`数据存储器`](mysql-cluster-ndbd-definition.html#ndbparam-ndbd-datamemory)到`ndb_apply_status`那里。

因为这个表是从源数据中填充的，所以应该允许复制；任何无意中阻止副本更新的复制过滤或二进制日志过滤规则`ndb_apply_status`，或者阻止源写入二进制日志可能会阻止集群之间的复制正常运行。有关此类过滤规则引起的潜在问题的更多信息，请参阅[复制和二进制日志过滤规则与 NDB 集群之间的复制](mysql-cluster-replication-issues.html#mysql-cluster-replication-issues-filtering).

可以删除此表，但不建议这样做。删除它会将所有 SQL 节点置于只读模式；在 NDB 8.0.24 及更高版本中，`新开发银行`检测到该表已被删除，并重新创建它，之后可以再次执行更新。删除和重新创建`ndb_apply_status`在二进制日志中创建一个间隙事件；间隙事件导致副本 SQL 节点停止应用来自源的更改，直到重新启动复制通道。在 NDB 8.0.24 之前，在这种情况下需要重新启动所有 SQL 节点以使其退出只读模式，然后重新创建`ndb_apply_status`手动。

`0`在里面`时代`此表的列表示源自存储引擎以外的事务`新开发银行`.

`ndb_apply_status`用于记录哪些 epoch 事务已从上游源复制并应用于副本集群。此信息被捕获在一个`新开发银行`在线备份，但（按设计）它不是由[**数据库\_恢复**](mysql-cluster-programs-ndb-restore.html).在某些情况下，恢复此信息以在新设置中使用会有所帮助；从 NDB 8.0.29 开始，您可以通过调用[**数据库\_恢复**](mysql-cluster-programs-ndb-restore.html)与[`--with-apply-status`](mysql-cluster-programs-ndb-restore.html#option_ndb_restore_with-apply-status)选项。有关详细信息，请参阅选项说明。

#### 数据库\_二进制日志\_索引表

[](<>)[](<>)

NDB Cluster Replication 使用`ndb_binlog_index`用于存储二进制日志的索引数据的表。由于该表对于每个 MySQL 服务器都是本地的并且不参与集群，因此它使用[`InnoDB`](innodb-storage-engine.html)存储引擎。这意味着它必须在每个[**mysqld**](mysqld.html)参与源集群。（二进制日志本身包含来自集群中所有 MySQL 服务器的更新。）该表定义如下：

```
CREATE TABLE `ndb_binlog_index` (
    `Position` BIGINT(20) UNSIGNED NOT NULL,
    `File` VARCHAR(255) NOT NULL,
    `epoch` BIGINT(20) UNSIGNED NOT NULL,
    `inserts` INT(10) UNSIGNED NOT NULL,
    `updates` INT(10) UNSIGNED NOT NULL,
    `deletes` INT(10) UNSIGNED NOT NULL,
    `schemaops` INT(10) UNSIGNED NOT NULL,
    `orig_server_id` INT(10) UNSIGNED NOT NULL,
    `orig_epoch` BIGINT(20) UNSIGNED NOT NULL,
    `gci` INT(10) UNSIGNED NOT NULL,
    `next_position` bigint(20) unsigned NOT NULL,
    `next_file` varchar(255) NOT NULL,
    PRIMARY KEY (`epoch`,`orig_server_id`,`orig_epoch`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
```

笔记

如果您从旧版本（NDB 7.5.2 之前）升级，请执行 MySQL 升级过程并确保系统表通过启动 MySQL 服务器来升级`--升级=强制`选项。系统表升级导致[`ALTER TABLE ... 引擎=INNODB`](alter-table.html)为该表执行的语句。的使用`MyISAM`继续支持此表的存储引擎以实现向后兼容性。

`ndb_binlog_index`转换为后可能需要额外的磁盘空间`InnoDB`.如果这成为一个问题，您可以通过使用`InnoDB`此表的表空间，更改其`ROW_FORMAT`到`压缩`， 或两者。有关详细信息，请参阅[第 13.1.21 节，“CREATE TABLESPACE 语句”](create-tablespace.html)， 和[第 13.1.20 节，“CREATE TABLE 语句”](create-table.html)， 也[第 15.6.3 节，“表空间”](innodb-tablespace.html).

的大小`ndb_binlog_index`表取决于每个二进制日志文件的纪元数和二进制日志文件的数量。每个二进制日志文件的 epoch 数通常取决于每个 epoch 生成的二进制 log 的数量和二进制 log 文件的大小，越小的 epoch 导致每个文件的 epoch 越多。你应该知道空的时期会产生插入到`ndb_binlog_index`表，即使当[`--ndb-log-empty-epochs`](mysql-cluster-options-variables.html#option_mysqld_ndb-log-empty-epochs)选项是`离开`，这意味着每个文件的条目数取决于文件使用的时间长度；这种关系可以用这里显示的公式表示：

```
[number of epochs per file] = [time spent per file] / TimeBetweenEpochs
```

繁忙的 NDB Cluster 定期写入二进制日志，并且可能比安静的 NDB Cluster 更快地旋转二进制日志文件。这意味着一个“安静”的 NDB Cluster 具有[`--ndb-log-empty-epochs=ON`](mysql-cluster-options-variables.html#option_mysqld_ndb-log-empty-epochs)实际上可以有更多的`ndb_binlog_index`每个文件的行数比具有大量活动的行数。

什么时候[**mysqld**](mysqld.html)开始于[`--ndb-log-orig`](mysql-cluster-options-variables.html#option_mysqld_ndb-log-orig)选项，`orig_server_id`和`orig_epoch`列分别存储事件发起的服务器的 ID 和事件在发起服务器上发生的纪元，这在使用多个源的 NDB Cluster 复制设置中很有用。这[`选择`](select.html)用于在多源设置中查找与副本上应用的最高纪元最近的二进制日志位置的语句（请参阅[第 23.7.10 节，“NDB 集群复制：双向和循环复制”](mysql-cluster-replication-multi-source.html)) 使用了这两个未编入索引的列。这可能会在尝试故障转移时导致性能问题，因为查询必须执行表扫描，尤其是当源已与[`--ndb-log-empty-epochs=ON`](mysql-cluster-options-variables.html#option_mysqld_ndb-log-empty-epochs).您可以通过向这些列添加索引来改进多源故障转移时间，如下所示：

```
ALTER TABLE mysql.ndb_binlog_index
    ADD INDEX orig_lookup USING BTREE (orig_server_id, orig_epoch);
```

从单个源复制到单个副本时，添加此索引没有任何好处，因为在这种情况下用于获取二进制日志位置的查询没有使用`orig_server_id`要么`orig_epoch`.

看[第 23.7.8 节，“使用 NDB Cluster Replication 实现故障转移”](mysql-cluster-replication-failover.html), 有关使用`下一个位置`和`下一个文件`列。

下图显示了 NDB Cluster 复制源服务器、其二进制日志注入器线程和`mysql.ndb_binlog_index`桌子。

[](<>)

**图 23.35 复制源集群**

<img alt="Most concepts are described in the surrounding text. This complex image has three main areas. The top left area is divided into three sections: MySQL Server (mysqld), NDBCLUSTER table handler, and mutex. A connection thread connects these, and receiver and injector threads connect the NDBCLUSTER table handler and mutex. The bottom area shows four data nodes (ndbd). They all produce events represented by arrows pointing to the receiver thread, and the receiver thread also points to the connection and injector threads. One node sends and receives to the mutex area. The arrow representing the injector thread points to a binary log as well as the ndb_binlog_index table, which is described in the surrounding text." src="images/cluster-replication-binlog-injector.png" height="406" width="750" />

#### 数据库\_复制表

[](<>)[](<>)

这`ndb_replication`table 用于控制二进制日志记录和冲突解决，并基于每个表进行操作。此表中的每一行对应于一个正在复制的表，确定如何记录对表的更改，如果指定了冲突解决函数，则确定如何解决该表的冲突。

不像`ndb_apply_status`和`ndb_replication`表`ndb_replication`必须使用此处显示的 SQL 语句手动创建表：

```
CREATE TABLE mysql.ndb_replication  (
    db VARBINARY(63),
    table_name VARBINARY(63),
    server_id INT UNSIGNED,
    binlog_type INT UNSIGNED,
    conflict_fn VARBINARY(128),
    PRIMARY KEY USING HASH (db, table_name, server_id)
)   ENGINE=NDB
PARTITION BY KEY(db,table_name);
```

此处列出了此表的列，并附有说明：

-   `D b`柱子

    包含要复制的表的数据库的名称。

    您可以使用一个或两个通配符`_`和`%`作为数据库名称的一部分。（看[与通配符匹配](mysql-cluster-replication-schema.html#ndb-replication-wildcards)，在本节后面。）

-   `表名`柱子

    要复制的表的名称。

    表名可以包含一个或两个通配符`_`和`%`.看[与通配符匹配](mysql-cluster-replication-schema.html#ndb-replication-wildcards), 在本节后面。

-   `server_id`柱子

    表所在的 MySQL 实例（SQL 节点）的唯一服务器 ID。

    `0`在此列中的作用类似于通配符`%`, 并匹配任何服务器 ID。（看[与通配符匹配](mysql-cluster-replication-schema.html#ndb-replication-wildcards)，在本节后面。）

-   `binlog_type`柱子

    要使用的二进制日志记录的类型。有关值和描述，请参见文本。

-   `冲突_fn`柱子

    要应用的冲突解决功能；之一[NDB$OLD(列\_姓名）](mysql-cluster-replication-conflict-resolution.html#mysql-cluster-replication-ndb-old), [NDB$MAX(列\_姓名）](mysql-cluster-replication-conflict-resolution.html#mysql-cluster-replication-ndb-max), [新开发银行$MAX\_删除\_赢（）](mysql-cluster-replication-conflict-resolution.html#mysql-cluster-replication-ndb-max-delete-win), [新开发银行$EPOCH()](mysql-cluster-replication-conflict-resolution.html#mysql-cluster-replication-ndb-epoch), [新开发银行$时代\_转（）](mysql-cluster-replication-conflict-resolution.html#mysql-cluster-replication-ndb-epoch-trans), [新开发银行$EPOCH2()](mysql-cluster-replication-conflict-resolution.html#mysql-cluster-replication-ndb-epoch2), [新开发银行$EPOCH2\_转（）](mysql-cluster-replication-conflict-resolution.html#mysql-cluster-replication-ndb-epoch2-trans); `空值`表示此表不使用冲突解决。

    看[冲突解决功能](mysql-cluster-replication-conflict-resolution.html#conflict-resolution-functions)，有关这些函数及其在 NDB 复制冲突解决中的用途的更多信息。

    一些冲突解决功能（`新开发银行$OLD()`,`新开发银行$EPOCH()`,`NDB$EPOCH_TRANS()`) 需要使用一个或多个用户创建的异常表。看[冲突解决例外表](mysql-cluster-replication-conflict-resolution.html#conflict-resolution-exceptions-table).

    要使用 NDB 复制启用冲突解决，有必要在应该解决冲突的一个或多个 SQL 节点上创建并使用控制信息填充此表。根据要采用的冲突解决类型和方法，这可能是源服务器、副本服务器或两者。在一个简单的源-副本设置中，数据也可以在副本上本地更改，这通常是副本。在更复杂的复制方案中，例如双向复制，这通常是所涉及的所有源。看[第 23.7.11 节，“NDB 集群复制冲突解决”](mysql-cluster-replication-conflict-resolution.html)， 了解更多信息。

    这`ndb_replication`table 允许在冲突解决范围之外对二进制日志进行表级控制，在这种情况下`冲突_fn`被指定为`空值`，而其余​​列值用于控制给定表或匹配通配符表达式的表集的二进制日志记录。通过设置适当的值`binlog_type`列，您可以使给定表或表的日志记录使用所需的二进制日志格式，或完全禁用二进制日志记录。此列的可能值以及内部值和说明如下表所示：

[](<>)

**表 23.69 二进制日志\_类型值，带有内部值和描述**

| 价值 | 内部价值 | 描述 |
| --- | ---- | --- |
| 0 | `NBT_DEFAULT` | 使用服务器默认值 |
| 1. | `NBT_无_记录` | 不要在二进制日志中记录此表（与[`sql_log_bin=0`](replication-options-binary-log.html#sysvar_sql_log_bin)，但仅适用于一个或多个指定表） |
| 2. | `NBT_仅更新` | 只记录更新的属性（与[`--ndb日志仅更新`](mysql-cluster-options-variables.html#option_mysqld_ndb-log-updated-only)，但仅适用于一个或多个指定表） |
| 3. | `NBT_满` | 记录完整行，即使未更新（MySQL服务器默认行为） |
| 4. | `NBT_使用_更新` | （用于生成`NBT_更新_仅使用_更新`和`NBT_完整_使用_更新`只有价值观；不打算单独使用） |
| 5. | [*不用*] | --- |
| 6. | `NBT_更新_仅使用_更新`（等于`NBT_仅更新| NBT_使用|更新`) | 使用更新的属性，即使值不变 |
| 7. | `NBT_完整_使用_更新`（等于`NBT_完整| NBT_使用|更新`) | 使用整行，即使值不变 |
| 8. | `NBT_仅更新__最小值` | 日志更新为`更新_行`; 只在前图像中记录主键列，在后图像中只记录更新的列（与[`--ndb日志更新最小`](mysql-cluster-options-variables.html#option_mysqld_ndb-log-update-minimal)，但仅适用于一个或多个指定表） |
| 9 | `NBT_更新_完整_最小` | 日志更新为`更新_行`; 只在前图像中记录主键列，在后图像中记录除主键列以外的所有列 |

通过在表中插入行，可以为不同的表将二进制日志设置为不同的格式`ndb_复制`使用适当的`分贝`, `表2\u名称`和`binlog_型`列值。设置二进制日志记录格式时，应使用上表中显示的内部整数值。以下两条语句将二进制日志记录设置为整行日志记录(`NBT_满`，表的内部值3）`测验A.`，并仅记录更新(`NBT_仅更新`，表的内部值2）`测验B`:

```
# Table test.a: Log full rows
INSERT INTO mysql.ndb_replication VALUES("test", "a", 0, 3, NULL);

# Table test.b: log updates only
INSERT INTO mysql.ndb_replication VALUES("test", "b", 0, 2, NULL);
```

要禁用一个或多个表的日志记录，请使用1(`NBT_无_记录`)因为`binlog_型`，如图所示：

```
# Disable binary logging for table test.t1
INSERT INTO mysql.ndb_replication VALUES("test", "t1", 0, 1, NULL);

# Disable binary logging for any table in 'test' whose name begins with 't'
INSERT INTO mysql.ndb_replication VALUES("test", "t%", 0, 1, NULL);
```

背景`NBT_无_记录`对于一个给定的表，它相当于设置[`sql_log_bin=0`](replication-options-binary-log.html#sysvar_sql_log_bin)，但它单独适用于一个或多个表。`NBT_无_记录`在数据节点上有效地实现；如果SQL节点未对给定表执行二进制日志记录，则不会向其发送这些表的行更改事件。这意味着它不会接收所有更改并放弃一些更改，而是不会订阅这些更改。

`NBT_无_记录`可能有很多原因，包括以下列出的原因：

-   不通过网络发送更改通常可以节省带宽、缓冲和CPU资源。

-   不记录对具有非常频繁更新但其值不是很大的表的更改非常适合于临时数据（例如会话数据），这些数据在集群发生完全故障时可能相对不重要。

-   使用会话变量（或`sql_log_bin`)和应用程序代码，还可以记录（或不记录）某些SQL语句或SQL语句类型；例如，在某些情况下，不在一个或多个表上记录DDL语句可能是可取的。

-   出于性能、需要将不同的数据库复制到不同的位置、对不同的数据库使用不同的二进制日志类型等原因，可以将复制流拆分为两个（或更多）二进制日志。

[](<>)**与通配符匹配。**为了避免在列表中插入行`ndb_复制`表用于复制设置中数据库、表和SQL节点的每个组合，`NDB`支持在此表的`分贝`, `表2\u名称`和`服务器id`柱。中分别使用的数据库和表名，`分贝`和`表2\u名称`可能包含以下通配符中的一个或两个：

-   `_`（下划线字符）：匹配零个或多个字符

-   `%`（百分号）：匹配单个字符

    （这些通配符与MySQL支持的通配符相同[`喜欢`](string-comparison-functions.html#operator_like)接线员。）

    这个`服务器id`立柱支架`0`作为一个通配符，相当于`_`（匹配任何东西）。这在前面所示的示例中使用。

    表中给定的一行`ndb_复制`表可以使用通配符来匹配任意组合的数据库名称、表名称和服务器ID。如果表中有多个潜在匹配项，则根据此处显示的表选择最佳匹配项，其中*W*表示通配符匹配，*E*精确匹配，并且*质量*列，匹配得越好：

[](<>)

**表23.70 mysql中列的通配符和精确匹配的不同组合的权重。ndb\_复制表**

| `分贝` | `表2\u名称` | `服务器id` | 质量 |
| ---- | -------- | ------- | --- |
| W | W | W | 1. |
| W | W | E | 2. |
| W | E | W | 3. |
| W | E | E | 4 |
| E | W | W | 5 |
| E | W | E | 6 |
| E | E | W | 7 |
| E | E | E | 8 |

因此，数据库名、表名和服务器ID的精确匹配被认为是最佳（最强）匹配，而最弱（最差）匹配则是所有三列的通配符匹配。在选择应用哪条规则时，只考虑比赛的强度；表中行的出现顺序对该确定没有影响。
