Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 Reference Manual  /  ...  /  NDB Cluster Replication Using the Multithreaded Applier

25.7.11 NDB 集群复制使用多线程应用程序

NDB 复制在 NDB 8.4 中支持使用通用 MySQL 服务器多线程应用程序机制(MTA),该机制允许独立的二进制日志事务在副本上并行地被应用,从而提高峰值复制吞吐量。

MySQL 服务器 MTA 实现将单独的二进制日志事务委派给一个可配置的工作线程池(worker threads),并确保 worker threads 遵守二进制日志中的事务依赖关系,并维护 commit 顺序,如果需要(请参阅第 19.2.3 节,“Replication Threads”)。要在 NDB 集群中使用该功能, replica 必须被配置为使用多个工作线程。要实现这一点,请将replica_parallel_workers设置来控制 replica 上的工作线程数量。默认值为 4。

如果在源mysqld上设置replica_parallel_type,则必须将其设置为 LOGICAL_CLOCK(默认值)。

Note

NDB 不支持replica_parallel_type=DATABASE

此外,建议您将源服务器用于跟踪二进制日志事务写集的内存设置(binlog_transaction_dependency_history_size)设置为E * P,其中E是平均epoch大小(以操作数为单位),P是预期的最大并行度。请参阅 Writeset Tracking Memory Usage,了解更多信息。

MTA的NDB副本mysqld配置要求replica_parallel_workers大于1。启用MTA时的推荐初始值为4,这也是默认值。

此外,replica_preserve_commit_order必须设置为ON。这也是默认值。

事务依赖关系是通过分析每个事务的写集来检测的,即该事务所写的行(表、键值)。如果两个事务修改同一行,他们被认为是相互依赖的,需要按顺序(即串行)应用,以避免死锁或错误结果。如果一个表具有secondary唯一键,这些值也将添加到事务的写集中,以检测不同事务对同一唯一键值的影响,并因此要求排序。对于无法高效确定依赖关系的情况,mysqld将退回到考虑事务相互依赖的安全原因。

事务依赖关系在源mysqld中被编码为二进制日志。依赖关系使用逻辑时钟(Logical clock)方案在ANONYMOUS_ GTID事件中编码。 (见Section 19.1.4.1,“Replication Mode Concepts”。)

MySQL(和NDB集群)所使用的写集实现基于哈希冲突检测,基于相关表和索引值的64位行哈希值。这可靠地检测到同一键被看到两次,但也可能产生false positives,如果不同的表和索引值哈希到相同的64位值;这可能导致人为依赖关系,减少可用并发性。

事务依赖关系将被强制执行以下情况之一:

  • DDL语句

  • 二进制日志轮转或遇到二进制日志文件边界

  • 写入历史大小限制

  • 引用目标表外键的写入操作

    更具体地说,事务对父表(parent)进行插入、更新和删除操作时,相对于所有前置和后置事务都是串行化的,而不是只与涉及约束关系的表事务串行化。反之,对于引用外键的子表(child)进行插入、更新和删除操作的事务,不特别地与其他事务串行化。

MySQL MTA 实现尝试并行应用独立的二进制日志事务。NDB 记录在同一个 epoch(TimeBetweenEpochs,默认 100 毫秒)中所有用户事务的更改,在一个二进制日志事务中,即 epoch 事务。因此,对于两个连续的 epoch 事务,如果它们之间没有修改任何行,则可以并行应用。如果在两个 epoch 中都修改了某个行,则它们是依赖的,需要串行应用,这可能会限制可exploitable 并行性。

epoch 事务根据源集群在 epoch 中修改的行集来判断是否独立,不包括传递 epoch 元数据的mysql.ndb_apply_status WRITE_ROW 事件。这避免了每个 epoch 事务都对前一个 epoch 依赖,但需要在复制服务器上将 binlog 应用,以保持提交顺序。这也意味着 NDB 二进制日志具有写入历史依赖关系,不适合由使用不同 MySQL 存储引擎的副本数据库使用。

可能需要或有必要修改应用程序事务行为,以避免在短时间内对同一行重复修改,单独的事务,以提高可exploitable并行性。

使用binlog_transaction_dependency_history_size服务器系统变量可以设置跟踪二进制日志事务写入集的内存大小,该变量默认为25000个行哈希。

如果平均二进制日志事务修改N行,那么要能够识别独立的事务(可并行化)到并行性水平P,我们需要binlog_transaction_dependency_history_size至少为N * P。(最大值为1000000。)

有限的历史记录大小导致可靠确定的最大依赖长度,从而给出了可表达的有限并行性。任何未在历史记录中找到的一行可能依赖于最后一个从历史记录中 purged 的事务。

写入集历史记录不像滑动窗口,覆盖最后N个事务,而是一个有限的缓冲区,当它满时将其内容完全丢弃。因此,历史大小随时间而变化,类似于 sawtooth 模式,因此独立的事务可能仍被标记为依赖,如果在它们被处理之间写入集历史记录缓冲区已经被重置。

在这个方案中,每个事务在二进制日志文件中都被注释了一个 sequence_number(1, 2, 3,...) 和它依赖于的最 recent 二进制日志事务的序列号,称为 last_committed

在给定的二进制日志文件中,第一个事务的 sequence_number 是 1,last_committed 是 0。

如果一个二进制日志事务依赖于它的直接前驱,那么它的应用是 serialized。如果依赖于更早的事务,那么可能可以并行地应用该事务和前面的独立事务。

使用 mysqlbinlog 可以查看 ANONYMOUS_ GTID 事件的内容,包括 sequence_numberlast_committed(因此可以确定事务依赖关系)。

源服务器生成的 ANONYMOUS_ GTID 事件将单独处理与压缩的事务 payload,使用 bulk BEGINTABLE_MAP*WRITE_ROW*UPDATE_ROW*DELETE_ROW*COMMIT 事件,允许在解压缩之前确定依赖关系。这意味着复制协调线程可以将事务 payload 的解压缩委派给工作线程,从而自动并行地解压缩独立事务在复制服务器上。

次要唯一列。具有次要唯一列(即除了主键外的唯一键)的表格将所有列发送到源,以检测唯一键相关的冲突。

在当前二进制日志模式中,不包括所有列,只包括更改的列(--ndb-log-updated-only=OFF--ndb-log-update-minimal=ON--ndb-log-update-as-write=OFF),这可能会增加数据节点到 SQL 节点的数据传输量。

影响取决于修改行(更新或删除)的速度,以及未实际修改的列中的数据体积。

NDB 到 InnoDB 的复制。 NDB 二进制日志注入器事务依赖关系跟踪故意忽略由生成的 mysql.ndb_apply_status 元数据事件创建的交互事务依赖关系,这些事件在副本应用程序中作为 epoch 事务的提交的一部分处理。对于到InnoDB 的复制,没有特殊处理;这可能会导致使用 InnoDB 多线程应用程序消费 NDB MTA 二进制日志时出现性能下降或其他问题。