MySQL8-中文参考-三十五-

MySQL8 中文参考(三十五)

原文:docs.oracle.com/javase/tutorial/reallybigindex.html

原文:dev.mysql.com/doc/refman/8.0/en/replication-options-binary-log.html

19.1.6.4 二进制日志选项和变量

  • 启动时与二进制日志一起使用的选项

  • 与二进制日志一起使用的系统变量

您可以使用本节中描述的mysqld选项和系统变量来影响二进制日志的操作,以及控制写入二进制日志的语句。有关二进制日志的其他信息,请参见第 7.4.4 节,“二进制日志”。有关使用 MySQL 服务器选项和系统变量的其他信息,请参见第 7.1.7 节,“服务器命令选项”和第 7.1.8 节,“服务器系统变量”。

启动时与二进制日志一起使用的选项

以下列表描述了启用和配置二进制日志的启动选项。稍后在本节中讨论与二进制日志一起使用的系统变量。

  • --binlog-row-event-max-size=*N*

    命令行格式 --binlog-row-event-max-size=#
    系统变量 (≥ 8.0.14) binlog_row_event_max_size
    作用域 (≥ 8.0.14) 全局
    动态 (≥ 8.0.14)
    SET_VAR 提示适用 (≥ 8.0.14)
    类型 整数
    默认值 8192
    最小值 256
    最大值 (64 位平台) 18446744073709551615
    最大值 (32 位平台) 4294967295
    单位 字节

    当使用基于行的二进制日志记录时,此设置是行级二进制日志事件的最大大小软限制,以字节为单位。在可能的情况下,存储在二进制日志中的行被分组为大小不超过此设置值的事件。如果无法拆分事件,则最大大小可能会超过。该值必须是(否则会被四舍五入为)256 的倍数。默认值为 8192 字节。

  • --log-bin[=*base_name*]

    命令行格式 --log-bin=file_name
    类型 文件名

    指定用于二进制日志文件的基本名称。启用二进制日志记录后,服务器将所有更改数据的语句记录到二进制日志中,用于备份和复制。二进制日志是具有基本名称和数字扩展的文件序列。--log-bin选项值是日志序列的基本名称。服务器通过向基本名称添加数字后缀来按顺序创建二进制日志文件。

    如果不提供--log-bin选项,MySQL 将使用binlog作为二进制日志文件的默认基本名称。为了与早期版本兼容,如果提供了--log-bin选项但没有字符串或为空字符串,则基本名称默认为*host_name*-bin,使用主机机器的名称。

    二进制日志文件的默认位置是数据目录。您可以使用--log-bin选项指定另一个位置,通过在基本名称前添加一个绝对路径名来指定不同的目录。当服务器从跟踪已使用的二进制日志文件的二进制日志索引文件中读取条目时,它会检查条目是否包含相对路径。如果包含相对路径,则使用--log-bin选项设置的绝对路径将替换路径的相对部分。在二进制日志索引文件中记录的绝对路径保持不变;在这种情况下,必须手动编辑索引文件以启用新路径或路径的使用。二进制日志文件基本名称和任何指定的路径可作为log_bin_basename系统变量使用。

    在早期的 MySQL 版本中,默认情况下禁用了二进制日志记录,只有在指定了--log-bin选项时才会启用。从 MySQL 8.0 开始,默认情况下启用了二进制日志记录,无论您是否指定了--log-bin选项。唯一的例外是,如果您使用mysqld手动初始化数据目录,通过使用--initialize--initialize-insecure选项调用它时,默认情况下会禁用二进制日志记录。在这种情况下,可以通过指定--log-bin选项来启用二进制日志记录。当启用二进制日志记录时,显示服务器上二进制日志记录状态的log_bin系统变量将设置为 ON。

    要禁用二进制日志记录,您可以在启动时指定--skip-log-bin--disable-log-bin选项。如果指定了其中任何一个选项,并且同时指定了--log-bin选项,则后面指定的选项优先。当禁用二进制日志记录时,log_bin系统变量将设置为 OFF。

    当服务器上使用 GTIDs 时,如果在异常关闭后重新启动服务器时禁用二进制日志记录,可能会丢失一些 GTIDs,导致复制失败。在正常关闭时,当前二进制日志文件中的 GTID 集合将保存在mysql.gtid_executed表中。在未发生此情况的异常关闭后,在恢复过程中,GTIDs 将从二进制日志文件中添加到表中,前提是二进制日志记录仍然启用。如果在服务器重新启动时禁用了二进制日志记录,则服务器无法访问二进制日志文件以恢复 GTIDs,因此无法启动复制。在正常关闭后可以安全地禁用二进制日志记录。

    --log-slave-updates--slave-preserve-commit-order选项需要二进制日志记录。如果禁用二进制日志记录,则省略这些选项,或指定--log-slave-updates=OFF--skip-slave-preserve-commit-order。当指定--skip-log-bin--disable-log-bin时,MySQL 默认禁用这些选项。如果同时指定--log-slave-updates--slave-preserve-commit-order--skip-log-bin--disable-log-bin,将发出警告或错误消息。

    在 MySQL 5.7 中,启用二进制日志记录时必须指定服务器 ID,否则服务器将无法启动。在 MySQL 8.0 中,默认情况下将server_id系统变量设置为 1。当启用二进制日志记录时,现在可以使用此默认服务器 ID 启动服务器,但如果您没有通过设置server_id系统变量显式指定服务器 ID,则会发出信息消息。对于用于复制拓扑的服务器,必须为每个服务器指定唯一的非零服务器 ID。

    有关二进制日志的格式和管理信息,请参阅第 7.4.4 节,“二进制日志”。

  • --log-bin-index[=*file_name*]

    命令行格式 --log-bin-index=file_name
    系统变量 log_bin_index
    范围 全局
    动态
    SET_VAR提示适用
    类型 文件名

    二进制日志索引文件的名称,其中包含二进制日志文件的名称。默认情况下,它具有与使用--log-bin选项指定的二进制日志文件相同的位置和基本名称,再加上扩展名.index。如果您没有指定--log-bin,默认的二进制日志索引文件名为binlog.index。如果您指定了不带字符串或空字符串的--log-bin选项,则默认的二进制日志索引文件名为*host_name*-bin.index,使用主机机器的名称。

    有关二进制日志的格式和管理信息,请参见第 7.4.4 节,“二进制日志”。

语句选择选项。 下面列表中的选项影响写入二进制日志的语句,从而由复制源服务器发送到其副本。还有一些用于副本的选项,控制应该执行或忽略来自源的语句。有关详细信息,请参见第 19.1.6.3 节,“副本服务器选项和变量”。

  • --binlog-do-db=*db_name*

    命令行格式 --binlog-do-db=name
    类型 字符串

    此选项对二进制日志记录的影响类似于--replicate-do-db对复制的影响。

    此选项的影响取决于是否使用基于语句或基于行的日志格式,就像--replicate-do-db的影响取决于是否使用基于语句或基于行的复制一样。您应该记住,用于记录给定语句的格式可能不一定与binlog_format的值所指示的格式相同。例如,DDL 语句如CREATE TABLEALTER TABLE始终作为语句记录,而不考虑生效的日志格式,因此对于--binlog-do-db的以下基于语句的规则始终适用于确定语句是否被记录。

    基于语句的日志记录。 只有那些默认数据库(即由USE选择的数据库)为db_name的语句才会被写入二进制日志。要指定多个数据库,请多次使用此选项,每个数据库使用一次;但是,这样做不会导致跨数据库语句(例如UPDATE *some_db.some_table* SET foo='bar')在选择不同数据库(或没有数据库)时被记录。

    警告

    要指定多个数据库,必须多次使用此选项。因为数据库名称可以包含逗号,如果提供逗号分隔的列表,则该列表被视为单个数据库的名称。

    使用基于语句的日志记录时不像您期望的那样工作的示例:如果服务器使用--binlog-do-db=sales启动,并且您发出以下语句,则UPDATE语句不会被记录:

    USE prices;
    UPDATE sales.january SET amount=amount+1000;
    

    这种“只需检查默认数据库”行为的主要原因是,仅凭语句本身很难知道是否应该复制(例如,如果您使用多表DELETE语句或跨多个数据库操作的多表UPDATE语句)。如果没有必要,仅检查默认数据库而不是所有数据库会更快。

    另一个可能不明显的情况是,即使在设置选项时没有指定,给定的数据库也被复制。如果服务器使用--binlog-do-db=sales启动,即使在设置--binlog-do-db时未包括prices,以下UPDATE语句也会被记录:

    USE sales;
    UPDATE prices.discounts SET percentage = percentage + 10;
    

    因为sales是发出UPDATE语句时的默认数据库,所以UPDATE被记录。

    基于行的日志记录。 记录仅限于数据库db_name。只有属于db_name的表的更改才会被记录;默认数据库对此没有影响。假设服务器使用--binlog-do-db=sales启动,并且基于行的日志记录生效,然后执行以下语句:

    USE prices;
    UPDATE sales.february SET amount=amount+100;
    

    sales数据库中february表的更改将根据UPDATE语句记录;无论是否发出了USE语句都会发生。然而,当使用基于行的日志记录格式和--binlog-do-db=sales时,以下UPDATE所做的更改不会被记录:

    USE prices;
    UPDATE prices.march SET amount=amount-25;
    

    即使USE prices语句被更改为USE salesUPDATE语句的效果仍不会被写入二进制日志。

    在基于语句的日志记录和基于行的日志记录中,关于涉及多个数据库的语句的--binlog-do-db处理存在另一个重要区别。假设服务器是使用--binlog-do-db=db1启动的,并且执行了以下语句:

    USE db1;
    UPDATE db1.table1, db2.table2 SET db1.table1.col1 = 10, db2.table2.col2 = 20;
    

    如果使用基于语句的日志记录,两个表的更新都会被写入二进制日志。然而,当使用基于行的格式时,只有table1的更改被记录;table2位于不同的数据库中,因此不会受到UPDATE的影响。现在假设,而不是使用USE db1语句,而是使用了USE db4语句:

    USE db4;
    UPDATE db1.table1, db2.table2 SET db1.table1.col1 = 10, db2.table2.col2 = 20;
    

    当使用基于语句的日志记录时,使用UPDATE语句时不会被写入二进制日志。然而,当使用基于行的日志记录时,table1的更改被记录,但table2的更改不会被记录——换句话说,只有在由--binlog-do-db指定的数据库中的表的更改才会被记录,并且默认数据库的选择对此行为没有影响。

  • --binlog-ignore-db=*db_name*

    命令行格式 --binlog-ignore-db=name
    类型 字符串

    这个选项对二进制日志记录的影响类似于--replicate-ignore-db对复制的影响。

    此选项的效果取决于是否使用基于语句或基于行的日志记录格式,就像--replicate-ignore-db的效果取决于是否使用基于语句或基于行的复制一样。您应该记住,用于记录给定语句的格式可能不一定与binlog_format的值所指示的格式相同。例如,DDL 语句(如CREATE TABLEALTER TABLE)始终作为语句记录,而不考虑生效的日志记录格式,因此对于--binlog-ignore-db的以下基于语句的规则始终适用于确定该语句是否被记录。

    基于语句的日志记录。 告诉服务器不记录默认数据库(即由USE选择的数据库)为db_name的任何语句。

    当没有默认数据库时,不会应用--binlog-ignore-db选项,并且这些语句始终被记录。 (Bug #11829838, Bug #60188)

    基于行的格式。 告诉服务器不要记录对数据库db_name中任何表的更新。当前数据库不起作用。

    在使用基于语句的日志记录时,以下示例不会按您期望的方式工作。假设服务器是使用--binlog-ignore-db=sales启动的,并且您发出以下语句:

    USE prices;
    UPDATE sales.january SET amount=amount+1000;
    

    在这种情况下,UPDATE语句会被记录,因为--binlog-ignore-db仅适用于默认数据库(由USE语句确定)。由于sales数据库在语句中明确指定,因此该语句未被过滤。但是,在使用基于行的日志记录时,UPDATE语句的效果不会写入二进制日志,这意味着sales.january表的任何更改都不会被记录;在这种情况下,--binlog-ignore-db=sales导致忽略对源数据库副本中sales数据库中表所做的所有更改以进行二进制日志记录。

    要忽略多个数据库,请多次使用此选项,每个数据库使用一次。因为数据库名称可以包含逗号,如果提供逗号分隔的列表,则该列表将被视为单个数据库的名称。

    如果您正在使用跨数据库更新并且不希望将这些更新记录下来,则不应使用此选项。

校验和选项。 MySQL 支持读取和写入二进制日志校验和。可以使用以下两个选项启用它们:

  • --binlog-checksum={NONE|CRC32}

    命令行格式 --binlog-checksum=type
    类型 字符串
    默认值 CRC32
    有效值 NONE``CRC32

    启用此选项会导致源代码为写入二进制日志的事件生成校验和。设置为NONE以禁用,或者设置要用于生成校验和的算法的名称;目前仅支持 CRC32 校验和,CRC32 是默认值。您不能在事务内更改此选项的设置。

要控制副本(从中继日志)读取校验和,请使用--slave-sql-verify-checksum选项。

测试和调试选项。 以下二进制日志选项用于复制测试和调试。它们不适用于正常操作。

  • --max-binlog-dump-events=*N*

    命令行格式 --max-binlog-dump-events=#
    类型 整数
    默认值 0

    此选项仅在 MySQL 测试套件内部用于复制测试和调试。

  • --sporadic-binlog-dump-fail

    命令行格式 --sporadic-binlog-dump-fail[={OFF|ON}]
    类型 布尔
    默认值 OFF

    此选项仅在 MySQL 测试套件内部用于复制测试和调试。

与二进制日志一起使用的系统变量

以下列表描述了用于控制二进制日志记录的系统变量。它们可以在服务器启动时设置,并且其中一些可以使用 SET 在运行时更改。用于控制二进制日志记录的服务器选项在本节的前面列出。

  • binlog_cache_size

    命令行格式 --binlog-cache-size=#
    系统变量 binlog_cache_size
    范围 全局
    动态
    SET_VAR 提示适用
    类型 整数
    默认值 32768
    最小值 4096
    最大值(64 位平台) 18446744073709547520
    最大值(32 位平台) 4294963200
    单位 字节
    块大小 4096

    在事务期间保存对二进制日志的更改的内存缓冲区的大小。

    当服务器启用二进制日志记录(使用 log_bin 系统变量设置为 ON)时,如果服务器支持任何事务性存储引擎,则为每个客户端分配一个二进制日志缓存。如果事务的数据超过内存缓冲区的空间,多余的数据将存储在临时文件中。当服务器上启用二进制日志加密时,内存缓冲区不加密,但(从 MySQL 8.0.17 开始)用于保存二进制日志缓存的任何临时文件是加密的。在每个事务提交后,通过清除内存缓冲区并截断使用的临时文件来重置二进���日志缓存。

    如果经常使用大型事务,可以增加此缓存大小以获得更好的性能,从而减少或消除写入临时文件的需求。Binlog_cache_useBinlog_cache_disk_use 状态变量可用于调整此变量的大小。参见 第 7.4.4 节,“二进制日志”。

    binlog_cache_size 仅设置事务缓存的大小;语句缓存的大小由 binlog_stmt_cache_size 系统变量控制。

  • binlog_checksum

    命令行格式 --binlog-checksum=type
    系统变量 binlog_checksum
    范围 全局
    动态
    SET_VAR提示适用
    类型 字符串
    默认值 CRC32
    有效值 NONE``CRC32

    启用此变量会导致源为二进制日志中的每个事件编写校验和。binlog_checksum支持值NONE(禁用校验和)和CRC32。默认值为CRC32。当禁用binlog_checksum(值为NONE)时,服务器通过为每个事件编写和检查事件长度(而不是校验和)来验证仅将完整事件写入二进制日志。

    在源上将此变量设置为副本不识别的值会导致副本将其自己的binlog_checksum值设置为NONE,并因错误而停止复制。如果与旧副本的向后兼容性是一个问题,您可能希望将值明确设置为NONE

    直到 MySQL 8.0.20,Group Replication 无法使用校验和,也不支持二进制日志中的校验和,因此在配置服务器实例成为组成员时,必须设置binlog_checksum=NONE。从 MySQL 8.0.21 开始,Group Replication 支持校验和,因此组成员可以使用默认设置。

    更改binlog_checksum的值会导致二进制日志被旋转,因为必须为整个二进制日志文件编写校验和,而不能仅为部分文件编写。您不能在事务内更改binlog_checksum的值。

    当使用binlog_transaction_compression系统变量启用二进制日志事务压缩时,不会为压缩的事务负载中的每个事件编写校验和。相反,为 GTID 事件编写校验和,并为压缩的Transaction_payload_event编写校验和。

  • binlog_direct_non_transactional_updates

    命令行格式 --binlog-direct-non-transactional-updates[={OFF|ON}]
    系统变量 binlog_direct_non_transactional_updates
    范围 全局,会话
    动态
    SET_VAR提示适用
    类型 布尔值
    默认值 OFF

    由于并发问题,当事务包含对事务表和非事务表的更新时,复制品可能会变得不一致。MySQL 试图通过将非事务语句写入事务缓存来保留这些语句之间的因果关系,该缓存在提交时被刷新。然而,当代表事务对非事务表进行的修改立即对其他连接可见时,问题就会出现,因为这些更改可能不会立即���入二进制日志。

    binlog_direct_non_transactional_updates变量提供了解决此问题的一种可能方法。默认情况下,此变量已禁用。启用binlog_direct_non_transactional_updates会导致对非事务表的更新直接写入二进制日志,而不是写入事务缓存。

    截至 MySQL 8.0.14 版本,设置此系统变量的会话值是一项受限操作。会话用户必须具有足够权限来设置受限会话变量。请参阅第 7.1.9.1 节,“系统变量权限”。

    binlog_direct_non_transactional_updates仅适用于使用基于语句的二进制日志格式复制的语句;也就是说,仅当binlog_format的值为STATEMENT时,或者当binlog_formatMIXED且给定语句正在使用基于语句的格式进行复制时才起作用。当二进制日志格式为ROW时,或者当binlog_format设置为MIXED且给定语句使用基于行的格式进行复制时,此变量不起作用。

    重要提示

    在启用此变量之前,您必须确保事务表和非事务表之间没有依赖关系;这种依赖关系的一个示例是语句INSERT INTO myisam_table SELECT * FROM innodb_table。否则,这些语句很可能会导致复制品与源之间出现分歧。

    当二进制日志格式为ROWMIXED时,此变量不起作用。

  • binlog_encryption

    命令行格式 --binlog-encryption[={OFF|ON}]
    引入版本 8.0.14
    系统变量 binlog_encryption
    作用范围 全局
    动态
    SET_VAR提示适用
    类型 布尔值
    默认值 OFF

    启用此服务器上二进制日志文件和中继日志文件的加密。OFF是默认设置。ON设置二进制日志文件和中继日志文件的加密。不需要在服务器上启用二进制日志记录以启用加密,因此可以在没有二进制日志的副本上加密中继日志文件。要使用加密,必须安装并配置一个密钥环插件以提供 MySQL 服务器的密钥环服务。有关如何执行此操作的说明,请参见第 8.4.4 节,“MySQL 密钥环”。任何受支持的密钥环插件都可以用于存储二进制日志加密密钥。

    当首次启用二进制日志加密启动服务器时,在初始化二进制日志和中继日志之前会生成一个新的二进制日志加密密钥。此密钥用于为每个二进制日志文件(如果服务器启用了二进制日志记录)和中继日志文件(如果服务器有复制通道)加密一个文件密码,并且从文件密码生成的进一步密钥用于加密文件中的数据。中继日志文件为所有通道加密,包括组复制应用程序通道和在激活加密后创建的新通道。二进制日志索引文件和中继日志索引文件永远不会被加密。

    如果在服务器运行时激活加密,那么此时会生成一个新的二进制日志加密密钥。例外情况是,如果以前在服务器上激活了加密,然后禁用了,那么之前使用的二进制日志加密密钥将再次被使用。二进制日志文件和中继日志文件立即进行轮换,并且新文件和所有后续二进制日志文件和中继日志文件的文件密码都使用此二进制日志加密密钥进行加密。仍然存在于服务器上的现有二进制日志文件和中继日志文件不会自动加密,但如果不再需要,可以将它们清除。

    如果通过将binlog_encryption系统变量更改为OFF来停用加密,则二进制日志文件和中继日志文件将立即进行轮换,并且所有后续记录都将是未加密的。以前加密的文件不会自动解密,但服务器仍然能够读取它们。激活或停用加密时需要BINLOG_ENCRYPTION_ADMIN权限(或已弃用的SUPER权限)。组复制应用程序通道不包括在中继日志轮换请求中,因此在正常使用中,这些通道的未加密记录直到它们的日志轮换后才开始。

    有关二进制日志文件和中继日志文件加密的更多信息,请参见第 19.3.2 节,“加密二进制日志文件和中继日志文件”。

  • binlog_error_action

    命令行格式 --binlog-error-action[=value]
    系统变量 binlog_error_action
    范围 全局
    动态
    SET_VAR 提示适用
    类型 枚举
    默认值 ABORT_SERVER
    有效值 IGNORE_ERROR``ABORT_SERVER

    控制服务器遇到无法写入、刷新或同步二进制日志等错误时会发生什么,这可能导致源二进制日志不一致,副本失去同步。

    此变量默认为ABORT_SERVER,当二进制日志遇到此类错误时,服务器会停止记录并关闭。在重新启动时,恢复的过程与意外服务器停止的情况相同(参见第 19.4.2 节,“处理复制的意外停止”)。

    binlog_error_action设置为IGNORE_ERROR时,如果服务器遇到此类错误,它会继续进行当前事务,记录错误然后停止记录,并继续执行更新。要恢复二进制日志记录,必须重新启用log_bin,这需要重新启动服务器。此设置与 MySQL 的旧版本向后兼容。

  • binlog_expire_logs_seconds

    命令行格式 --binlog-expire-logs-seconds=#
    系统变量 binlog_expire_logs_seconds
    范围 全局
    动态
    SET_VAR 提示适用
    类型 整数
    默认值 2592000
    最小值 0
    最大值 4294967295
    单位

    设置二进制日志过期时间(以秒为单位)。在过期后,二进制日志文件可以自动删除。可能的删除发生在启动时和二进制日志刷新时。日志刷新的发生如第 7.4 节,“MySQL 服务器日志”所示。

    默认的二进制日志过期时间为 2592000 秒,相当于 30 天(302460*60 秒)。如果在启动时既没有为binlog_expire_logs_seconds设置值,也没有为废弃的系统变量expire_logs_days设置值,则使用默认值。如果在启动时为binlog_expire_logs_secondsexpire_logs_days中的一个变量设置了非零值,则该值将用作二进制日志的过期时间。如果在启动时为这两个变量都设置了非零值,则binlog_expire_logs_seconds的值将用作二进制日志的过期时间,而expire_logs_days的值将被忽略并显示警告消息。

    在运行时,如果另一个变量binlog_expire_logs_secondsexpire_logs_days当前已设置为非零值,则不能将binlog_expire_logs_secondsexpire_logs_days设置为非零值。由于binlog_expire_logs_seconds的默认值为非零,因此必须在设置或更改expire_logs_days的值之前明确将binlog_expire_logs_seconds设置为零。

    从 MySQL 8.0.29 开始,可以通过将系统变量binlog_expire_logs_auto_purge设置为OFF来禁用二进制日志的自动清理。这优先于binlog_expire_logs_seconds的任何设置。

    在 MySQL 8.0.28 及更早版本中,要禁用二进制日志的自动清理,必须明确为binlog_expire_logs_seconds指定值为 0,并且不为expire_logs_days指定值。为了与早期版本兼容,如果您明确为expire_logs_days指定值为 0,并且不为binlog_expire_logs_seconds指定值,则也会禁用自动清理。在这种情况下,不会应用binlog_expire_logs_seconds的默认值。

    要手动删除二进制日志文件,请使用PURGE BINARY LOGS语句。参见 Section 15.4.1.1, “PURGE BINARY LOGS Statement”。

  • binlog_expire_logs_auto_purge

    命令行格式 --binlog-expire-logs-auto-purge={ON|OFF}
    引入版本 8.0.29
    系统变量 binlog_expire_logs_auto_purge
    作用范围 全局
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 ON

    启用或禁用二进制日志文件的自动清理。将此变量设置为ON(默认值)启用自动清理;将其设置为OFF禁用自动清理。等待清理的间隔由binlog_expire_logs_secondsexpire_logs_days控制。

    注意

    即使binlog_expire_logs_auto_purgeON,将binlog_expire_logs_secondsexpire_logs_days都设置为0也会阻止自动清理操作的进行。

    此变量对PURGE BINARY LOGS没有影响。

  • binlog_format

    命令行格式 --binlog-format=format
    已弃用 8.0.34
    系统变量 binlog_format
    范围 全局,会话
    动态
    SET_VAR提示适用
    类型 枚举
    默认值 ROW
    有效值 MIXED``STATEMENT``ROW

    此系统变量设置了二进制日志记录格式,可以是STATEMENTROWMIXED中的任何一种。(参见第 19.2.1 节,“复制格式”。)当服务器启用二进制日志记录时,即log_bin系统变量设置为ON时,设置生效。在 MySQL 8.0 中,默认情况下启用二进制日志记录,并且默认使用基于行的格式。

    注意

    binlog_format在 MySQL 8.0.34 中已被弃用,并可能在将来的 MySQL 版本中被移除。这意味着除基于行的日志记录格式外的其他格式的支持也可能在将来的版本中被移除。因此,任何新的 MySQL 复制设置应仅使用基于行的日志记录。

    binlog_format可以在启动时或运行时设置,但在某些情况下,在运行时更改此变量是不可能的,或会导致复制失败,如后文所述。

    默认值为ROW例外:在 NDB Cluster 中,默认值为MIXED;不支持基于语句的复制。

    设置此系统变量的会话值是受限制的操作。会话用户必须具有足够权限来设置受限制的会话变量。请参见第 7.1.9.1 节,“系统变量权限”。

    更改此变量生效的规则和效果持续时间与其他 MySQL 服务器系统变量相同。有关更多信息,请参见第 15.7.6.1 节,“变量赋值的 SET 语法”。

    当指定MIXED时,将使用基于语句的复制,但有例外情况,即仅当仅有基于行的复制保证会产生正确结果时才会使用基于行的复制。例如,当语句包含可加载函数或UUID()函数时会发生这种情况。

    有关在设置每个二进制日志格式时如何处理存储程序(存储过程和函数、触发器和事件)的详细信息,请参见 Section 27.7,“存储程序二进制日志记录”。

    在以下情况下无法在运行时切换复制格式:

    • 无法从存储函数或触发器内部更改复制格式。

    • 如果会话有打开的临时表,则无法为该会话更改复制格式(SET @@SESSION.binlog_format)。

    • 如果任何复制通道有打开的临时表,则无法全局更改复制格式(SET @@GLOBAL.binlog_formatSET @@PERSIST.binlog_format)。

    • 如果任何复制通道应用程序线程当前正在运行,则无法全局更改复制格式(SET @@GLOBAL.binlog_formatSET @@PERSIST.binlog_format)。

    在任何情况下尝试切换复制格式(或尝试设置当前复制格式)都会导致错误。但是,您可以随时使用PERSIST_ONLYSET @@PERSIST_ONLY.binlog_format)来更改复制格式,因为此操作不会修改运行时全局系统变量的值,并且只在服务器重新启动后生效。

    当存在任何临时表时不建议在运行时切换复制格式,因为仅在使用基于语句的复制时才记录临时表,而在基于行的复制和混合复制中,它们不会被记录���

    在复制源服务器上更改日志格式不会导致副本更改其日志格式以匹配。在复制正在进行时切换复制格式可能会导致问题,如果副本启用了二进制日志记录,并且更改导致副本使用STATEMENT格式记录日志,而源使用ROWMIXED格式记录日志。副本无法将以ROW记录格式接收的二进制日志条目转换为STATEMENT格式以在自己的二进制日志中使用,因此此情况可能导致复制失败。有关更多信息,请参见 Section 7.4.4.2,“设置二进制日志格式”。

    二进制日志格式会影响以下服务器选项的行为:

    • --replicate-do-db

    • --replicate-ignore-db

    • --binlog-do-db

    • --binlog-ignore-db

    这些效果在���个选项的描述中有详细讨论。

  • binlog_group_commit_sync_delay

    命令行格式 --binlog-group-commit-sync-delay=#
    系统变量 binlog_group_commit_sync_delay
    范围 全局
    动态
    SET_VAR提示适用
    类型 整数
    默认值 0
    最小值 0
    最大值 1000000
    单位 微秒

    控制二进制日志提交在将二进制日志文件同步到磁盘之前等待多少微秒。默认情况下,binlog_group_commit_sync_delay设置为 0,意味着没有延迟。将binlog_group_commit_sync_delay设置为微秒延迟可以使更多事务一起同步到磁盘,从而减少提交一组事务的总时间,因为较大的组需要更少的时间单位来完成。

    当设置sync_binlog=0sync_binlog=1时,binlog_group_commit_sync_delay指定的延迟将应用于每个二进制日志提交组在同步之前(或在sync_binlog=0的情况下,在继续之前)。当将sync_binlog设置为大于 1 的值n时,延迟将应用于每n个二进制日志提交组之后。

    设置binlog_group_commit_sync_delay可以增加任何具有(或在故障转移后可能具有)副本的服务器上并因此可以增加副本的并行执行的提交事务数量。要从这种效果中受益,副本服务器必须设置replica_parallel_type=LOGICAL_CLOCK(从 MySQL 8.0.26 开始)或slave_parallel_type=LOGICAL_CLOCK,并且当binlog_transaction_dependency_tracking=COMMIT_ORDER也设置时效果更显著。在调整binlog_group_commit_sync_delay的设置时,重要的是考虑源的吞吐量和副本的吞吐量。

    设置binlog_group_commit_sync_delay也可以减少在任何具有二进制日志的服务器(源或副本)上对二进制日志执行fsync()调用的次数。

    请注意,设置binlog_group_commit_sync_delay会增加服务器上事务的延迟,可能会影响客户端应用程序。此外,在高并发工作负载下,延迟可能增加争用,从而降低吞吐量。通常,设置延迟的好处超过了缺点,但应始终进行调整以确定最佳设置。

  • binlog_group_commit_sync_no_delay_count

    命令行格式 --binlog-group-commit-sync-no-delay-count=#
    系统变量 binlog_group_commit_sync_no_delay_count
    范围 全局
    动态
    SET_VAR提示适用
    类型 整数
    默认值 0
    最小值 0
    最大值 100000

    在由binlog_group_commit_sync_delay指定的当前延迟中放弃之前等待的最大事务数。如果binlog_group_commit_sync_delay设置为 0,则此选项无效。

  • binlog_max_flush_queue_time

    命令行格式 --binlog-max-flush-queue-time=#
    已弃用
    系统变量 binlog_max_flush_queue_time
    范围 全局
    动态
    SET_VAR提示适用
    类型 整数
    默认值 0
    最小值 0
    最大值 100000
    单位 微秒

    binlog_max_flush_queue_time已被弃用,并标记为在未来的 MySQL 版本中最终移除。以前,此系统变量控制了继续从刷新队列中读取事务的时间(以微秒为单位),然后进行组提交。它不再起作用。

  • binlog_order_commits

    命令行格式 --binlog-order-commits[={OFF|ON}]
    系统变量 binlog_order_commits
    范围 全局
    动态
    SET_VAR提示适用
    类型 布尔值
    默认值 ON

    当在复制源服务器上启用此变量(默认情况下)时,发给存储引擎的事务提交指令在单个线程上串行化,因此事务总是按照写入二进制日志的顺序提交。禁用此变量允许使用多个线程发出事务提交指令。与二进制日志组提交结合使用,这可以防止单个事务的提交速率成为吞吐量的瓶颈,并可能产生性能改进。

    事务在所有涉及的存储引擎确认事务准备提交时被写入二进制日志。然后二进制日志组提交逻辑在其写入二进制日志后提交一组事务。当禁用binlog_order_commits时,由于使用多个线程进行此过程,提交组中的事务可能按照不同于二进制日志中的顺序提交。(来自单个客户端的事务总是按照时间顺序提交。)在许多情况下,这并不重要,因为在单独事务中执行的操作应该产生一致的结果,如果不是这种情况,则应该使用单个事务。

    如果您希望确保源端和多线程复制的事务历史保持一致,请在复制端设置slave_preserve_commit_order=1

  • binlog_rotate_encryption_master_key_at_startup

    命令行格式 --binlog-rotate-encryption-master-key-at-startup[={OFF|ON}]
    引入版本 8.0.14
    系统变量 binlog_rotate_encryption_master_key_at_startup
    作用范围 全局
    动态
    SET_VAR Hint Applies
    类型 布尔值
    默认值 OFF

    指定在服务器启动时是否会轮换二进制日志主密钥。二进制日志主密钥是用于加密服务器上的二进制日志文件和中继日志文件的文件密码的二进制日志加密密钥。当启用二进制日志加密(binlog_encryption=ON)时,首次启动服务器时会生成一个新的二进制日志加密密钥,并用作二进制日志主密钥。如果 binlog_rotate_encryption_master_key_at_startup 系统变量也设置为 ON,每当服务器重新启动时,会生成一个进一步的二进制日志加密密钥,并用作所有后续二进制日志文件和中继日志文件的二进制日志主密钥。如果 binlog_rotate_encryption_master_key_at_startup 系统变量设置为 OFF,即默认情况下,服务器重新启动后会再次使用现有的二进制日志主密钥。有关二进制日志加密密钥和二进制日志主密钥的更多信息,请参见 Section 19.3.2, “Encrypting Binary Log Files and Relay Log Files”。

  • binlog_row_event_max_size

    命令行格式 --binlog-row-event-max-size=#
    系统变量 (≥ 8.0.14) binlog_row_event_max_size
    范围 (≥ 8.0.14) 全局
    动态 (≥ 8.0.14)
    SET_VAR 提示适用 (≥ 8.0.14)
    类型 整数
    默认值 8192
    最小值 256
    最大值 (64 位平台) 18446744073709551615
    最大值 (32 位平台) 4294967295
    单位 字节

    当使用基于行的二进制日志记录时,此设置是行基二进制日志事件的最大大小的软限制,以字节为单位。在可能的情况下,存储在二进制日志中的行被分组为大小不超过此设置值的事件。如果无法拆分事件,则最大大小可能会超过。默认值为 8192 字节。

    此全局系统变量是只读的,只能在服务器启动时设置。因此,其值只能通过在 SET 语句中使用 PERSIST_ONLY 关键字或 @@persist_only 限定符来修改。

  • binlog_row_image

    命令行格式 --binlog-row-image=image_type
    系统变量 binlog_row_image
    范围 全局,会话
    动态
    SET_VAR 提示适用
    类型 枚举
    默认值 full
    有效值 full(记录所有列)minimal(仅记录更改的列和用于识别行的列)noblob(记录所有列,除了不需要的 BLOB 和 TEXT 列)

    对于 MySQL 基于行的复制,此变量确定如何将行图像写入二进制日志。

    设置此系统变量的会话值是受限制的操作。会话用户必须具有足够权限来设置受限制的会话变量。请参阅 第 7.1.9.1 节,“系统变量权限”。

    在 MySQL 基于行的复制中,每个行更改事件包含两个图像,一个“前”图像,其列与搜索要更新的行匹配,以及包含更改的“后”图像。通常,MySQL 记录完整行(即所有列)的前后图像。但是,并不严格要求在两个图像中都包含每一列,我们通常可以通过仅记录实际需要的列来节省磁盘、内存和网络使用。

    注意

    删除行时,仅记录前图像,因为删除后没有更改的值需要传播。插入行时,仅记录后图像,因为没有现有行需要匹配。仅在更新行时,才需要前后图像,并且两者都写入二进制日志。

    对于前图像,只需要记录一组最小列,以唯一标识行。如果包含行的表具有主键,则只会将主键列写入二进制日志。否则,如果表具有所有列均为 NOT NULL 的唯一键,则只需要记录唯一键中的列。 (如果表既没有主键也没有不带任何 NULL 列的唯一键,则必须在前图像中使用并记录所有列。)对于后图像,只需要记录实际更改的列。

    您可以使用 binlog_row_image 系统变量使服务器记录完整或最小行。实际上,该变量可以取以下三个可能的值,如下列表所示:

    • full:记录前图像和后图像中的所有列。

    • minimal:仅记录前图像中用于识别要更改的行的列;仅记录 SQL 语句指定的值或由自增生成的后图像中的列。

    • noblob:记录所有列(与 full 相同),但不记录不需要识别行或未更改的 BLOBTEXT 列。

    注意

    NDB Cluster 不支持此变量;设置它不会影响对NDB表的日志记录。

    默认值为full

    当使用minimalnoblob时,仅当源表和目标表均满足以下条件时,删除和更新才能正确工作:

    • 所有列必须存在且顺序相同;每列必须使用与另一表中对应列相同的数据类型。

    • 表必须具有相同的主键定义。

    (换句话说,表必须相同,可能除了不是表主键的索引之外。)

    如果不满足这些条件,则可能目标表中的主键列值不足以为删除或更新提供唯一匹配。在这种情况下,不会发出警告或错误;源表和副本会默默地发生分歧,从而破坏一致性。

    当二进制日志格式为STATEMENT时,设置此变量不起作用。当binlog_formatMIXED时,binlog_row_image的设置将应用于使用基于行格式记录的更改,但此设置对作为语句记录的更改没有影响。

    在全局或会话级别设置binlog_row_image不会导致隐式提交;这意味着可以在事务进行中��改此变量而不影响事务。

  • binlog_row_metadata

    命令行格式 --binlog-row-metadata=metadata_type
    系统变量 binlog_row_metadata
    范围 全局
    动态
    SET_VAR提示适用
    类型 枚举
    默认值 MINIMAL
    有效值 FULL(包括所有元数据)MINIMAL(限制包含的元数据)

    配置在使用基于行的日志记录时向二进制日志添加的表元数据的数量。当设置为MINIMAL时,默认情况下,只记录与SIGNED标志、列字符集和几何类型相关的元数据。当设置为FULL时,将记录完整的表元数据,例如列名、ENUMSET字符串值、PRIMARY KEY信息等。

    扩展元数据具有以下目的:

    • 副本使用元数据在其表结构与源表不同的情况下传输数据。

    • 外部软件可以使用元数据解码行事件并将数据存储到外部数据库,例如数据仓库。

  • binlog_row_value_options

    命令行格式 --binlog-row-value-options=#
    系统变量 binlog_row_value_options
    范围 全局,会话
    动态
    SET_VAR提示适用
    类型 设置
    默认值
    有效值 PARTIAL_JSON

    当设置为PARTIAL_JSON时,这将启用一种节省空间的二进制日志格式,用于修改 JSON 文档中仅有小部分内容的更新,这会导致基于行的复制仅将 JSON 文档的修改部分写入二进制日志中的更新后图像,而不是写入完整文档(参见 JSON 值的部分更新)。这适用于使用任何JSON_SET()JSON_REPLACE()JSON_REMOVE()序列修改 JSON 列的UPDATE语句。如果服务器无法生成部分更新,则使用完整文档。

    默认值是一个空字符串,这会禁用该格式的使用。要取消binlog_row_value_options并恢复写入完整 JSON 文档,将其值设置为空字符串。

    设置此系统变量的会话值是一项受限制的操作。会话用户必须具有足够权限来设置受限制的会话变量。请参阅第 7.1.9.1 节,“系统变量权限”。

    binlog_row_value_options=PARTIAL_JSON仅在启用二进制日志记录且binlog_format设置为ROWMIXED时生效。基于语句的复制始终仅记录 JSON 文档的修改部分,而不管为binlog_row_value_options设置了任何值。为了最大化节省的空间量,请与此选项一起使用binlog_row_image=NOBLOBbinlog_row_image=MINIMALbinlog_row_image=FULL保存的空间比这两者少,因为完整的 JSON 文档存储在前图像中,而部分更新仅存储在后图像中。

    mysqlbinlog输出包括以使用BINLOG语句编码为 base-64 字符串的事件形式的部分 JSON 更新。如果指定了--verbose选项,mysqlbinlog将以可读的 JSON 形式使用伪 SQL 语句显示部分 JSON 更新。

    MySQL 复制在副本上无法应用修改到 JSON 文档时会生成错误。这包括找不到路径的情况。请注意,即使有此类和其他安全检查,如果副本上的 JSON 文档与源上的不同,并且应用了部分更新,仍然存在在副本上生成有效但意外的 JSON 文档的理论可能性。

  • binlog_rows_query_log_events

    命令行格式 --binlog-rows-query-log-events[={OFF|ON}]
    系统变量 binlog_rows_query_log_events
    范围 全局,会话
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 OFF

    此系统变量仅影响基于行的日志记录。启用时,会导致服务器将信息性日志事件(如行查询日志事件)写入其二进制日志中。此信息可用于调试和相关目的,例如在无法从行更新中重建时获取源上发出的原始查询。

    设置此系统变量的会话值是受限制的操作。会话用户必须具有足够权限来设置受限制的会话变量。请参阅第 7.1.9.1 节,“系统变量权限”。

    这些信息事件通常被 MySQL 程序忽略,读取二进制日志时不会引起任何问题,因此在复制或从备份中恢复时也不会有问题。要查看它们,请通过使用 mysqlbinlog 的--verbose选项两次增加详细程度,可以是-vv--verbose --verbose

  • binlog_stmt_cache_size |

    命令行格式 --binlog-stmt-cache-size=#
    系统变量 binlog_stmt_cache_size
    范围 全局
    动态
    SET_VAR 提示适用
    类型 整数
    默认值 32768
    最小值 4096
    最大值(64 位平台) 18446744073709547520
    最大值(32 位平台) 4294963200
    单位 字节
    块大小 4096

    用于二进制日志的内存缓冲区大小,用于保存在事务期间发出的非事务性语句。

    当服务器上启用了二进制日志记录(使用log_bin系统变量设置为 ON),如果服务器支持任何事务存储引擎,则为每个客户端分配单独的二进制日志事务和语句缓存。如果事务中使用的非事务性语句的数据超过内存缓冲区中的空间,则多余的数据将存储在临时文件中。当服务器上激活二进制日志加密时,内存缓冲区不加密,但(从 MySQL 8.0.17 开始)用于保存二进制日志缓存的任何临时文件是加密的。在每个事务提交后,通过清除内存缓冲区并截断使用的临时文件来重置二进制日志语句缓存。

    如果您在事务中经常使用大型非事务性语句,可以增加此缓存大小以通过减少或消除写入临时文件的需求来获得更好的性能。Binlog_stmt_cache_useBinlog_stmt_cache_disk_use状态变量可用于调整此变量的大小。请参阅第 7.4.4 节,“二进制日志”。

    binlog_cache_size系统变量设置事务缓存的大小。

  • binlog_transaction_compression

    命令行格式 --binlog-transaction-compression[={OFF|ON}]
    引入版本 8.0.20
    系统变量 binlog_transaction_compression
    范围 全局,会话
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 OFF

    启用对在此服务器上写入二进制日志文件的事务的压缩。OFF是默认设置。使用binlog_transaction_compression_level_zstd系统变量设置用于压缩的 zstd 算法级别。

    启用二进制日志事务压缩后,事务负载将被压缩,然后作为单个事件(Transaction_payload_event)写入二进制日志文件。压缩的事务负载在发送到副本、其他 Group Replication 组成员或诸如mysqlbinlog等客户端时仍保持压缩状态,并且在中继日志中仍以压缩状态写入。因此,二进制日志事务压缩既节省了事务发起者和接收者(以及它们的备份)的存储空间,又在服务器实例之间发送事务时节省了网络带宽。

    要使binlog_transaction_compression=ON直接生效,必须在服务器上启用二进制日志记录。当 MySQL 服务器实例没有二进制日志时,如果它是从 MySQL 8.0.20 版本开始的,它可以接收、处理和显示压缩的事务负载,而不管其对binlog_transaction_compression的值如何。这些服务器实例接收的压缩事务负载以压缩状态写入中继日志,因此它们间接受益于复制拓扑中其他服务器执行的压缩。

    此系统变量在事务上下文中无法更改。设置此系统变量的会话值是受限操作。会话用户必须具有足够权限来设置受限会话变量。请参见第 7.1.9.1 节,“系统变量权限”。

    有关二进制日志事务压缩的更多信息,包括哪些事件被压缩,哪些事件不被压缩,以及在使用事务压缩时行为的变化,请参见第 7.4.4.5 节,“二进制日志事务压缩”。

    在 NDB 8.0.31 之前:在服务器运行时设置此变量对NDB表的事务日志记录没有影响。可以通过在命令行或选项文件中启动 MySQL 时使用--binlog-transaction-compression=ON来为NDB表启用二进制日志事务压缩,但不能在服务器运行时启用或禁用。

    在 NDB 8.0.31 及更高版本中:您可以使用ndb_log_transaction_compression系统变量来为NDB启用此功能。此外,在命令行或my.cnf文件中设置--binlog-transaction-compression=ON会导致在服务器启动时启用ndb_log_transaction_compression。有关该变量的详细信息,请参阅变量的描述。

  • binlog_transaction_compression_level_zstd

    命令行格式 --binlog-transaction-compression-level-zstd=#
    引入 8.0.20
    系统变量 binlog_transaction_compression_level_zstd
    范围 全局,会话
    动态
    SET_VAR 提示适用
    类型 整数
    默认值 3
    最小值 1
    最大值 22

    设置此服务器上的二进制日志事务压缩级别,该功能由binlog_transaction_compression系统变量启用。该值是一个整数,确定压缩工作量,从 1(最低工作量)到 22(最高工作量)。如果不指定此系统变量,则压缩级别设置为 3。

    随着压缩级别的增加,数据压缩比例增加,从而减少了事务负载所需的存储空间和网络带宽。然而,数据压缩所需的工作量也会增加,消耗源服务器上的时间、CPU 和内存资源。压缩工作量的增加与数据压缩比例的增加之间并没有线性关系。

    此系统变量不能在事务上下文中更改。设置此系统变量的会话值是一项受限制的操作。会话用户必须具有足够权限来设置受限制的会话变量。请参阅第 7.1.9.1 节,“系统变量权限”。

    此变量对NDB表的事务日志记录没有影响;在 NDB Cluster 8.0.31 及更高版本中,您可以改用ndb_log_transaction_compression_level_zstd

  • binlog_transaction_dependency_tracking

    命令行格式 --binlog-transaction-dependency-tracking=value
    已弃用 8.0.35
    系统变量 binlog_transaction_dependency_tracking
    范围 全局
    动态
    SET_VAR提示适用
    类型 枚举
    默认值 COMMIT_ORDER
    有效值 COMMIT_ORDER``WRITESET``WRITESET_SESSION

    对于具有多线程副本的复制源服务器(副本上的replica_parallel_workersslave_parallel_workers大于 0),binlog_transaction_dependency_tracking指定源mysqld生成的依赖信息的方式,该信息写入二进制日志以帮助副本确定哪些事务可以并行执行。

    复制源写入的依赖信息使用逻辑时间戳表示。(因此,设置此变量要求replica_parallel_typeslave_parallel_type已设置为LOGICAL_CLOCK。)每个事务有两个逻辑时间戳,如下所示:

    • sequence_number:对于给定二进制日志中的第一个事务,此值为 1,对于第二个事务为 2,依此类推。每个二进制日志文件中的编号重新从 1 开始。

    • last_committed:这指的是与当前事务发生冲突的最近提交事务的sequence_number。此值始终小于sequence_number

    binlog_transaction_dependency_tracking控制用于计算这些逻辑时间戳的方案的选择。可用选择如下:

    • COMMIT_ORDER:如果第一个事务的提交时间窗口与第二个事务的提交时间窗口重叠,则认为两个事务是独立的。这是默认值。

      提交时间窗口从事务的最后一条语句执行后立即开始,并在存储引擎提交结束后立即结束。由于事务在这两个时间点之间持有所有行锁,我们知道它们不会更新相同的行。

    • WRITESET:逻辑时间戳基于COMMIT_ORDER与基于事务的写入集的第二方案的组合计算。事务中的每一行都向事务的写入集添加一个或多个哈希集,每个唯一键在行中都有一个。 (如果没有唯一的非空键,则使用行的哈希。)这包括已删除和已插入的行;对于更新的行,旧行和新行也包括在内。

      如果两个事务的写入集重叠,即两个事务的写入集中存在相同的某个数字(哈希),则认为这两个事务存在冲突。此外,由于写入集的计算方式,存在周期性的序列化点,使得写入集计算过程将序列化点之后的每个事务视为与序列化点之前的每个事务存在冲突。序列化点仅影响WRITESET算法计算的依赖关系;序列化点两侧的事务可能具有重叠的提交时间窗口,因此尽管如此,在副本上可以并行化。DDL 语句、更新具有外键的表的事务以及会话值与全局值不同的transaction_write_set_extraction的事务会触发序列化点。如果自上一个序列化点以来提交的事务生成了至少binlog_transaction_dependency_history_size个唯一哈希,则还会强制执行序列化点。

      为了使多线程复制与 NDB 集群复制一起工作(NDB 8.0.33 及更高版本支持),源端必须将此变量设置为WRITESET。有关更多信息,请参见第 25.7.11 节,“使用多线程应用程序的 NDB 集群复制”。

    • WRITESET_SESSION: 如果以下任一语句为真,则认为两个事务存在依赖关系:

      • 事务根据WRITESET存在依赖关系。

      • 事务在同一用户会话中提交。

    WRITESETWRITESET_SESSION模式下,源端使用COMMIT_ORDER为具有空或部分写入集的事务、更新没有主键或唯一键的表的事务以及更新外键关系中的父表的事务生成依赖信息。

    要将binlog_transaction_dependency_tracking设置为WRITESETWRITESET_SESSION,必须将transaction_write_set_extraction设置为OFF之外的值;默认值(XXHASH64)已足够。只要binlog_transaction_dependency_tracking的值为WRITESETWRITESET_SESSION,就无法更改transaction_write_set_extraction。对于复制事务,任何值的更改在副本停止并使用STOP REPLICASTART REPLICA重新启动后才会生效。

    保留并检查最新事务更改给定行的行哈希数由binlog_transaction_dependency_history_size的值确定。

    在从中继日志应用事务时,组复制在认证后执行自己的并行化,独立于为binlog_transaction_dependency_tracking设置的任何值,但是该变量确实影响事务如何写入组复制成员的二进制日志。这些日志中的依赖信息用于协助从捐赠者的二进制日志进行状态传输的过程,该过程在成员加入或重新加入组时发生。对于该过程,将binlog_transaction_dependency_tracking设置为WRITESET可以根据组的工作负载提高组成员的性能。

  • binlog_transaction_dependency_history_size

    命令行格式 --binlog-transaction-dependency-history-size=#
    系统变量 binlog_transaction_dependency_history_size
    作用范围 全局
    动态
    SET_VAR Hint Applies
    类型 整数
    默认值 25000
    最小值 1
    最大值 1000000

    设置在内存中保留并用于查找最后修改给定行的事务的行哈希数的上限。一旦达到这个哈希数,历史记录将被清除。

  • expire_logs_days

    命令行格式 --expire-logs-days=#
    已弃用
    系统变量 expire_logs_days
    作用范围 全局
    动态
    SET_VAR Hint Applies
    类型 整数
    默认值 0
    最小值 0
    最大值 99
    单位

    指定自动删除二进制日志文件之前的天数。expire_logs_days已弃用,您应该期望在将来的版本中将其删除。相反,请使用binlog_expire_logs_seconds,它以秒为单位设置二进制日志过期期限。如果您没有为任何系统变量设置值,则默认的过期期限为 30 天。可能的删除发生在启动时和二进制日志刷新时。如第 7.4 节,“MySQL 服务器日志”中所示,日志刷新发生。

    如果在启动时为 expire_logs_days 指定了任何非零值,并且同时指定了 binlog_expire_logs_seconds,则忽略该值,并使用 binlog_expire_logs_seconds 作为二进制日志过期期限。在这种情况下会发出警告消息。只有在未指定或指定为 0 时,启动时为 expire_logs_days 指定的非零值才会作为二进制日志过期期限。

    在运行时,如果另一个值已经被设置为非零值,你不能将 binlog_expire_logs_secondsexpire_logs_days 设置为非零值。因为 binlog_expire_logs_seconds 的默认值为非零,所以你必须在设置或更改 expire_logs_days 的值之前,显式将 binlog_expire_logs_seconds 设置为零。

    要禁用二进制日志的自动清理,请明确为 binlog_expire_logs_seconds 指定值为 0,并且不为 expire_logs_days 指定值。为了与早期版本兼容,如果明确为 expire_logs_days 指定值为 0,并且不为 binlog_expire_logs_seconds 指定值,则自动清理也会被禁用。在这种情况下,不会应用 binlog_expire_logs_seconds 的默认值。

    要手动删除二进制日志文件,请使用 PURGE BINARY LOGS 语句。参见 Section 15.4.1.1, “PURGE BINARY LOGS 语句”。

  • log_bin

    系统变量 log_bin
    作用范围 全局
    是否动态
    SET_VAR提示适用
    类型 布尔值

    显示服务器上二进制日志记录的状态,可以是启用(ON)或禁用(OFF)。启用二进制日志记录后,服务器会记录所有更改数据的语句到二进制日志中,用于备份和复制。ON表示二进制日志可用,OFF表示未使用。可以使用--log-bin选项指定二进制日志的基本名称和位置。

    在早期的 MySQL 版本中,默认情况下禁用了二进制日志记录,只有在指定--log-bin选项时才启用。从 MySQL 8.0 开始,默认情况下启用了二进制日志记录,无论是否指定了--log-bin选项,log_bin系统变量都设置为ON。唯一的例外是,如果您使用mysqld手动初始化数据目录,通过使用--initialize--initialize-insecure选项,此时默认情况下禁用了二进制日志记录。在这种情况下,可以通过指定--log-bin选项来启用二进制日志记录。

    如果在启动时指定了--skip-log-bin--disable-log-bin选项,则禁用二进制日志记录,log_bin系统变量设置为OFF。如果同时指定了其中任何一个选项和--log-bin选项,则后面指定的选项优先。

    有关二进制日志的格式和管理信息,请参阅第 7.4.4 节,“二进制日志”。

  • log_bin_basename

    系统变量 log_bin_basename
    范围 全局
    动态
    SET_VAR 提示适用
    类型 文件名

    存储二进制日志文件的基本名称和路径,可以使用--log-bin服务器选项进行设置。变量的最大长度为 256。在 MySQL 8.0 中,如果未提供--log-bin选项,则默认基本名称为binlog。为了与 MySQL 5.7 兼容,如果提供了--log-bin选项但没有字符串或为空字符串,则默认基本名称为*host_name*-bin,使用主机机器的名称。默认位置是数据目录。

  • log_bin_index

    命令行格式 --log-bin-index=file_name
    系统变量 log_bin_index
    范围 全局
    动态
    SET_VAR 提示适用
    类型 文件名

    保存二进制日志索引文件的基本名称和路径,可以使用 --log-bin-index 服务器选项进行设置。变量长度最大为 256。

  • log_bin_trust_function_creators

    命令行格式 --log-bin-trust-function-creators[={OFF|ON}]
    已弃用 8.0.34
    系统变量 log_bin_trust_function_creators
    范围 全局
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 OFF

    此变量在启用二进制日志记录时应用。它控制存储函数创建者是否可信,不会创建可能导致不安全事件写入二进制日志的存储函数。如果设置为 0(默认值),除了具有 SUPER 权限外,用户不允许创建或更改存储函数,还必须具有 CREATE ROUTINEALTER ROUTINE 权限。设置为 0 还强制要求函数必须声明具有 DETERMINISTIC 特性,或具有 READS SQL DATANO SQL 特性。如果将变量设置为 1,则 MySQL 不会强制执行这些限制以创建存储函数。此变量还适用于触发器创建。请参阅 第 27.7 节,“存储程序二进制日志记录”。

  • log_bin_use_v1_row_events

    命令行格式 --log-bin-use-v1-row-events[={OFF|ON}]
    已弃用 8.0.18
    系统变量 log_bin_use_v1_row_events
    范围 全局
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 OFF

    此只读系统变量已弃用。在服务器启动时将系统变量设置为ON,通过使用 Version 1 二进制日志行事件而不是 MySQL 5.6 默认的 Version 2 二进制日志行事件,启用了与运行 MySQL Server 5.5 及更早版本的副本机器进行基于行的复制。

  • log_replica_updates

    命令行格式 --log-replica-updates[={OFF|ON}]
    引入 8.0.26
    系统变量 log_replica_updates
    范围 全局
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 ON

    从 MySQL 8.0.26 开始,使用log_replica_updates 替代从该版本开始弃用的log_slave_updates。在 MySQL 8.0.26 之前的版本中,请使用log_slave_updates

    log_replica_updates 指定了复制服务器从复制源服务器接收的更新是否应记录到复制服务器自己的二进制日志中。

    启用此变量会导致复制服务器将从源接收并由复制 SQL 线程执行的更新写入复制服务器自己的二进制日志中。二进制日志记录由--log-bin选项控制,默认情况下启用,复制服务器上也必须启用二进制日志记录才能记录更新。请参阅第 19.1.6 节,“复制和二进制日志选项和变量”。log_replica_updates 默认启用,除非您指定--skip-log-bin来禁用二进制日志记录,此时 MySQL 也会默认禁用复制更新记录。如果需要在启用二进制日志时禁用复制更新记录,请在复制服务器启动时指定--log-replica-updates=OFF

    启用log_replica_updates 可以实现复制服务器的链式连接。例如,您可能希望使用以下安排设置复制服务器:

    A -> B -> C
    

    在这里,A 作为复制服务器 B 的源,B 作为复制服务器 C 的源。为使此工作正常,B 必须同时是源和复制服务器。启用二进制日志记录和log_replica_updates启用,这些是默认设置,从 A 接收的更新由 B 记录到其二进制日志中,因此可以传递给 C

  • log_slave_updates

    命令行格式 --log-slave-updates[={OFF|ON}]
    弃用 8.0.26
    系统变量 log_slave_updates
    范围 全局
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 ON

    从 MySQL 8.0.26 开始,log_slave_updates已被弃用,应改用别名log_replica_updates。在 MySQL 8.0.26 之前的版本中,请使用log_slave_updates

    log_slave_updates指定是否应将复制服务器从复制源服务器接收的更新记录到副本自己的二进制日志中。

    启用此变量会导致副本将从源接收并由复制 SQL 线程执行的更新写入副本自己的二进制日志中。必须还在副本上启用二进制日志记录,该记录由--log-bin选项控制,并且默认情况下已启用,才能记录更新。请参阅第 19.1.6 节,“复制和二进制日志选项和变量”。默认情况下启用log_slave_updates,除非您指定--skip-log-bin来禁用二进制日志记录,此时 MySQL 也默认禁用副本更新记录。如果需要在启用二进制日志时禁用副本更新记录,请在副本服务器启动时指定--log-slave-updates=OFF

    启用log_slave_updates可以使复制服务器链接在一起。例如,您可能希望使用以下安排设置复制服务器:

    A -> B -> C
    

    在这里,A作为副本B的源,B作为副本C的源。为了使其工作,B必须同时是源副本。启用二进制日志记录和log_slave_updates启用,这些是默认设置,从A接收的更新由B记录到其二进制日志中,因此可以传递给C

  • log_statements_unsafe_for_binlog

    命令行格式 --log-statements-unsafe-for-binlog[={OFF|ON}]
    弃用 8.0.34
    系统变量 log_statements_unsafe_for_binlog
    范围 全局
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 ON

    如果遇到错误 1592,控制生成的警告是否添加到错误日志中。

  • master_verify_checksum

    命令行格式 --master-verify-checksum[={OFF|ON}]
    已弃用 8.0.26
    系统变量 master_verify_checksum
    作用范围 全局
    动态
    SET_VAR提示适用
    类型 布尔值
    默认值 OFF

    从 MySQL 8.0.26 版本开始,master_verify_checksum 已被弃用,应改用别名 source_verify_checksum。在 MySQL 8.0.26 版本之前的发布版本中,请使用 master_verify_checksum

    启用 master_verify_checksum 会导致源通过检查校验和来验证从二进制日志中读取的事件,并在不匹配时停止并显示错误。master_verify_checksum 默认情况下是禁用的;在这种情况下,源使用二进制日志中的事件长度来验证事件,因此只有完整的事件才会从二进制日志中读取。

  • max_binlog_cache_size

    命令行格式 --max-binlog-cache-size=#
    系统变量 max_binlog_cache_size
    作用范围 全局
    动态
    SET_VAR提示适用
    类型 整数
    默认值(64 位平台) 18446744073709547520
    默认值(32 位平台) 4294967295
    最小值 4096
    最大值(64 位平台) 18446744073709547520
    最大值(32 位平台) 4294967295
    单位 字节
    块大小 4096

    如果一个事务需要的字节数超过这个值,服务器会生成一个“多语句事务需要超过 'max_binlog_cache_size' 字节的存储空间”错误。当 gtid_mode 不是 ON 时,最大推荐值为 4GB,因为在这种情况下,MySQL 无法处理大于 4GB 的二进制日志位置;当 gtid_modeON 时,这个限制不适用,服务器可以处理任意大小的二进制日志位置。

    如果由于 gtid_mode 不是 ON,或出于其他原因,您需要保证二进制日志不超过给定大小 maxsize,则应根据此处显示的公式设置此变量:

    max_binlog_cache_size < 
      (((*maxsize* - max_binlog_size) / max_connections) - 1000) / 1.2
    

    这个计算考虑了以下条件:

    • 只要在开始写入之前的大小小于max_binlog_size,服务器就会写入二进制日志。

    • 服务器不会写入单个事务,而是一组事务。一组中可能的最大事务数等于max_connections

    • 服务器会写入未包含在缓存中的数据。这包括每个事件的 4 字节校验和;虽然这只会增加不到事务大小的 20%,但这个量是不可忽略的。此外,服务器会为每个事务写入一个Gtid_log_event;每个事件可能会使写入二进制日志的内容增加另外 1 KB。

    max_binlog_cache_size仅设置事务缓存的大小;语句缓存的上限由max_binlog_stmt_cache_size系统变量控制。

    max_binlog_cache_size对会话的可见性与binlog_cache_size系统变量的可见性相匹配;换句话说,改变其值只会影响在值更改后启动的新会话。

  • max_binlog_size

    命令行格式 --max-binlog-size=#
    系统变量 max_binlog_size
    范围 全局
    动态
    SET_VAR提示适用
    类型 整数
    默认值 1073741824
    最小值 4096
    最大值 1073741824
    单位 字节
    块大小 4096

    如果写入二进制日志导致当前日志文件大小超过此变量的值,则服务器会旋转二进制日志(关闭当前文件并打开下一个文件)。最小值为 4096 字节。最大和默认值为 1GB。加密的二进制日志文件有额外的 512 字节头部,包含在max_binlog_size中。

    事务被一次性写入二进制日志,因此永远不会在多个二进制日志之间分割。因此,如果你有大事务,你可能会看到比max_binlog_size更大的二进制日志文件。

    如果max_relay_log_size为 0,则max_binlog_size的值也适用于中继日志。

    在服务器上使用 GTIDs 时,当达到max_binlog_size时,如果无法访问系统表mysql.gtid_executed以写入当前二进制日志文件中的 GTIDs,则无法旋转二进制日志。在这种情况下,服务器根据其binlog_error_action设置做出响应。如果设置为IGNORE_ERROR,服务器上会记录错误并停止二进制日志记录,或者如果设置为ABORT_SERVER,服务器将关闭。

  • max_binlog_stmt_cache_size

    命令行格式 --max-binlog-stmt-cache-size=#
    系统变量 max_binlog_stmt_cache_size
    范围 全局
    动态
    SET_VAR 提示适用
    类型 整数
    默认值 18446744073709547520
    最小值 4096
    最大值 18446744073709547520
    单位 字节
    块大小 4096

    如果事务中的非事务性语句需要的内存超过这么多字节,服务器将生成错误。最小值为 4096。32 位平台上的最大和默认值为 4GB,在 64 位平台上为 16EB(艾字节)。

    max_binlog_stmt_cache_size仅设置语句缓存的大小;事务缓存的上限完全由max_binlog_cache_size系统变量控制。

  • original_commit_timestamp

    系统变量 original_commit_timestamp
    范围 会话
    动态
    SET_VAR 提示适用
    类型 数值

    用于复制的内部使用。在副本上重新执行事务时,此值设置为事务在原始源上提交时的时间,以自纪元以来的微秒为单位。这允许原始提交时间戳在整个复制拓扑中传播。

    设置此系统变量的会话值是受限操作。会话用户必须具有REPLICATION_APPLIER权限(参见第 19.3.3 节,“复制权限检查”),或具有足够权限设置受限会话变量(参见第 7.1.9.1 节,“系统变量权限”)。但是,请注意,该变量不是供用户设置的;它是由复制基础设施自动设置的。

  • source_verify_checksum

    命令行格式 --source-verify-checksum[={OFF&#124;ON}]
    引入版本 8.0.26
    系统变量 source_verify_checksum
    作用域 全局
    动态
    SET_VAR提示适用
    类型 布尔值
    默认值 OFF

    从 MySQL 8.0.26 开始,使用source_verify_checksum代替从该版本开始已弃用的master_verify_checksum。在 MySQL 8.0.26 之前的版本中,请使用master_verify_checksum

    启用source_verify_checksum会导致源通过检查校验和来验证从二进制日志中读取的事件,并在不匹配时停止并显示错误。source_verify_checksum默认情况下是禁用的;在这种情况下,源使用二进制日志中的事件长度来验证事件,因此只有完整的事件才会从二进制日志中读取。

  • sql_log_bin

    系统变量 sql_log_bin
    作用域 会话
    动态
    SET_VAR提示适用
    类型 布尔值
    默认值 ON

    此变量控制当前会话是否启用对二进制日志的记录(假设二进制日志本身已启用)。默认值为ON。要为当前会话禁用或启用二进制日志记录,请将会话sql_log_bin变量设置为OFFON

    将此变量设置为OFF,以便在对源进行更改时暂时禁用二进制日志记录,这些更改不希望被复制到副本中。

    设置此系统变量的会话值是受限制的操作。会话用户必须具有足够权限来设置受限制的会话变量。请参阅第 7.1.9.1 节,“系统变量权限”。

    不可能在事务或子查询中设置sql_log_bin的会话值。

    将此变量设置为 OFF 可防止将 GTID 分配给二进制日志中的事务。 如果您正在使用 GTID 进行复制,这意味着即使稍后重新启用二进制日志记录,从此时开始写入日志的 GTID 也不会考虑期间发生的任何事务,因此实际上这些事务会丢失。

  • sync_binlog

    命令行格式 --sync-binlog=#
    系统变量 sync_binlog
    作用范围 全局
    动态
    SET_VAR提示适用
    类型 整数
    默认值 1
    最小值 0
    最大值 4294967295

    控制 MySQL 服务器将二进制日志同步到磁盘的频率。

    • sync_binlog=0:禁用 MySQL 服务器将二进制日志同步到磁盘。相反,MySQL 服务器依赖操作系统定期刷新二进制日志到磁盘,就像对任何其他文件一样。这个设置提供了最佳性能,但在断电或操作系统崩溃的情况下,可能会出现服务器已提交但尚未同步到二进制日志的事务。

    • sync_binlog=1:在提交事务之前将二进制日志同步到磁盘。这是最安全的设置,但由于增加了磁盘写入次数,可能会对性能产生负面影响。在断电或操作系统崩溃的情况下,二进制日志中缺失的事务仅处于准备状态。这允许自动恢复程序回滚事务,确保没有事务丢失在二进制日志中。

    • sync_binlog=*N*,其中 N 是除 0 或 1 之外的值:在收集了 N 个二进制日志提交组后,将二进制日志同步到磁盘。在断电或操作系统崩溃的情况下,可能会出现服务器已提交但尚未刷新到二进制日志的事务。这个设置可能会对性能产生负面影响,因为增加了磁盘写入次数。较高的值可以提高性能,但增加了数据丢失的风险。

    对于使用InnoDB和事务的复制设置,为了获得最大的耐久性和一致性,请使用以下设置:

    • sync_binlog=1

    • innodb_flush_log_at_trx_commit=1

    注意

    许多操作系统和一些磁盘硬件会欺骗刷新到磁盘的操作。它们可能告诉mysqld刷新已经完成,即使实际上并没有。在这种情况下,即使使用推荐的设置,事务的耐久性也无法得到保证,最坏的情况下,停电可能会损坏InnoDB数据。在 SCSI 磁盘控制器或磁盘本身中使用带电池后备的磁盘缓存可以加快文件刷新速度,并使操作更安全。您还可以尝试禁用硬件缓存中的磁盘写入缓存。

  • transaction_write_set_extraction

    命令行格式 --transaction-write-set-extraction[=value]
    已弃用 8.0.26
    系统变量 transaction_write_set_extraction
    作用域 全局,会话
    动态
    SET_VAR提示适用
    类型 枚举
    默认值 XXHASH64
    有效值 OFF``MURMUR32``XXHASH64

    此系统变量指定在事务期间提取的写入哈希的算法。默认值为XXHASH64OFF表示不收集写入集。

    transaction_write_set_extraction在 MySQL 8.0.26 中已弃用;预计将在未来的 MySQL 版本中删除。

    XXHASH64设置是 Group Replication 所必需的,用于从事务中提取写入以用于所有组成员的冲突检测和认证过程(参见 Section 20.3.1, “Group Replication Requirements”)。对于具有多线程副本的复制源服务器(在这些副本上,replica_parallel_workersslave_parallel_workers设置为大于 0 的值),其中binlog_transaction_dependency_tracking设置为WRITESETWRITESET_SESSIONtransaction_write_set_extraction不能为OFF。当前binlog_transaction_dependency_tracking的值为WRITESETWRITESET_SESSION时,不能更改transaction_write_set_extraction的值。

    截至 MySQL 8.0.14 版本,设置此系统变量的会话值是一项受限制的操作;会话用户必须具有足够的特权来设置受限制的会话变量(参见第 7.1.9.1 节,“系统变量特权”)。binlog_format必须设置为ROW才能更改transaction_write_set_extraction的值。如果更改了该值,则新值在复制事务上不会立即生效,直到副本使用STOP REPLICASTART REPLICA停止并重新启动后才会生效。

原文:dev.mysql.com/doc/refman/8.0/en/replication-options-gtids.html

19.1.6.5 全局事务 ID 系统变量

本节描述的 MySQL 服务器系统变量用于监视和控制全局事务标识符(GTIDs)。有关更多信息,请参见第 19.1.3 节,“具有全局事务标识符的复制”。

  • binlog_gtid_simple_recovery

    命令行格式 --binlog-gtid-simple-recovery[={OFF&#124;ON}]
    系统变量 binlog_gtid_simple_recovery
    范围 全局
    动态
    SET_VAR提示��用
    类型 布尔值
    默认值 ON

    此变量控制 MySQL 启动或重新启动时在搜索 GTID 时如何迭代二进制日志文件。

    binlog_gtid_simple_recovery=TRUE(这是 MySQL 8.0 中的默认值)时,gtid_executedgtid_purged的值在启动时基于最新和最旧的二进制日志文件中的Previous_gtids_log_event的值进行计算。有关计算的描述,请参见 gtid_purged 系统变量。此设置在服务器重新启动时仅访问两个二进制日志文件。如果服务器上的所有二进制日志都是使用 MySQL 5.7.8 或更高版本生成的,则始终可以安全地使用binlog_gtid_simple_recovery=TRUE

    如果服务器上存在来自 MySQL 5.7.7 或更旧版本的任何二进制日志(例如,在将较旧服务器升级到 MySQL 8.0 后),并且使用binlog_gtid_simple_recovery=TRUEgtid_executedgtid_purged 可能会在以下两种情况下被错误初始化:

    • 最新的二进制日志是由 MySQL 5.7.5 或更早版本生成的,并且对于某些二进制日志,gtid_modeON,但对于最新的二进制日志为OFF

    • 在 MySQL 5.7.7 或更早版本上发出了SET @@GLOBAL.gtid_purged语句,并且在SET @@GLOBAL.gtid_purged语句时处于活动状态的二进制日志尚未被清除。

    如果在任何情况下计算出了不正确的 GTID 集合,则即使稍后使用binlog_gtid_simple_recovery=FALSE重新启动服务器,它仍然是不正确的。如果服务器存在任何这些情况或可能存在这些情况,请在启动或重新启动服务器之前设置binlog_gtid_simple_recovery=FALSE

    当设置binlog_gtid_simple_recovery=FALSE时,计算gtid_executedgtid_purged的方法如 gtid_purged 系统变量中所述,将更改为按以下方式迭代二进制日志文件:

    • 不再使用最新的二进制日志文件中的Previous_gtids_log_event和 GTID 日志事件的值,而是从最新的二进制日志文件开始计算gtid_executed,并使用从第一个二进制日志文件中找到的Previous_gtids_log_event值。如果服务器的最近的二进制日志文件没有 GTID 日志事件,例如如果服务器最初使用了gtid_mode=ON,但稍后将服务器更改为gtid_mode=OFF,这个过程可能需要很长时间。

    • 不再使用最旧的二进制日志文件中的Previous_gtids_log_event的值,而是从最旧的二进制日志文件开始计算gtid_purged,并使用从第一个二进制日志文件中找到的非空Previous_gtids_log_event值或至少一个 GTID 日志事件的值(表示从那一点开始使用 GTID)。如果服务器的旧二进制日志文件没有 GTID 日志事件,例如如果服务器最近才设置了gtid_mode=ON,这个过程可能需要很长时间。

  • enforce_gtid_consistency

    命令行格式 --enforce-gtid-consistency[=value]
    系统变量 enforce_gtid_consistency
    范围 全局
    动态
    SET_VAR提示适用
    类型 枚举
    默认值 OFF
    有效值 OFF``ON``WARN

    根据此变量的值,服务器通过仅允许执行可以安全使用 GTID 记录的语句来强制执行 GTID 一致性。在启用基于 GTID 的复制之前,必须将此变量设置为 ON

    enforce_gtid_consistency 可配置的值为:

    • OFF:允许所有事务违反 GTID 一致性。

    • ON:不允许任何事务违反 GTID 一致性。

    • WARN:允许所有事务违反 GTID 一致性,但在这种情况下会生成警告。

    --enforce-gtid-consistency 仅在对语句进行二进制日志记录时生效。如果服务器上禁用了二进制日志记录,或者如果语句未写入二进制日志因为它们被过滤器移除,那么对于未记录的语句,GTID 一致性不会被检查或强制执行。

    enforce_gtid_consistency 设置为 ON 时,只有可以使用 GTID 安全语句记录的语句才能被记录,因此以下列出的操作不能与此选项一起使用:

    • 在事务中的 CREATE TEMPORARY TABLEDROP TEMPORARY TABLE 语句。

    • 更新既包含事务表又包含非事务表的事务或语句。有一个例外,即如果所有非事务表都是临时表,则允许在同一事务或同一语句中使用非事务 DML。

    • CREATE TABLE ... SELECT 语句,在 MySQL 8.0.21 之前。从 MySQL 8.0.21 开始,支持原子 DDL 的存储引擎允许 CREATE TABLE ... SELECT 语句。

    更多信息,请参阅 Section 19.1.3.7, “使用 GTID 限制复制”。

    在 MySQL 5.7 之前以及在该版本系列的早期版本中,布尔值enforce_gtid_consistency默认为OFF。为了与这些早期版本保持兼容性,枚举默认为OFF,并且设置--enforce-gtid-consistency而不带值被解释为将值设置为ON。该变量还具有多个文本别名用于表示值:0=OFF=FALSE1=ON=TRUE2=WARN。这与其他枚举类型不同,但保持了与先前版本中使用的布尔类型的兼容性。这些更改影响了变量返回的内容。使用SELECT @@ENFORCE_GTID_CONSISTENCYSHOW VARIABLES LIKE 'ENFORCE_GTID_CONSISTENCY'SELECT * FROM INFORMATION_SCHEMA.VARIABLES WHERE 'VARIABLE_NAME' = 'ENFORCE_GTID_CONSISTENCY',都返回文本形式,而不是数字形式。这是一个不兼容的更改,因为@@ENFORCE_GTID_CONSISTENCY对于布尔值返回数字形式,但对于SHOW和信息模式返回文本形式。

  • gtid_executed

    系统变量 gtid_executed
    范围 全局
    动态
    SET_VAR Hint Applies
    类型 字符串
    单位 GTID 集合

    当与全局范围一起使用时,此变量包含服务器上执行的所有事务和由SET gtid_purged语句设置的 GTIDs 的表示。这与SHOW MASTER STATUSSHOW REPLICA STATUS输出中的Executed_Gtid_Set列的值相同。此变量的值是一个 GTID 集合,请参阅 GTID Sets 获取更多信息。

    当服务器启动时,@@GLOBAL.gtid_executed被初始化。有关如何迭代二进制日志以填充gtid_executed的更多信息,请参阅binlog_gtid_simple_recovery。随着事务的执行或执行任何SET gtid_purged语句,GTIDs 将被添加到集合中。

    在任何给定时间可以在二进制日志中找到的事务集合等于 GTID_SUBTRACT(@@GLOBAL.gtid_executed, @@GLOBAL.gtid_purged);也就是说,所有尚未清除的二进制日志中的事务。

    执行 RESET MASTER 会导致这个变量的全局值(但不包括会话值)被重置为空字符串。除非由于 RESET MASTER 而清除了该集合,否则 GTID 不会从该集合中删除。

  • gtid_executed_compression_period

    命令行格式 --gtid-executed-compression-period=#
    系统变量 gtid_executed_compression_period
    作用域 全局
    动态
    SET_VAR 提示适用
    类型 整数
    默认值(≥ 8.0.23) 0
    默认值(≤ 8.0.22) 1000
    最小值 0
    最大值 4294967295

    每处理这么多事务时,压缩 mysql.gtid_executed 表。当服务器启用二进制日志记录时,不会使用这种压缩方法,而是在每次二进制日志轮换时压缩 mysql.gtid_executed 表。当服务器禁用二进制日志记录时,压缩线程会休眠,直到执行了指定数量的事务,然后唤醒以执行 mysql.gtid_executed 表的压缩。将此系统变量的值设置为 0 表示线程永远不会唤醒,因此不会使用这种显式压缩方法。相反,压缩会根据需要隐式发生。

    从 MySQL 8.0.17 开始,InnoDB 事务由一个单独的进程写入到 mysql.gtid_executed 表中,而非 InnoDB 事务。如果服务器同时存在 InnoDB 事务和非 InnoDB 事务,那么由这个系统变量控制的压缩会干扰这个进程的工作,并且可能显著减慢速度。因此,从那个版本开始,建议将 gtid_executed_compression_period 设置为 0。

    从 MySQL 8.0.23 开始,InnoDB 和非 InnoDB 事务由同一进程写入到 mysql.gtid_executed 表中,并且 gtid_executed_compression_period 的默认值为 0。

    更多信息请参见 mysql.gtid_executed 表压缩。

  • gtid_mode

    命令行格式 --gtid-mode=MODE
    系统变量 gtid_mode
    范围 全局
    动态
    SET_VAR 提示适用
    类型 枚举
    默认值 OFF
    有效值 OFF``OFF_PERMISSIVE``ON_PERMISSIVE``ON

    控制 GTID 基础日志记录是否启用以及日志可以包含什么类型的事务。您必须具有足够的权限来设置全局系统变量。请参阅第 7.1.9.1 节,“系统变量权限”。在设置gtid_mode=ON之前,必须将enforce_gtid_consistency设置为ON。在修改此变量之前,请参阅第 19.1.4 节,“在线服务器上更改 GTID 模式”。

    记录的事务可以是匿名的或者使用 GTIDs。匿名事务依赖于二进制日志文件和位置来识别特定事务。GTID 事务具有用于引用事务的唯一标识符。不同的模式包括:

    • OFF: 新事务和复制事务都必须是匿名的。

    • OFF_PERMISSIVE: 新事务是匿名的。复制事务可以是匿名的或者 GTID 事务。

    • ON_PERMISSIVE: 新事务是 GTID 事务。复制事务可以是匿名的或���GTID 事务。

    • ON: 新事务和复制事务都必须是 GTID 事务。

    从一个值更改为另一个值只能一次一步。例如,如果gtid_mode当前设置为OFF_PERMISSIVE,则可以更改为OFFON_PERMISSIVE,但不能更改为ON

    gtid_purgedgtid_executed的值是持久的,无论gtid_mode的值如何。因此,即使更改了gtid_mode的值,这些变量仍包含正确的值。

  • gtid_next

    系统变量 gtid_next
    范围 会话
    动态
    SET_VAR 提示适用
    类型 枚举
    默认值 AUTOMATIC
    有效值 AUTOMATIC``ANONYMOUS``<UUID>:<NUMBER>

    此变量用于指定下一个 GTID 是否以及如何获取。

    设置此系统变量的会话值是受限制的操作。会话用户必须具有REPLICATION_APPLIER权限(参见 Section 19.3.3, “Replication Privilege Checks”),或具有足够权限设置受限制的会话变量(参见 Section 7.1.9.1, “System Variable Privileges”)。

    gtid_next 可以取以下任一值:

    • AUTOMATIC: 使用下一个自动生成的全局事务 ID。

    • ANONYMOUS: 事务没有全局标识符,仅通过文件和位置进行标识。

    • UUID:NUMBER 格式的全局事务 ID。

    以上哪些选项有效取决于gtid_mode的设置,更多信息请参见 Section 19.1.4.1, “Replication Mode Concepts”。如果gtid_modeOFF,设置此变量不会产生任何效果。

    在将此变量设置为 UUID:NUMBER 后,事务已经提交或回滚之后,必须再次发出明确的 SET GTID_NEXT 语句,然后才能执行其他语句。

    DROP TABLEDROP TEMPORARY TABLE 在将非临时表与临时表组合使用,或者使用事务存储引擎的临时表与使用非事务存储引擎的临时表时会失败,并显示明确的错误。

  • gtid_owned

    系统变量 gtid_owned
    范围 全局,会话
    动态
    SET_VAR 提示适用
    类型 字符串
    单元 GTID 集合

    这个只读变量主要用于内部使用。其内容取决于其范围。

    • 当在全局范围内使用时,gtid_owned 保存着服务器当前正在使用的所有 GTID 的列表,以及拥有它们的线程的 ID。这个变量主要用于多线程复制,以检查事务是否已经在另一个线程上应用。应用程序线程在处理事务时始终拥有事务的 GTID,因此@@global.gtid_owned在处理过程中显示 GTID 和所有者。当事务已经提交(或回滚)时,应用程序线程释放 GTID 的所有权。

    • 当与会话范围一起使用时,gtid_owned保存当前由此会话使用并拥有的单个 GTID。此变量主要用于测试和调试在客户端通过设置gtid_next显式分配事务的 GTID 时 GTID 的使用情况。在这种情况下,@@session.gtid_owned在客户端处理事务时始终显示 GTID,直到事务已提交(或回滚)。当客户端完成处理事务时,变量将被清除。如果会话使用gtid_next=AUTOMATIC,则gtid_owned仅在事务的提交语句执行期间短暂填充,因此无法从相关会话中观察到,尽管在正确时刻读取@@global.gtid_owned时会列出。如果您有跟踪客户端在会话中处理的 GTID 的要求,可以启用由session_track_gtids系统变量控制的会话状态跟踪器。

  • gtid_purged

    系统变量 gtid_purged
    范围 全局
    动态
    SET_VAR提示适用
    类型 字符串
    单位 GTID 集合

    全局值gtid_purged系统变量(@@GLOBAL.gtid_purged)是一个 GTID 集,包含在服务器上已提交但不在服务器上任何二进制日志文件中存在的所有事务的 GTID。gtid_purgedgtid_executed的子集。gtid_purged中包含以下类别的 GTID:

    • 已在副本上以二进制日志记录禁用的事务的复制 GTID。

    • 现在已清除的二进制日志文件中写入的事务的 GTID。

    • 明确通过语句SET @@GLOBAL.gtid_purged添加到集合中的 GTID。

    当服务器启动时,全局的gtid_purged的值会被初始化为一组 GTID。有关如何计算此 GTID 集合的信息,请参阅 gtid_purged 系统变量。如果服务器上存在来自 MySQL 5.7.7 或更早版本的二进制日志,则可能需要在服务器的配置文件中设置binlog_gtid_simple_recovery=FALSE以生成正确的计算。有关需要此设置的情况的详细信息,请参阅binlog_gtid_simple_recovery的描述。

    执行RESET MASTER会导致gtid_purged的值被重置为空字符串。

    您可以设置gtid_purged的值,以记录服务器上已应用某个 GTID 集合中的事务,尽管这些事务在服务器上的任何二进制日志中都不存在。此操作的一个示例用例是在服务器上恢复一个或多个数据库的备份时,但您没有包含这些事务的相关二进制日志。

    重要提示

    GTID 仅在服务器实例上可用,直到有符号 64 位整数的非负值的数量(2 的 63 次方减 1)。如果您将gtid_purged的值设置为接近此限制的数字,后续的提交可能会导致服务器耗尽 GTID 并执行binlog_error_action指定的操作。从 MySQL 8.0.23 开始,当服务器实例接近限制时会发出警告消息。

    从 MySQL 8.0 开始,有两种方法可以设置gtid_purged的值。您可以用您指定的 GTID 集替换gtid_purged的值,或者将您指定的 GTID 集附加到已由gtid_purged持有的 GTID 集中。如果服务器没有现有的 GTIDs,例如您正在使用现有数据库的备份进行配置的空服务器,两种方法都会产生相同的结果。如果您正在恢复与服务器上已有的事务重叠的备份,例如用mysqldump(即使备份是部分的,也包括服务器上所有事务的 GTIDs)从源创建的部分转储替换受损表,使用第一种方法替换gtid_purged的值。如果您正在恢复与服务器上已有的事务不重叠的备份,例如使用来自两个不同服务器的转储进行多源复制的配置,使用第二种方法添加到gtid_purged的值。

    • 要用您指定的 GTID 集替换gtid_purged的值,请使用以下语句:

      SET @@GLOBAL.gtid_purged = 'gtid_set'
      

      gtid_set必须是当前gtid_purged值的超集,并且不能与gtid_subtract(gtid_executed,gtid_purged)相交。换句话说,新的 GTID 集合必须包括已经在gtid_purged中的任何 GTIDs,并且不能包括尚未被清除的gtid_executed中的任何 GTIDs。gtid_set也不能包括任何在@@global.gtid_owned中的 GTIDs,即当前正在服务器上处理的事务的 GTIDs。

      结果是全局值gtid_purged被设置为gtid_set,而gtid_executed的值变为gtid_set和先前gtid_executed的值的并集。

    • 要将您指定的 GTID 集附加到gtid_purged,请使用以下带有加号(+)的语句:

      SET @@GLOBAL.gtid_purged = '+gtid_set'
      

      gtid_set 绝对不能与当前值gtid_executed相交。换句话说,新的 GTID 集不能包含gtid_executed中的任何 GTID,包括已经在gtid_purged中的事务。gtid_set也不能包含任何在@@global.gtid_owned中的 GTID,即当前正在服务器上处理的事务的 GTID。

      结果是gtid_set被添加到gtid_executedgtid_purged中。

注意

如果服务器上存在来自 MySQL 5.7.7 或更早版本的任何二进制日志(例如,在将旧服务器升级到 MySQL 8.0 后),在发出SET @@GLOBAL.gtid_purged语句后,您可能需要在重新启动服务器之前在服务器的配置文件中设置binlog_gtid_simple_recovery=FALSE,否则gtid_purged可能会计算错误。有关需要此设置的情况的详细信息,请参阅binlog_gtid_simple_recovery的描述。

19.1.7 常见的复制管理任务

原文:dev.mysql.com/doc/refman/8.0/en/replication-administration.html

19.1.7.1 检查复制状态

19.1.7.2 在副本上暂停复制

19.1.7.3 跳过事务

一旦复制已经启动,它将在不需要太多常规管理的情况下执行。本节描述了如何检查复制状态,如何暂停副本,以及如何跳过副本上的失败事务。

提示

要部署多个 MySQL 实例,您可以使用 InnoDB 集群,它使您能够轻松管理一组 MySQL 服务器实例在 MySQL Shell 中。InnoDB 集群将 MySQL Group Replication 包装在一个编程环境中,使您能够轻松部署一组 MySQL 实例以实现高可用性。此外,InnoDB 集群与 MySQL Router 无缝接口,使您的应用程序可以连接到集群而无需编写自己的故障转移过程。然而,对于不需要高可用性的类似用例,您可以使用 InnoDB ReplicaSet。有关 MySQL Shell 的安装说明可以在这里找到。

原文:dev.mysql.com/doc/refman/8.0/en/replication-administration-status.html

19.1.7.1 检查复制状态

管理复制过程时最常见的任务是确保复制正在进行,并且源端和副本之间没有错误发生。

您必须在每个副本上执行的SHOW REPLICA STATUS语句提供有关副本服务器和源服务器之间连接的配置和状态的信息。从 MySQL 8.0.22 开始,SHOW SLAVE STATUS已被弃用,可以使用SHOW REPLICA STATUS代替。性能模式具有提供此信息的复制表,以更易于访问的形式呈现。请参阅第 29.12.11 节,“性能模式复制表”。

在性能模式复制表中显示的复制心跳信息可以让您检查复制连接是否活动,即使源端最近没有向副本发送事件。如果二进制日志中的更新或未发送事件的时间超过心跳间隔时间,源端会向副本发送心跳信号。源端上的MASTER_HEARTBEAT_PERIOD设置(由CHANGE MASTER TO语句设置)指定了心跳的频率,默认为副本的连接超时时间的一半(由系统变量replica_net_timeoutslave_net_timeout指定)。性能模式表replication_connection_status显示了副本最近接收到心跳信号的时间,以及接收到的心跳信号数量。

如果您使用SHOW REPLICA STATUS语句来检查单个副本的状态,则该语句提供以下信息:

mysql> SHOW REPLICA STATUS\G
*************************** 1\. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 127.0.0.1
                  Source_User: root
                  Source_Port: 13000
                Connect_Retry: 1
              Source_Log_File: master-bin.000001
          Read_Source_Log_Pos: 927
               Relay_Log_File: slave-relay-bin.000002
                Relay_Log_Pos: 1145
        Relay_Source_Log_File: master-bin.000001
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 927
              Relay_Log_Space: 1355
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Source_SSL_Allowed: No
           Source_SSL_CA_File:
           Source_SSL_CA_Path:
              Source_SSL_Cert:
            Source_SSL_Cipher:
               Source_SSL_Key:
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Source_Server_Id: 1
                  Source_UUID: 73f86016-978b-11ee-ade5-8d2a2a562feb
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 10
                  Source_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Source_SSL_Crl:
           Source_SSL_Crlpath:
           Retrieved_Gtid_Set: 73f86016-978b-11ee-ade5-8d2a2a562feb:1-3
            Executed_Gtid_Set: 73f86016-978b-11ee-ade5-8d2a2a562feb:1-3
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Source_TLS_Version:
       Source_public_key_path:
        Get_Source_public_key: 0
            Network_Namespace:

要检查状态报告中的关键字段,请查看:

  • Replica_IO_State:副本的当前状态。有关更多信息,请参阅第 10.14.5 节,“复制 I/O(接收器)线程状态” Thread States")和第 10.14.6 节,“复制 SQL 线程状态”。

  • Replica_IO_Running:用于读取源头二进制日志的 I/O(接收器)线程是否正在运行。通常情况下,你希望这个值为 Yes,除非你尚未开始复制或已经使用 STOP REPLICA 明确停止了复制。

  • Replica_SQL_Running:用于执行中继日志中事件的 SQL 线程是否正在运行。与 I/O 线程一样,这通常应该是 Yes

  • Last_IO_ErrorLast_SQL_Error:处理中继日志时 I/O(接收器)和 SQL(应用程序)线程注册的最后错误。理想情况下,这些应该为空,表示没有错误。

  • Seconds_Behind_Source:复制 SQL(应用程序)线程落后处理源头二进制日志的秒数。较高的数字(或递增的数字)可能表明复制无法及时处理源头的事件。

    Seconds_Behind_Source 为 0 的值通常可以解释为复制已经追赶上源头,但也有一些情况并非严格如此。例如,如果源头和复制之间的网络连接中断,但复制 I/O(接收器)线程尚未注意到这一点;也就是说,replica_net_timeoutslave_net_timeout 设置的时间段尚未过去。

    Seconds_Behind_Source 的瞬时值可能无法准确反映当前情况。当复制 SQL(应用程序)线程已经追赶上 I/O 时,Seconds_Behind_Source 显示为 0;但当复制 I/O(接收器)线程仍在排队新事件时,Seconds_Behind_Source 可能会显示一个较大的值,直到复制应用程序线程执行完新事件。特别是在事件具有旧时间戳的情况下,如果在相对较短的时间内多次执行 SHOW REPLICA STATUS,你可能会看到这个值在 0 和一个相对较大的值之间反复变化。

几对字段提供有关复制从源头二进制日志中读取事件并在中继日志中处理事件的进度信息:

  • (Master_Log_file, Read_Master_Log_Pos):源头二进制日志中指示复制 I/O(接收器)线程已读取事件的坐标。

  • (Relay_Master_Log_File, Exec_Master_Log_Pos):源头二进制日志中指示复制 SQL(应用程序)线程已执行从该日志接收的事件的坐标。

  • (Relay_Log_File, Relay_Log_Pos):副本中继日志中的坐标,指示复制 SQL(应用程序)线程执行中继日志的进度。这些坐标对应于前面的坐标,但是以副本中继日志坐标表示,而不是源二进制日志坐标。

在源端,您可以使用SHOW PROCESSLIST检查连接的副本的状态,以查看正在运行的进程列表。副本连接在Command字段中具有Binlog Dump

mysql> SHOW PROCESSLIST \G;
*************************** 4\. row ***************************
     Id: 10
   User: root
   Host: replica1:58371
     db: NULL
Command: Binlog Dump
   Time: 777
  State: Has sent all binlog to slave; waiting for binlog to be updated
   Info: NULL

因为是副本驱动复制过程,所以在此报告中几乎没有可用的信息。

对于使用--report-host选项启动并连接到源端的副本,源端上的SHOW REPLICAS(或在 MySQL 8.0.22 之前,SHOW SLAVE HOSTS)语句显示有关副本的基本信息。输出包括副本服务器的 ID,--report-host选项的值,连接端口和源 ID:

mysql> SHOW REPLICAS;
+-----------+----------+------+-------------------+-----------+
| Server_id | Host     | Port | Rpl_recovery_rank | Source_id |
+-----------+----------+------+-------------------+-----------+
|        10 | replica1 | 3306 |                 0 |         1 |
+-----------+----------+------+-------------------+-----------+
1 row in set (0.00 sec)

原文:dev.mysql.com/doc/refman/8.0/en/replication-administration-pausing.html

19.1.7.2 在副本上暂停复制

你可以使用STOP REPLICASTART REPLICA语句在副本上停止和启动复制。从 MySQL 8.0.22 开始,STOP SLAVESTART SLAVE已被弃用,可以使用STOP REPLICASTART REPLICA代替。

要停止源的二进制日志的处理,请使用STOP REPLICA

mysql> STOP SLAVE;
Or from MySQL 8.0.22:
mysql> STOP REPLICA;

当复制停止时,复制 I/O(接收器)线程停止从源二进制日志读取事件并将其写入中继日志,SQL 线程停止从中继日志读取事件并执行它们。您可以通过指定线程类型单独暂停 I/O(接收器)或 SQL(应用程序)线程:

mysql> STOP SLAVE IO_THREAD;
mysql> STOP SLAVE SQL_THREAD;
Or from MySQL 8.0.22:
mysql> STOP REPLICA IO_THREAD;
mysql> STOP REPLICA SQL_THREAD;

要再次开始执行,请使用START REPLICA语句:

mysql> START SLAVE;
Or from MySQL 8.0.22:
mysql> START REPLICA;

要启动特定线程,请指定线程类型:

mysql> START SLAVE IO_THREAD;
mysql> START SLAVE SQL_THREAD;
Or from MySQL 8.0.22:
mysql> START REPLICA IO_THREAD;
mysql> START REPLICA SQL_THREAD;

对于仅通过处理来自源的事件来执行更新的副本,如果要执行备份或其他任务,则仅停止 SQL 线程可能很有用。I/O(接收器)线程继续从源读取事件,但不执行它们。这使得在重新启动 SQL(应用程序)线程时更容易让副本赶上。

仅停止接收线程使中继日志中的事件能够被应用程序线程执行,直到中继日志结束的地方。当您想要暂停执行以赶上已从源接收的事件,当您想要在副本上执行管理操作但又确保它已处理到特定点的所有更新时,这可能很有用。此方法还可用于在您对源进行管理操作时暂停副本上的事件接收。停止接收线程但允许应用程序线程运行有助于确保在再次启动复制时不会有大量待执行的事件积压。

原文:dev.mysql.com/doc/refman/8.0/en/replication-administration-skip.html

19.1.7.3 跳过事务

如果由于复制事务中的事件问题而导致复制停止,则可以通过在副本上跳过失败的事务来恢复复制。在跳过事务之前,请确保复制 I/O(接收器)线程以及 SQL(应用程序)线程已停止。

首先,您需要确定导致错误的复制事件。错误的详细信息和最后成功应用的事务记录在性能模式表replication_applier_status_by_worker中。您可以使用mysqlbinlog检索和显示围绕错误发生时记录的事件。有关如何执行此操作的说明,请参阅第 9.5 节,“时间点(增量)恢复”。或者,您可以在副本上发出SHOW RELAYLOG EVENTS或在源上发出SHOW BINLOG EVENTS

在跳过事务并重新启动副本之前,请检查以下几点:

  • 停止复制的事务是否来自未知或不受信任的来源?如果是,请调查原因,以确定是否有任何安全考虑因素表明不应重新启动副本。

  • 停止复制的事务是否需要在副本上应用?如果是,请进行适当的更正并重新应用该事务,或者在副本上手动协调数据。

  • 停止复制的事务是否需要在源上应用?如果不需要,请在原始发生地的服务器上手动撤消该事务。

要跳过事务,请根据情况选择以下方法之一:

  • 当使用 GTIDs 时(gtid_modeON),请参阅第 19.1.7.3.1 节,“跳过带有 GTIDs 的事务”。

  • 当不使用 GTIDs 或正在逐步引入 GTIDs 时(gtid_modeOFFOFF_PERMISSIVEON_PERMISSIVE),请参阅第 19.1.7.3.2 节,“跳过不带 GTIDs 的事务”。

  • 如果您已经使用CHANGE REPLICATION SOURCE TOCHANGE MASTER TO语句的ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS选项在复制通道上启用了 GTID 分配,请参阅第 19.1.7.3.2 节,“跳过没有 GTIDs 的事务”。在复制通道上使用ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS与为通道引入基于 GTID 的复制不同,您不能在这些通道上使用基于 GTID 的复制的事务跳过方法。

要在跳过事务后重新启动复制,请发出START REPLICA命令,如果副本是多源副本,则带有FOR CHANNEL子句。

19.1.7.3.1 跳过带有 GTIDs 的事务

当使用 GTIDs 时(gtid_modeON),即使事务内容被过滤掉,已提交事务的 GTID 也会在副本上持久化。这个特性可以防止副本在使用 GTID 自动定位重新连接到源时检索先前被过滤的事务。它还可以用于在副本上跳过一个事务,方法是提交一个空事务来代替失败的事务。

当您已经使用CHANGE REPLICATION SOURCE TO语句的ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS选项在复制通道上启用了 GTID 分配时,这种跳过事务的方法不适用。

如果失败的事务在工作线程中生成了错误,您可以直接从性能模式表replication_applier_status_by_worker中的APPLYING_TRANSACTION字段获取其 GTID。要查看该事务是什么,请在副本上发出SHOW RELAYLOG EVENTS或在源上发出SHOW BINLOG EVENTS,并搜索输出以找到由该 GTID 引导的事务。

当您已经评估了失败的事务是否需要采取其他适当的操作(如安全考虑)后,要跳过它,请在副本上提交一个与失败事务具有相同 GTID 的空事务。例如:

SET GTID_NEXT='aaa-bbb-ccc-ddd:N';
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';

在副本上存在这个空事务意味着当您发出START REPLICA语句重新启动复制时,副本将使用自动跳过功能来忽略失败的事务,因为它看到具有该 GTID 的事务已经被应用。如果副本是多源副本,则在提交空事务时不需要指定通道名称,但在发出START REPLICA时需要指定通道名称。

请注意,如果此副本正在使用二进制日志记录,则在将来该副本成为源或主时,空事务将进入复制流。如果您需要避免这种可能性,请考虑刷新和清除副本的二进制日志,就像这个例子一样:

FLUSH LOGS;
PURGE BINARY LOGS TO 'binlog.000146';

空事务的 GTID 是持久的,但事务本身通过清除二进制日志文件而被移除。

19.1.7.3.2 跳过没有 GTID 的事务

当 GTID 未被使用或正在逐步引入时(gtid_modeOFFOFF_PERMISSIVEON_PERMISSIVE),您可以通过发出SET GLOBAL sql_replica_skip_counter语句(从 MySQL 8.0.26 开始)或SET GLOBAL sql_slave_skip_counter语句来跳过指定数量的事件。或者,您可以通过发出CHANGE REPLICATION SOURCE TOCHANGE MASTER TO语句来跳过一个或多个事件,以将源二进制日志位置向前移动。

当您在复制通道上使用ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS选项的CHANGE REPLICATION SOURCE TOCHANGE MASTER TO语句启用 GTID 分配时,这些方法也是适用的。

当您使用这些方法时,重要的是要理解,您并不一定是跳过一个完整的事务,就像之前描述的基于 GTID 的方法总是这样。这些非 GTID 方法并不知道事务的存在,而是操作事件。二进制日志被组织为一系列称为事件组的组,每个事件组由一系列事件组成。

  • 对于事务性表,一个事件组对应一个事务。

  • 对于非事务性表,一个事件组对应一个单独的 SQL 语句。

一个单独的事务可以包含对事务性和非事务性表的更改。

当您使用SET GLOBAL sql_replica_skip_counterSET GLOBAL sql_slave_skip_counter语句跳过事件,并且结果位置位于事件组的中间时,复制品会继续跳过事件,直到达到该组的末尾。然后执行将从下一个事件组开始。CHANGE REPLICATION SOURCE TOCHANGE MASTER TO语句没有此功能,因此您必须小心确定重新启动复制的正确位置,即事件组的开头。但是,使用CHANGE REPLICATION SOURCE TOCHANGE MASTER TO意味着您无需计算需要跳过的事件,就像使用SET GLOBAL sql_replica_skip_counterSET GLOBAL sql_slave_skip_counter一样,而是可以直接指定重新启动的位置。

19.1.7.3.2.1 使用SET GLOBAL sql_slave_skip_counter跳过事务

当您已经评估了失败的事务以及之前描述的任何其他适当操作(如安全考虑)后,计算您需要跳过的事件数。一个事件通常对应于二进制日志中的一个 SQL 语句,但请注意,使用AUTO_INCREMENTLAST_INSERT_ID()的语句在二进制日志中计为两个事件。当使用二进制日志事务压缩时,压缩的事务负载(Transaction_payload_event)被计为单个计数值,因此其中的所有事件都作为一个单元跳过。

如果您想跳过完整的事务,可以计算事件直到事务结束,或者只是跳过相关的事件组。请记住,使用SET GLOBAL sql_replica_skip_counterSET GLOBAL sql_slave_skip_counter时,复制品会继续跳过到事件组的末尾。确保您不要跳得太远,进入下一个事件组或事务,以免也被跳过。

发出以下SET语句,其中N是要从源跳过的事件数:

SET GLOBAL sql_slave_skip_counter = *N*

Or from MySQL 8.0.26:
SET GLOBAL sql_replica_skip_counter = *N*

如果设置了gtid_mode=ON,或者复制 I/O(接收器)和 SQL(应用程序)线程正在运行,则无法发出此语句。

SET GLOBAL sql_replica_skip_counterSET GLOBAL sql_slave_skip_counter 语句没有立即生效。当你在这个 SET 语句之后再次发出 START REPLICA 语句时,系统变量 sql_replica_skip_countersql_slave_skip_counter 的新值会生效,并且事件会被跳过。那个 START REPLICA 语句也会自动将系统变量的值设置回 0。如果复制品是多源复制品,则在发出那个 START REPLICA 语句时,FOR CHANNEL 子句是必需的。确保你命名了正确的通道,否则事件会在错误的通道上被跳过。

19.1.7.3.2.2 跳过事务使用 CHANGE MASTER TO

当你评估了失败的事务以及之前描述的任何其他适当操作(如安全考虑)后,确定源二进制日志中表示适当位置以重新启动复制的坐标(文件和位置)。这可以是导致问题的事件后的事件组的开始,或者下一个事务的开始。复制 I/O(接收器)线程在下次启动时从这些坐标开始读取源,跳过失败的事件。确保你准确地确定了位置,因为这个语句不考虑事件组。

发出以下 CHANGE REPLICATION SOURCE TOCHANGE MASTER TO 语句,其中 source_log_name 是包含重新启动位置的二进制日志文件,source_log_pos 是表示二进制日志文件中重新启动位置的数字:

CHANGE MASTER TO MASTER_LOG_FILE='*source_log_name*', MASTER_LOG_POS=*source_log_pos*;

Or from MySQL 8.0.24:
CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='*source_log_name*', SOURCE_LOG_POS=*source_log_pos*;

如果复制品是多源复制品,则必须在 CHANGE REPLICATION SOURCE TOCHANGE MASTER TO 语句中使用 FOR CHANNEL 子句来命名适当的通道。

如果 SOURCE_AUTO_POSITION=1MASTER_AUTO_POSITION=1 被设置,或者复制 I/O(接收器)和 SQL(应用程序)线程正在运行,则无法发出此语句。如果在通常设置为 SOURCE_AUTO_POSITION=1MASTER_AUTO_POSITION=1 时需要使用此跳过事务的方法,你可以在发出语句时将设置更改为 SOURCE_AUTO_POSITION=0MASTER_AUTO_POSITION=0,然后之后再将其改回。例如:

CHANGE MASTER TO MASTER_AUTO_POSITION=0, MASTER_LOG_FILE='binlog.000145', MASTER_LOG_POS=235;
CHANGE MASTER TO MASTER_AUTO_POSITION=1;

Or from MySQL 8.0.24:

CHANGE REPLICATION SOURCE TO SOURCE_AUTO_POSITION=0, SOURCE_LOG_FILE='binlog.000145', SOURCE_LOG_POS=235;
CHANGE REPLICATION SOURCE TO SOURCE_AUTO_POSITION=1;

19.2 复制实现

原文:dev.mysql.com/doc/refman/8.0/en/replication-implementation.html

19.2.1 复制格式

19.2.2 复制通道

19.2.3 复制线程

19.2.4 中继日志和复制元数据存储库

19.2.5 服务器如何评估复制过滤规则

复制基于源服务器跟踪其数据库的所有更改(更新、删除等)在其二进制日志中。二进制日志充当自服务器启动以来修改数据库结构或内容(数据)的所有事件的书面记录。通常,SELECT语句不会被记录,因为它们既不修改数据库结构也不修改内容。

连接到源的每个副本都请求二进制日志的副本。也就是说,它从源拉取数据,而不是源推送数据到副本。副本还执行接收到的二进制日志中的事件。这样做的效果是重复原始更改,就像它们在源上做的那样。表被创建或其结构被修改,数据根据最初在源上进行的更改被插入、删除和更新。

每个副本都是独立的,从源二进制日志中的更改重放在连接到源的每个副本上都是独立的。此外,因为每个副本只通过从源请求来接收二进制日志的副本,所以副本能够以自己的速度读取和更新数据库的副本,并且可以随意启动和停止复制过程,而不会影响到源端或副本端更新到最新数据库状态的能力。

有关复制实现的具体信息,请参阅第 19.2.3 节“复制线程”。

源服务器和副本定期报告有关复制过程的状态,以便您可以监视它们。有关所有与复制相关状态的描述,请参阅第 10.14 节“检查服务器线程(进程)信息”。

源的二进制日志在处理之前会被写入到副本的本地中继日志中。副本还记录有关源的二进制日志和本地中继日志的当前位置的信息。请参阅第 19.2.4 节“中继日志和复制元数据存储库”。

数据库更改在副本上根据一组规则进行过滤,这些规则根据控制事件评估的各种配置选项和变量进行应用。有关这些规则如何应用的详细信息,请参见第 19.2.5 节,“服务器如何评估复制过滤规则”。

19.2.1 复制格式

原文:dev.mysql.com/doc/refman/8.0/en/replication-formats.html

19.2.1.1 基于语句和基于行的复制的优缺点

19.2.1.2 基于行的日志记录和复制的用法

19.2.1.3 二进制日志记录中安全和不安全语句的确定

复制工作是因为写入二进制日志的事件从源读取,然后在副本上处理。根据事件类型,事件以不同格式记录在二进制日志中。使用的不同复制格式对应于事件记录在源二进制日志中时使用的二进制日志格式。二进制日志格式和复制期间使用的术语之间的关联为:

  • 当使用基于语句的二进制日志记录时,源将 SQL 语句写入二进制日志。将源复制到副本的复制通过在副本上执行 SQL 语句来完成。这称为基于语句的复制(可以缩写为 SBR),对应于 MySQL 基于语句的二进制日志记录格式。

  • 当使用基于行的日志记录时,源将事件写入二进制日志,指示如何更改单个表行。将源复制到副本的复制通过复制表示更改的事件到副本的表行来完成。这称为基于行的复制(可以缩写为 RBR)。

    基于行的日志记录是默认方法。

  • 您还可以配置 MySQL 使用基于语句和基于行的混合日志记录,具体取决于要记录的更改哪种最合适。这称为混合格式日志记录。在使用混合格式日志记录时,默认使用基于语句的日志。根据某些语句以及使用的存储引擎,日志在特定情况下会自动切换为基于行。使用混合格式的复制称为混合基于复制或混合格式复制。有关更多信息,请参见第 7.4.4.3 节“混合二进制日志记录格式”。

NDB 集群。 MySQL NDB Cluster 8.0 中的默认二进制日志记录格式为MIXED。您应该注意,NDB Cluster 复制始终使用基于行的复制,并且NDB存储引擎与基于语句的复制不兼容。有关更多信息,请参见第 25.7.2 节“NDB Cluster 复制的一般要求”。

当使用MIXED格式时,二进制日志格式部分由正在使用的存储引擎和正在执行的语句确定。有关混合格式日志记录和支持不同日志格式的规则,请参见 Section 7.4.4.3, “Mixed Binary Logging Format”。

在运行中的 MySQL 服务器中,日志格式由设置binlog_format服务器系统变量来控制。这个变量可以在会话或全局范围内设置。关于新设置何时以及如何生效的规则与其他 MySQL 服务器系统变量相同。为当前会话设置变量仅持续到该会话结束,且对其他会话不可见。全局设置变量会影响在更改后连接的客户端,但不会影响任何当前的客户端会话,包括更改变量设置的会话。要使全局系统变量设置永久生效,以便在服务器重新启动时应用,必须在选项文件中设置它。更多信息,请参见 Section 15.7.6.1, “SET Syntax for Variable Assignment”。

有条件下,您无法在运行时更改二进制日志格式,或者这样做会导致复制失败。请参见 Section 7.4.4.2, “Setting The Binary Log Format”。

更改全局binlog_format值需要足够权限来设置全局系统变量。更改会话binlog_format值需要足够权限来设置受限制的会话系统变量。请参见 Section 7.1.9.1, “System Variable Privileges”。

注意

更改二进制日志格式(binlog_format系统变量)在 MySQL 8.0.34 版中已被弃用。在将来的 MySQL 版本中,您可以期待binlog_format被完全移除,并且基于行的格式成为 MySQL 使用的唯一日志格式。

基于语句和基于行的复制格式有不同的问题和限制。要比较它们的相对优势和劣势,请参见 Section 19.2.1.1, “Advantages and Disadvantages of Statement-Based and Row-Based Replication”。

使用基于语句的复制时,可能会遇到复制存储过程或触发器的问题。您可以通过改用基于行的复制来避免这些问题。有关更多信息,请参见第 27.7 节,“存储程序二进制日志记录”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-sbr-rbr.html

19.2.1.1 基于语句和基于行的复制的优缺点

每种二进制日志格式都有其优缺点。对于大多数用户来说,混合复制格式应该提供最佳的数据完整性和性能组合。然而,如果您想在执行某些任务时利用基于语句或基于行的复制格式的特定功能,您可以使用本节中提供的信息,该信息提供了它们相对优缺点的摘要,以确定哪种最适合您的需求。

  • 基于语句的复制的优点

  • 基于语句的复制的缺点

  • 基于行的复制的优点

  • 基于行的复制的缺点

基于语句的复制的优点
  • 已验证的技术。

  • 写入日志文件的数据较少。当更新或删除影响许多行时,这导致日志文件所需的存储空间大大减少。这也意味着可以更快地进行备份和恢复操作。

  • 日志文件包含所有进行任何更改的语句,因此可以用于审计数据库。

基于语句的复制的缺点
  • 不适用于基于语句的不安全语句。 并非所有修改数据的语句(例如INSERT DELETE, UPDATE, 和 REPLACE 语句)都可以使用基于语句的复制进行复制。任何非确定性行为在使用基于语句的复制时很难复制。此类数据修改语言(DML)语句的示例包括以下内容:

    • 依赖于不确定性的可加载函数或存储程序的语句,因为这些函数或存储程序返回的值取决于除提供给它的参数之外的因素。 (然而,基于行的复制只是复制函数或存储程序返回的值,因此其对表行和数据的影响在源和副本上是相同的。)有关更多信息,请参见第 19.5.1.16 节,“调用特性的复制”。

    • 使用 LIMIT 子句而没有 ORDER BYDELETEUPDATE 语句是不确定的。参见 Section 19.5.1.18, “Replication and LIMIT”.

    • 锁定读取语句(SELECT ... FOR UPDATESELECT ... FOR SHARE)使用 NOWAITSKIP LOCKED 选项。参见 Locking Read Concurrency with NOWAIT and SKIP LOCKED.

    • 确定性可加载函数必须在副本上应用。

    • 使用以下任何函数的语句无法使用基于语句的复制正确复制:

      • LOAD_FILE()

      • UUID(), UUID_SHORT()

      • USER()

      • FOUND_ROWS()

      • SYSDATE()(除非源和副本都使用 --sysdate-is-now 选项启动)

      • GET_LOCK()

      • IS_FREE_LOCK()

      • IS_USED_LOCK()

      • MASTER_POS_WAIT()

      • RAND()

      • RELEASE_LOCK()

      • SOURCE_POS_WAIT()

      • SLEEP()

      • VERSION()

      然而,所有其他函数都可以使用基于语句的复制正确复制,包括 NOW() 等等。

      更多信息,请参见 Section 19.5.1.14, “Replication and System Functions”.

    无法使用基于语句的复制正确复制的语句将记录警告,如下所示:

    [Warning] Statement is not safe to log in statement format.
    

    在这种情况下,客户端也会收到类似的警告。客户端可以使用 SHOW WARNINGS 显示它。

  • INSERT ... SELECT 需要比基于行的复制更多的行级锁。

  • UPDATE 语句需要进行表扫描(因为 WHERE 子句中未使用索引),必须锁定比基于行的复制更多的行。

  • 对于InnoDB:使用AUTO_INCREMENTINSERT语句会阻塞其他不冲突的INSERT语句。

  • 对于复杂语句,必须在副本上评估和执行语句,然后更新或插入行。使用基于行的复制,副本只需修改受影响的行,而不执行完整语句。

  • 如果在副本上评估时出现错误,特别是在执行复杂语句时,基于语句的复制可能会随着时间逐渐增加受影响行的错误边界。请参见第 19.5.1.29 节,“复制期间的副本错误”。

  • 存储函数执行与调用语句相同的NOW()值。但是,存储过程不是这样的。

  • 确定性可加载函数必须应用于副本。

  • 表定义在源和副本上必须(几乎)完全相同。有关更多信息,请参见第 19.5.1.9 节,“源和副本上具有不同表定义的复制”。

  • 从 MySQL 8.0.22 开始,从 MySQL 授予表中读取数据(通过连接列表或子查询)但不修改它们的 DML 操作将作为非锁定读取执行,并因此不适用于基于语句的复制。有关更多信息,请参见授予表并发性。

行级复制的优势
  • 所有更改都可以复制。这是最安全的复制形式。

    注意

    更新mysql系统模式中的信息的语句,例如GRANTREVOKE以及触发器、存储过程(包括存储过程)和视图的操作,都使用基于语句的复制复制到副本。

    对于诸如CREATE TABLE ... SELECT之类的语句,从表定义生成CREATE语句,并使用基于语句的格式进行复制,而行插入则使用基于行的格式进行复制。

  • 源上需要更少的行锁,从而实现更高的并发性,适用于以下类型的语句:

    • INSERT ... SELECT

    • 带有AUTO_INCREMENTINSERT语句

    • 带有不使用键或不更改大部分检查行的WHERE子句的UPDATEDELETE语句。

  • 在复制品上,对于任何INSERTUPDATEDELETE语句,需要更少的行锁。

基于行的复制的缺点
  • RBR 可以生成更多必须记录的数据。要复制一个 DML 语句(例如UPDATEDELETE语句),基于语句的复制仅将语句写入二进制日志。相比之下,基于行的复制将每个更改的行写入二进制日志。如果语句更改了许多行,基于行的复制可能会向二进制日志写入大量数据;即使对语句进行了回滚也是如此。这还意味着制作和恢复备份可能需要更多时间。此外,为了写入数据,二进制日志的锁定时间更长,这可能会导致并发问题。使用binlog_row_image=minimal可以大大减少这种劣势。

  • 生成大型BLOB值的确定性可加载函数在基于行的复制中复制所需的时间比基于语句的复制长。这是因为记录了BLOB列值,而不是生成数据的语句。

  • 在复制品上,您无法看到从源接收并执行的语句。但是,您可以使用mysqlbinlog和选项--base64-output=DECODE-ROWS以及--verbose查看哪些数据发生了变化。

    或者,使用binlog_rows_query_log_events变量,如果启用,则在使用-vv选项时,向mysqlbinlog输出中添加一个Rows_query事件与语句。

  • 对于使用MyISAM存储引擎的表,在将它们作为基于行的事件应用到二进制日志时,对于INSERT语句,复制品上需要更强的锁定,而不是将它们作为语句应用。这意味着在使用基于行的复制时,不支持对MyISAM表的并发插入。

译文:dev.mysql.com/doc/refman/8.0/en/replication-rbr-usage.html

19.2.1.2 基于行的日志记录和复制的用法

MySQL 使用基于语句的日志记录(SBL)、基于行的日志记录(RBL)或混合格式日志。所使用的二进制日志类型会影响日志的大小和效率。因此,在基于行的复制(RBR)和基于语句的复制(SBR)之间的选择取决于您的应用程序和环境。本节描述了使用基于行格式日志时的已知问题,并描述了在复制中使用它的一些最佳实践。

欲了解更多信息,请参阅第 19.2.1 节,“复制格式”和第 19.2.1.1 节,“基于语句和基于行复制的优缺点”。

有关 NDB 集群复制特定问题的信息(依赖于基于行的复制),请参阅第 25.7.3 节,“NDB 集群复制中的已知问题”。

  • 临时表的基于行日志记录。 如第 19.5.1.31 节,“复制和临时表”所述,当使用基于行格式或(从 MySQL 8.0.4 开始)混合格式时,临时表不会被复制。有关更多信息,请参阅第 19.2.1.1 节,“基于语句和基于行复制的优缺点”。

    当使用基于行或混合格式时,临时表不会被复制,因为没有必要。此外,由于临时表只能从创建它们的线程中读取,即使使用基于语句的格式,复制它们也很少或几乎没有任何好处。

    即使已创建临时表,您可以在运行时从基于语句切换到基于行的二进制日志格式。然而,在 MySQL 8.0 中,您无法在运行时从基于行或混合格式切换到基于语句的二进制日志格式,因为在先前模式中省略了任何CREATE TEMPORARY TABLE语句。

    MySQL 服务器跟踪创建每个临时表时生效的日志记录模式。当给定的客户端会话结束时,服务器会为仍然存在且在使用基于语句的二进制日志记录时创建的每个临时表记录一个DROP TEMPORARY TABLE IF EXISTS语句。如果在创建表时使用基于行或混合格式的二进制日志记录,则不会记录DROP TEMPORARY TABLE IF EXISTS语句。在 MySQL 8.0.4 和 5.7.25 之前的版本中,无论生效的日志记录模式如何,都会记录DROP TEMPORARY TABLE IF EXISTS语句。

    当使用binlog_format=ROW时,涉及临时表的非事务性 DML 语句是允许的,只要语句影响的非事务性表都是临时表(Bug #14272672)。

  • RBL 和非事务性表的同步。 当影响到许多行时,更改集会被拆分为几个事件;当语句提交时,所有这些事件都将写入二进制日志。在副本上执行时,会对涉及的所有表进行表锁定,然后以批处理模式应用行。根据副本表的引擎使用情况,这可能有效也可能无效。

  • 延迟和二进制日志大小。 RBL 将每行的更改写入二进制日志,因此其大小可能会迅速增加。这可能会显著增加使副本上的更改与源上的更改匹配所需的时间。您应该意识到这种延迟可能对您的应用程序产生影响。

  • 读取二进制日志。 mysqlbinlog 使用BINLOG语句在二进制日志中显示基于行的事件。该语句将事件显示为一个 base 64 编码的字符串,其含义不明显。当使用--base64-output=DECODE-ROWS--verbose选项调用时,mysqlbinlog将二进制日志的内容格式化为人类可读的形式。当二进制日志事件以基于行的格式编写,并且您想要读取或从复制或数据库故障中恢复时,您可以使用此命令读取二进制日志的内容。有关更多信息,请参见 Section 6.6.9.2, “mysqlbinlog Row Event Display”。

  • 二进制日志执行错误和副本执行模式。 使用slave_exec_mode=IDEMPOTENT通常仅在 MySQL NDB Cluster 复制中有用,其中IDEMPOTENT是默认值。(参见第 25.7.10 节,“NDB Cluster Replication: 双向和循环复制”)。当系统变量replica_exec_modeslave_exec_modeIDEMPOTENT时,由于找不到原始行而无法应用来自 RBL 的更改不会触发错误或导致复制失败。这意味着可能不会在副本上应用更新,导致源和副本不再同步。当replica_exec_modeslave_exec_modeIDEMPOTENT时,延迟问题和在 RBR 中使用非事务表可能导致源和副本进一步分歧。有关replica_exec_modeslave_exec_mode的更多信息,请参见第 7.1.8 节,“服务器系统变量”。

    对于其他情况,将replica_exec_modeslave_exec_mode设置为STRICT通常足够;这是除NDB之外的存储引擎的默认值。

  • 基于服务器 ID 的过滤不受支持。 您可以通过在CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(MySQL 8.0.23 之前)中使用IGNORE_SERVER_IDS选项来基于服务器 ID 进行过滤。此选项适用于基于语句和基于行的日志格式,但在设置GTID_MODE=ON时已被弃用。另一种在某些副本中过滤更改的方法是使用包含关系@@server_id <> *id_value*子句的WHERE子句与UPDATEDELETE语句。例如,WHERE @@server_id <> 1。但是,这在基于行的日志记录中无法正常工作。要使用server_id系统变量进行语句过滤,请使用基于语句的日志记录。

  • RBL、非事务表和停止的副本。 当使用基于行的日志记录时,如果在副本线程更新非事务表时停止副本服务器,副本数据库可能会达到不一致的状态。因此,建议您对使用基于行格式复制的所有表使用事务存储引擎,如InnoDB。在关闭副本 MySQL 服务器之前使用STOP REPLICASTOP REPLICA SQL_THREAD(在 MySQL 8.0.22 之前,使用STOP slaveSTOP SLAVE SQL_THREAD)有助于防止问题发生,并且无论您使用的是哪种日志格式或存储引擎,都建议始终这样做。

译文:dev.mysql.com/doc/refman/8.0/en/replication-rbr-safe-unsafe.html

19.2.1.3 二进制日志中安全和不安全语句的确定

在 MySQL 复制中,一个语句的“安全性”指的是该语句及其效果是否可以使用基于语句的格式正确复制。如果这对于该语句是正确的,我们将该语句称为安全的;否则,我们将其称为不安全的。

通常情况下,如果一个语句是确定性的,那么它就是安全的;如果不是,则是不安全的。然而,某些非确定性函数被视为不安全(请参见非确定性函数不被视为不安全,本节后面的内容)。此外,使用浮点数数学函数结果的语句——这些函数是依赖于硬件的——总是被视为不安全(请参见第 19.5.1.12 节,“复制和浮点值”)。

安全和不安全语句的处理。 一个语句的处理方式取决于该语句是否被视为安全,并且与二进制日志格式有关(即,binlog_format的当前值)。

  • 在使用基于行的日志记录时,对于安全和不安全的语句没有区别对待。

  • 在使用混合格式日志记录时,被标记为不安全的语句将使用基于行的格式记录;被视为安全的语句将使用基于语句的格式记录。

  • 在使用基于语句的日志记录时,被标记为不安全的语句会生成相应的警告。安全的语句会正常记录。

每个被标记为不安全的语句都会生成一个警告。如果在源端执行了大量这样的语句,这可能导致错误日志文件过大。为了防止这种情况发生,MySQL 有一个警告抑制机制。每当在任何 50 秒内生成的最近 50 个ER_BINLOG_UNSAFE_STATEMENT警告超过 50 次时,警告抑制就会被启用。一旦激活,这将导致这类警告不会被写入错误日志;相反,对于每 50 个这种类型的警告,错误日志中会写入一个注释最后一个警告在最近的*N*秒内重复了*S*次。只要最近的 50 个这样的警告在 50 秒内或更短的时间内发出,这将继续进行;一旦速率降低到低于此阈值,警告将再次正常记录。警告抑制对于决定基于语句的日志记录中语句的安全性,以及如何将警告发送给客户端没有影响。MySQL 客户端仍然会为每个这样的语句接收一个警告。

更多信息,请参见 Section 19.2.1, “Replication Formats”。

被视为不安全的语句。 具有以下特征的语句被视为不安全:

  • 包含可能在副本上返回不同值的系统函数的语句。 这些函数包括FOUND_ROWS(), GET_LOCK(), IS_FREE_LOCK(), IS_USED_LOCK(), LOAD_FILE(), MASTER_POS_WAIT(), RAND(), RELEASE_LOCK(), ROW_COUNT(), SESSION_USER(), SLEEP(), SOURCE_POS_WAIT(), SYSDATE(), SYSTEM_USER(), USER(), UUID(), 和 UUID_SHORT()

    非确定性函数不被视为不安全。 尽管这些函数不是确定性的,但在记录和复制的目的上被视为安全:CONNECTION_ID(), CURDATE(), CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP(), CURTIME(),, LAST_INSERT_ID(), LOCALTIME(), LOCALTIMESTAMP(), NOW(), UNIX_TIMESTAMP(), UTC_DATE(), UTC_TIME(), 和 UTC_TIMESTAMP()

    更多信息,请参见 Section 19.5.1.14, “Replication and System Functions”。

  • 系统变量的引用。 大多数系统变量在基于语句的格式下无法正确复制。参见 Section 19.5.1.39, “复制和变量”。特殊情况请参见 Section 7.4.4.3, “混合二进制日志格式”。

  • 可加载函数。 由于我们无法控制可加载函数的操作,因此必须假定它执行不安全的语句。

  • 全文插件。 此插件在不同的 MySQL 服务器上可能表现不同;因此,依赖于它的语句可能会产生不同的结果。因此,在 MySQL 中,所有依赖全文插件的语句都被视为不安全。

  • 触发器或存储过程更新具有 AUTO_INCREMENT 列的表。 这是不安全的,因为更新行的顺序可能在源和副本上不同。

    此外,对具有包含不是此复合键的第一列的 AUTO_INCREMENT 列的复合主键的表进行INSERT是不安全的。

    更多信息,请参见 Section 19.5.1.1, “复制和 AUTO_INCREMENT”。

  • 对具有多个主键或唯一键的表执行 INSERT ... ON DUPLICATE KEY UPDATE 语句。 当针对包含多个主键或唯一键的表执行此语句时,此语句被视为不安全,因为存储引擎检查键的顺序是不确定的,MySQL 服务器更新的行取决于此顺序。

    对于具有多个唯一或主键的表进行INSERT ... ON DUPLICATE KEY UPDATE语句在基于语句的复制中被标记为不安全。 (Bug #11765650, Bug #58637)

  • 使用 LIMIT 进行更新。 检索行的顺序未指定,因此被视为不安全。参见 Section 19.5.1.18, “复制和 LIMIT”。

  • 访问或引用日志表。 系统日志表的内容可能在源和副本之间不同。

  • 事务操作后的非事务操作。 在事务中,允许任何非事务读取或写入在任何事务读取或写入之后执行被视为不安全。

    更多信息,请参见 Section 19.5.1.35, “复制和事务”。

  • 访问或引用自记录表。 对自记录表的所有读取和写入都被视为不安全。在事务中,对自记录表的读取或写入后的任何语句也被视为不安全。

  • LOAD DATA 语句。 LOAD DATA被视为不安全,当binlog_format=MIXED时,该语句以基于行的格式记录。当binlog_format=STATEMENT时,LOAD DATA不会生成警告,与其他不安全语句不同。

  • XA 事务。 如果在源端并行提交的两个 XA 事务在副本上以相反顺序准备,那么在基于语句的复制中可能会出现无法安全解决的锁定依赖关系,并且可能导致副本上的复制失败并发生死锁。当binlog_format=STATEMENT时,XA 事务内的 DML 语句被标记为不安全并生成警告。当binlog_format=MIXEDbinlog_format=ROW时,XA 事务内的 DML 语句使用基于行的复制记录,并且潜在问题不存在。

  • DEFAULT子句指的是一个不确定性函数。 如果表达式的默认值指向一个不确定性函数,任何导致表达式被评估的语句对于基于语句的复制都是不安全的。这包括诸如INSERTUPDATEALTER TABLE等语句。与大多数其他不安全语句不同,这类语句在基于行的格式中无法安全复制。当binlog_format设置为STATEMENT时,该语句被记录并执行,但会在错误日志中写入警告消息。当binlog_format设置为MIXEDROW时,该语句不会被执行,并且会在错误日志中写入错误消息。有关显式默认值处理的更多信息,请参见 MySQL 8.0.13 中的显式默认值处理。

更多信息,请参见第 19.5.1 节,“复制功能和问题”。

19.2.2 复制通道

原文:dev.mysql.com/doc/refman/8.0/en/replication-channels.html

19.2.2.1 单个通道操作命令

19.2.2.2 与先前复制语句的兼容性

19.2.2.3 启动选项和复制通道

19.2.2.4 复制通道命名约定

在 MySQL 多源复制中,副本会打开多个复制通道,每个通道对应一个源服务器。复制通道代表从源到副本流动的事务路径。每个复制通道都有自己的接收器(I/O)线程、一个或多个应用程序(SQL)线程和中继日志。当来自源的事务被通道的接收器线程接收时,它们被添加到通道的中继日志文件中,并传递给通道的应用程序线程。这使得每个通道可以独立运作。

本节描述了通道在复制拓扑中的使用方式,以及它们对单源复制的影响。有关配置多源复制的源和副本、启动、停止和重置多源副本以及监视多源复制的说明,请参见第 19.1.5 节,“MySQL 多源复制”。

在多源复制拓扑中,一个副本服务器上可以创建的通道的最大数量为 256。每个复制通道必须具有唯一(非空)的名称,如第 19.2.2.4 节,“复制通道命名约定”中所解释的。启用多源复制时发出的错误代码和消息指定生成错误的通道。

注意

多源副本上的每个通道必须从不同的源复制。您不能从单个副本设置多个复制通道到单个源。这是因为副本的服务器 ID 在复制拓扑中必须是唯一的。源仅通过副本的服务器 ID 来区分副本,而不是通过复制通道的名称,因此它无法识别来自同一副本的不同复制通道。

多源复制副本还可以设置为多线程副本,方法是将系统变量replica_parallel_workers(从 MySQL 8.0.26 开始)或slave_parallel_workers(在 MySQL 8.0.26 之前)设置为大于 0 的值。当在多源复制副本上执行此操作时,副本上的每个通道都具有指定数量的应用程序线程,以及一个协调器线程来管理它们。无法为各个通道配置应用程序线程的数量。

从 MySQL 8.0 开始,可以在特定复制通道上配置多源复制副本的复制过滤器。当相同数据库或表存在于多个源上时,可以使用特定通道的复制过滤器,只需将副本从一个源复制即可。对于基于 GTID 的复制,如果同一事务可能来自多个源(例如在钻石拓扑中),必须确保所有通道上的过滤设置相同。有关更多信息,请参见 Section 19.2.5.4,“基于复制通道的过滤器”。

为了与旧版本兼容,MySQL 服务器在启动时自动创建一个名为空字符串("")的默认通道。该通道始终存在;用户无法创建或销毁它。如果没有创建其他通道(具有非空名称),则复制语句仅在默认通道上执行,以便所有来自旧副本的复制语句都能正常运行(参见 Section 19.2.2.2,“与先前复制语句的兼容性”)。本节描述的应用于复制通道的语句仅在至少有一个命名通道时才能使用。

原文:dev.mysql.com/doc/refman/8.0/en/channels-commands-single-channel.html

19.2.2.1 单通道操作命令

要使 MySQL 复制操作作用于单个复制通道,请在以下复制语句中使用FOR CHANNEL *channel*子句:

  • CHANGE REPLICATION SOURCE TO

  • CHANGE MASTER TO

  • START REPLICA(或在 MySQL 8.0.22 之前,START SLAVE

  • STOP REPLICA(或在 MySQL 8.0.22 之前,STOP SLAVE

  • SHOW RELAYLOG EVENTS

  • FLUSH RELAY LOGS

  • SHOW REPLICA STATUS(或在 MySQL 8.0.22 之前,SHOW SLAVE STATUS

  • RESET REPLICA(或在 MySQL 8.0.22 之前,RESET SLAVE

以下函数具有channel参数:

  • MASTER_POS_WAIT()

  • SOURCE_POS_WAIT()

以下语句不允许在group_replication_recovery通道上使用:

  • START REPLICA

  • STOP REPLICA

以下语句不允许在group_replication_applier通道上使用:

  • START REPLICA

  • STOP REPLICA

  • SHOW REPLICA STATUS

FLUSH RELAY LOGS现在允许在group_replication_applier通道上使用,但如果在应用事务时收到请求,则在事务结束后执行请求。请求者必须等待事务完成并进行旋转。此行为防止事务被拆分,这对于组复制是不允许的。

原文:dev.mysql.com/doc/refman/8.0/en/channels-with-prev-replication.html

19.2.2.2 与先前复制语句的兼容性

当一个复制品有多个通道且未指定 FOR CHANNEL *channel* 选项时,一个有效的语句通常会作用于所有可用通道,但也有一些特定的例外情况。

例如,以下语句对所有通道都能正常工作,除了某些 Group Replication 通道:

  • START REPLICA 启动所有通道的复制线程,除了 group_replication_recoverygroup_replication_applier 通道。

  • STOP REPLICA 停止所有通道的复制线程,除了 group_replication_recoverygroup_replication_applier 通道。

  • SHOW REPLICA STATUS 报告所有通道的状态,除了 group_replication_applier 通道。

  • RESET REPLICA 重置所有通道。

警告

谨慎使用 RESET REPLICA,因为此语句会删除所有现有通道,清除它们的中继日志文件,并仅重新创建默认通道。

一些复制语句无法在所有通道上操作。在这种情况下,会生成错误 1964 复制品上存在多个通道。请提供通道名称作为参数。以下语句和函数在多源复制拓扑中使用时会生成此错误,并且未使用 FOR CHANNEL *channel* 选项来指定要操作的通道:

  • SHOW RELAYLOG EVENTS

  • CHANGE REPLICATION SOURCE TO

  • CHANGE MASTER TO

  • MASTER_POS_WAIT()

  • SOURCE_POS_WAIT()

请注意,在单源复制拓扑中始终存在一个默认通道,其中语句和函数的行为与 MySQL 先前版本中的行为相同。

译文:dev.mysql.com/doc/refman/8.0/en/channels-startup-options.html

19.2.2.3 启动选项和复制通道

本节描述了受复制通道添加影响的启动选项。

当使用复制通道时,master_info_repositoryrelay_log_info_repository 系统变量必须设置为FILE。在 MySQL 8.0 中,FILE 设置已被弃用,TABLE 是默认设置,因此可以省略这些系统变量。从 MySQL 8.0.23 开始,它们必须被省略,因为从该版本开始已弃用它们的使用。如果这些系统变量设置为FILE,则尝试向副本添加更多源将导致ER_SLAVE_NEW_CHANNEL_WRONG_REPOSITORY错误。

下列启动选项现在影响所有复制拓扑中的通道。

  • --log-replica-updates--log-slave-updates

    所有副本接收的事务(甚至来自多个源)都会写入二进制日志。

  • --relay-log-purge

    设置后,每个通道会自动清除自己的中继日志。

  • --replica-transaction-retries--slave-transaction-retries

    指定的事务重试次数可以在所有通道的所有应用程序线程上进行。

  • --skip-replica-start--skip-slave-start(或 skip_replica_startskip_slave_start 系统变量设置)

    任何通道上都不会启动复制线程。

  • --replica-skip-errors--slave-skip-errors

    执行继续,所有通道的错误都被跳过。

下列启动选项的设置适用于每个通道;由于这些是mysqld启动选项,它们将应用于每个通道。

  • --max-relay-log-size=*size*

    每个通道的单个中继日志文件的最大大小;达到此限制后,文件将被轮换。

  • --relay-log-space-limit=*size*

    每个单独通道所有中继日志总大小的上限。对于N个通道,这些日志的总大小限制为relay_log_space_limit * *N*

  • --replica-parallel-workers=*value*--slave-parallel-workers=*value*

    每个通道的复制应用程序线程数。

  • replica_checkpoint_groupslave_checkpoint_group

    每个接收线程等待每个源的时间。

  • --relay-log-index=filename

    每个通道中继日志索引文件的基本名称。参见第 19.2.2.4 节,“复制通道命名约定”。

  • --relay-log=filename

    表示每个通道中继日志文件的基本名称。参见第 19.2.2.4 节,“复制通道命名约定”。

  • --replica-net-timeout=N--slave-net-timeout=N

    这个值是针对每个通道设置的,因此每个通道等待N秒来检查是否存在断开的连接。

  • --replica-skip-counter=N--slave-skip-counter=N

    这个值是针对每个通道设置的,因此每个通道跳过N个来自其源的事件。

原文:dev.mysql.com/doc/refman/8.0/en/channels-naming-conventions.html

19.2.2.4 复制通道命名约定

本节描述了复制通道对命名约定的影响。

每个复制通道都有一个唯一的名称,其最大长度为 64 个字符,且不区分大小写。由于通道名称用于复制的应用程序元数据存储库表中,因此这些名称的字符集始终为 UTF-8。虽然通常可以自由选择通道的任何名称,但以下名称已保留:

  • group_replication_applier

  • group_replication_recovery

你为复制通道选择的名称也会影响多源复制的中继日志文件和索引文件的命名。每个通道的中继日志文件和索引文件的命名格式为*relay_log_basename*-*channel*.xxxxxx,其中relay_log_basename是使用relay_log系统变量指定的基本名称,channel是记录到该文件的通道的名称。如果未指定relay_log系统变量,则将使用默认文件名,该文件名还包括通道的名称。

19.2.3 复制线程

原文:dev.mysql.com/doc/refman/8.0/en/replication-threads.html

19.2.3.1 监控复制主线程

19.2.3.2 监控复制应用程序工作线程

MySQL 复制功能使用以下类型的线程实现:

  • 二进制日志转储线程。 源码在复制品连接时创建一个线程,将二进制日志内容发送到复制品。在源码的SHOW PROCESSLIST输出中,可以将此线程标识为Binlog Dump线程。

  • 复制 I/O 接收线程。 当在复制品服务器上发出START REPLICA语句时,复制品将创建一个 I/O(接收器)线程,该线程连接到源并要求其发送其二进制日志中记录的更新。

    复制接收器线程读取源的Binlog Dump线程发送的更新(请参见前一项),并将其复制到组成复制品中继日志的本地文件中。

    此线程的状态在SHOW REPLICA STATUS的输出中显示为Slave_IO_running

  • 复制 SQL 应用程序线程。replica_parallel_workers(在 MySQL 8.0.26 及更早版本中,请使用slave_parallel_workers)等于 0 时,复制品将创建一个 SQL(应用程序)线程来读取由复制接收器线程写入的中继日志,并执行其中包含的事务。当replica_parallel_workers*N* >= 1时,存在N个应用程序线程和一个协调器线程,该协调器线程按顺序从中继日志中读取事务,并安排工作线程应用它们。每个工作线程应用协调器分配给它的事务。

通过将系统变量replica_parallel_workers(MySQL 8.0.26 或更高版本)或slave_parallel_workers(MySQL 8.0.26 之前)设置为大于 0 的值,可以进一步并行化复制品上的任务。这样做后,复制品将创建指定数量的工作线程来应用事务,以及一个协调器线程,该线程从中继日志中读取事务并将其分配给工作线程。将replica_parallel_workersslave_parallel_workers)设置为大于 0 的值的复制品称为多线程复制品。如果使用多个复制通道,则每个通道都使用此变量指定的线程数。

注意

多线程复制在 NDB 集群中从 NDB 8.0.33 版本开始得到支持。(之前,NDB 会默默地忽略 replica_parallel_workers 的任何设置。)详细信息请参见 第 25.7.11 节,“使用多线程应用程序的 NDB 集群复制”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-threads-monitor-main.html

19.2.3.1 监控复制主线程

SHOW PROCESSLIST语句提供的信息告诉您关于复制在源和副本上发生的情况。有关源状态的信息,请参见第 10.14.4 节,“复制源线程状态”。有关副本状态,请参见第 10.14.5 节,“复制 I/O(接收器)线程状态” Thread States"),以及第 10.14.6 节,“复制 SQL 线程状态”。

以下示例说明了三个主要的复制线程,即二进制日志转储线程、复制 I/O(接收器)线程和复制 SQL(应用程序)线程,在SHOW PROCESSLIST的输出中显示。

在源服务器上,SHOW PROCESSLIST的输出如下:

mysql> SHOW PROCESSLIST\G
*************************** 1\. row ***************************
     Id: 2
   User: root
   Host: localhost:32931
     db: NULL
Command: Binlog Dump
   Time: 94
  State: Has sent all binlog to slave; waiting for binlog to
         be updated
   Info: NULL

在这里,线程 2 是服务于连接的副本的Binlog Dump线程。State信息表明所有未完成的更新已发送到副本,并且源正在等待更多更新发生。如果在源服务器上看不到Binlog Dump线程,则表示复制未运行;也就是说,当前没有副本连接。

在副本服务器上,SHOW PROCESSLIST的输出如下:

mysql> SHOW PROCESSLIST\G
*************************** 1\. row ***************************
     Id: 10
   User: system user
   Host:
     db: NULL
Command: Connect
   Time: 11
  State: Waiting for master to send event
   Info: NULL
*************************** 2\. row ***************************
     Id: 11
   User: system user
   Host:
     db: NULL
Command: Connect
   Time: 11
  State: Has read all relay log; waiting for the slave I/O
         thread to update it
   Info: NULL

State信息表明线程 10 是与源服务器通信的复制 I/O(接收器)线程,线程 11 是处理中继日志中存储的更新的复制 SQL(应用程序)线程。在运行SHOW PROCESSLIST时,这两个线程都处于空闲状态,等待进一步的更新。

Time列中的值可以显示副本相对于源的延迟情况。参见第 A.14 节,“MySQL 8.0 FAQ:复制”。如果源端在Binlog Dump线程上没有活动发生足够的时间,源会确定副本已不再连接。对于任何其他客户端连接,这些超时取决于net_write_timeoutnet_retry_count的值;有关这些值的更多信息,请参见第 7.1.8 节,“服务器系统变量”。

显示副本状态 语句提供有关副本服务器上复制处理的额外信息。参见 第 19.1.7.1 节,“检查复制状态”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-threads-monitor-worker.html

19.2.3.2 监视复制应用程序工作线程

在多线程复制中,性能模式表replication_applier_status_by_coordinatorreplication_applier_status_by_worker分别显示复制的协调器线程和应用程序工作线程的状态信息。对于具有多个通道的复制品,将识别每个通道的线程。

如果详细设置为显示信息性消息,则多线程复制的协调器线程也会定期将统计信息打印到复制的错误日志中。统计信息的打印取决于协调器线程分配给应用程序工作线程的事件数量,最大频率为每 120 秒一次。消息列出了相关复制通道或默认复制通道(未命名)的以下统计信息:

经过的秒数

当前时间与上次将此信息打印到错误日志的时间之间的秒数差异。

分配的事件

自协调器线程启动以来,协调器线程已将所有应用程序工作线程排队的事件总数。

工作队列填满超出限制水平

当前排队到任何应用程序工作线程中超过超限水平的事件数量,该超限水平设置为 16384 个事件的最大队列长度的 90%。如果此值为零,则没有应用程序工作线程操作达到其容量上限。

等待由于工作队列已满

协调器线程因应用程序工作线程队列已满而等待调度事件的次数。如果此值为零,则没有应用程序工作线程耗尽其容量。

等待由于总大小

协调器线程因replica_pending_jobs_size_maxslave_pending_jobs_size_max限制已达到而等待调度事件的次数。此系统变量设置了可用于应用程序工作线程队列的最大内存量(以字节为单位),用于保存尚未应用的事件。如果异常大的事件超过此大小,则事务将保持,直到所有应用程序工作线程的队列为空,然后进行处理。所有后续事务将保持,直到大事务完成。

等待时钟冲突

协调线程等待调度事件的纳秒数,因为事件依赖的事务尚未提交。如果replica_parallel_typeslave_parallel_type 设置为DATABASE(而不是LOGICAL_CLOCK),则此值始终为零。

工作者占用时等待(计数)

协调线程短暂睡眠的次数,可能出现在两种情况下。第一种情况是协调线程分配事件并发现应用程序工作线程队列填满超过最大队列长度的 10%的欠流水平时,最多睡眠 1 毫秒。第二种情况是replica_parallel_typeslave_parallel_type 设置为LOGICAL_CLOCK,协调线程需要将事务的第一个事件分配给应用程序工作线程队列,它只会将其分配给一个空队列的工作线程,因此如果没有空队列,协调线程会睡眠直到有一个队列变为空。

工作者占用时等待

协调线程在等待空的应用程序工作线程队列时睡眠的纳秒数(即,在上述第二种情况中,replica_parallel_typeslave_parallel_type 设置为LOGICAL_CLOCK,并且需要为事务的第一个事件分配时)。

19.2.4 中继日志和复制元数据存储库

原文:dev.mysql.com/doc/refman/8.0/en/replica-logs.html

19.2.4.1 中继日志

19.2.4.2 复制元数据存储库

复制服务器创建多个信息存储库,用于复制过程:

  • 复制的中继日志由复制 I/O(接收器)线程编写,其中包含从复制源服务器的二进制日志中读取的事务。中继日志中的事务由复制 SQL(应用程序)线程在复制中应用。有关中继日志的信息,请参见第 19.2.4.1 节,“中继日志”。

  • 复制的连接元数据存储库包含复制接收器线程需要连接到复制源服务器并从源的二进制日志中检索事务的信息。连接元数据存储库写入mysql.slave_master_info表。

  • 复制的应用程序元数据存储库包含复制应用程序线程需要读取并应用来自复制中继日志的事务的信息。应用程序元数据存储库写入mysql.slave_relay_log_info表。

复制的连接元数据存储库和应用程序元数据存储库统称为复制元数据存储库。有关这些信息,请参见第 19.2.4.2 节,“复制元数据存储库”。

使复制对意外停机具有弹性。 使用事务存储引擎InnoDB创建mysql.slave_master_infomysql.slave_relay_log_info表。对复制的应用程序元数据存储库表的更新与事务一起提交,这意味着记录在该存储库中的复制进度信息始终与已应用于数据库的内容一致,即使出现意外服务器停机情况。有关在复制上组合设置以使其对意外停机最具弹性的信息,请参见第 19.4.2 节,“处理复制的意外停机”。

原文:dev.mysql.com/doc/refman/8.0/en/replica-logs-relaylog.html

19.2.4.1 中继日志

中继日志与二进制日志类似,由一组包含描述数据库更改事件的编号文件和一个包含所有已使用中继日志文件名称的索引文件组成。中继日志文件的默认位置是数据目录。

术语“中继日志文件”通常表示包含数据库事件的单个编号文件。术语“中继日志”集体表示一组编号的中继日志文件和索引文件。

中继日志文件与二进制日志文件具有相同的格式,并且可以使用mysqlbinlog进行读取(参见第 6.6.9 节,“mysqlbinlog — 用于处理二进制日志文件的实用程序”)。如果使用二进制日志事务压缩(从 MySQL 8.0.20 开始提供),写入中继日志的事务有效载荷将以与二进制日志相同的方式进行压缩。有关二进制日志事务压缩的更多信息,请参见第 7.4.4.5 节,“二进制日志事务压缩”。

对于默认复制通道,中继日志文件名采用默认形式*host_name*-relay-bin.*nnnnnn*,其中host_name是复制服务器主机的名称,nnnnnn是一个序列号。连续的中继日志文件使用连续的序列号创建,从000001开始。对于非默认复制通道,基本名称为*host_name*-relay-bin-*channel*,其中channel是中继日志中记录的复制通道的名称。

复制使用索引文件来跟踪当前正在使用的中继日志文件。默认的中继日志索引文件名为*host_name*-relay-bin.index,用于默认通道,非默认复制通道使用*host_name*-relay-bin-*channel*.index

默认的中继日志文件和中继日志索引文件的名称和位置可以分别通过relay_logrelay_log_index系统变量进行覆盖(参见第 19.1.6 节,“复制和二进制日志选项和变量”)。

如果一个复制使用默认基于主机的中继日志文件名,那么在设置复制后更改复制的主机名可能会导致复制失败,并显示错误消息“Failed to open the relay log”和“Could not find target log during relay log initialization”。这是一个已知问题(参见 Bug #2122)。如果预计将来可能更改复制的主机名(例如,如果在复制上设置了网络,以便可以使用 DHCP 修改其主机名),则可以通过在初始设置复制时显式使用relay_logrelay_log_index系统变量来指定中继日志文件名,从而完全避免此问题。这样可以使名称与服务器主机名更改无关。

如果在复制已经开始后遇到问题,解决方法之一是停止复制服务器,将旧中继日志索引文件的内容添加到新文件中,然后重新启动复制。在 Unix 系统上,可以按照以下方式执行:

$> cat *new_relay_log_name*.index >> *old_relay_log_name*.index
$> mv *old_relay_log_name*.index *new_relay_log_name*.index

复制服务器在以下情况下创建一个新的中继日志文件:

  • 每次复制 I/O(接收器)线程启动时。

  • 当日志被刷新时(例如,使用FLUSH LOGSmysqladmin flush-logs)。

  • 当当前中继日志文件的大小变得太大时,判定如下:

    • 如果max_relay_log_size的值大于 0,则为最大中继日志文件大小。

    • 如果max_relay_log_size的值为 0,则max_binlog_size确定最大中继日志文件大小。

复制 SQL(应用程序)线程在执行完文件中的所有事件并不再需要该文件时会自动删除每个中继日志文件。没有显式的机制用于删除中继日志,因为复制 SQL 线程会负责执行此操作。然而,FLUSH LOGS会旋转中继日志,影响复制 SQL 线程何时删除它们。

译文:dev.mysql.com/doc/refman/8.0/en/replica-logs-status.html

19.2.4.2 复制元数据存储库

复制服务器创建两个复制元数据存储库,连接元数据存储库和应用程序元数据存储库。复制元数据存储库在复制服务器关闭时保留。如果使用基于二进制日志文件位置的复制,则在复制重新启动时,它会读取这两个存储库,以确定它以前在读取源的二进制日志和处理自己的中继日志方面进行了多远。如果使用基于 GTID 的复制,则复制不会使用复制元数据存储库进行此目的,但确实需要其中包含的其他元数据。

  • 复制的连接元数据存储库包含复制 I/O(接收器)线程需要连接到复制源服务器并从源的二进制日志中检索事务的信息。该存储库中的元数据包括连接配置、复制用户帐户详细信息、连接的 SSL 设置,以及复制接收器线程当前正在从源的二进制日志中读取的文件名和位置。

  • 复制的应用程序元数据存储库包含复制 SQL(应用程序)线程需要读取并应用来自复制的中继日志的事务的信息。该存储库中的元数据包括复制应用程序线程已执行中继日志中的事务的文件名和位置,以及源二进制日志中的等效位置。它还包括应用事务过程的元数据,例如工作线程数和通道的PRIVILEGE_CHECKS_USER帐户。

连接元数据存储库写入mysql系统模式中的slave_master_info表中,而应用程序元数据存储库写入mysql系统模式中的slave_relay_log_info表中。如果mysqld无法初始化用于复制元数据存储库的表,则会发出警告消息,但允许复制继续启动。当从不支持使用表作为存储库的版本升级到支持表的版本时,最有可能发生这种情况。

重要

  1. 不要尝试手动更新或插入mysql.slave_master_infomysql.slave_relay_log_info表中的行。这样做可能导致未定义的行为,并且不受支持。在复制正在进行时,不允许执行需要对slave_master_infoslave_relay_log_info表中的任一表或两个表进行写锁定的任何语句(尽管允许随时执行仅执行读取的语句)。

  2. 对于连接元数据存储库表mysql.slave_master_info的访问权限应该限制在数据库管理员,因为它包含用于连接到源的复制用户帐户名和密码。使用受限访问模式来保护包含此表的数据库备份。从 MySQL 8.0.21 开始,您可以从连接元数据存储库中清除复制用户帐户凭据,并始终使用START REPLICA语句或START GROUP_REPLICATION语句提供它们。这种方法意味着复制通道始终需要操作员干预才能重新启动,但帐户名和密码不会记录在复制元数据存储库中。

RESET REPLICA会清除复制元数据存储库中的数据,但不包括复制连接参数(取决于 MySQL Server 版本)。有关详细信息,请参阅RESET REPLICA的描述。

从 MySQL 8.0.27 开始,您可以在CHANGE REPLICATION SOURCE TO语句上设置GTID_ONLY选项,以阻止复制通道将文件名和文件位置持久化到复制元数据存储库中。这样可以避免在 GTID 基础复制实际上不需要它们的情况下对表进行写入和读取。使用GTID_ONLY设置时,当副本队列和应用程序在事务中排队和应用事件,或者当复制线程停止和启动时,连接元数据存储库和应用程序元数据存储库不会被更新。文件位置在内存中进行跟踪,并且如果需要,可以使用SHOW REPLICA STATUS语句查看。复制元数据存储库仅在以下情况下同步:

  • 当发出CHANGE REPLICATION SOURCE TO语句时。

  • 当发出RESET REPLICA语句时。RESET REPLICA ALL会删除而不是更新存储库,因此它们会隐式同步。

  • 当初始化复制通道时。

  • 如果将复制元数据存储库从文件移动到表中。

在 MySQL 8.0 之前,要将复制元数据存储库创建为表,需要在服务器启动时指定master_info_repository=TABLErelay_log_info_repository=TABLE。否则,存储库将被创建为数据目录中的文件,命名为master.inforelay-log.info,或者使用--master-info-file选项和relay_log_info_file系统变量指定的替代名称和位置。从 MySQL 8.0 开始,默认情况下将复制元数据存储库创建为表,并且所有这些系统变量的使用已被弃用。

mysql.slave_master_infomysql.slave_relay_log_info表是使用InnoDB事务存储引擎创建的。对应用程序元数据存储库表的更新与事务一起提交,这意味着记录在该存储库中的副本进度信息始终与已应用于数据库的内容一致,即使在发生意外服务器停机的情况下也是如此。有关在副本上设置的组合对于意外停机最具弹性的信息,请参阅 Section 19.4.2, “处理副本意外停机”。

当您备份副本的数据或传输其数据的快照以创建新副本时,请确保包括包含复制元数据存储库的mysql.slave_master_infomysql.slave_relay_log_info表。对于克隆操作,请注意,当复制元数据存储库被创建为表时,在克隆操作期间会将其复制到接收方,但当它们被创建为文件时,则不会被复制。当使用基于二进制日志文件位置的复制时,需要复制元数据存储库以在重新启动已恢复、复制或克隆的副本后恢复复制。如果您没有中继日志文件,但仍然有应用程序元数据存储库,则可以检查它以确定复制 SQL 线程在源二进制日志中执行到哪个程度。然后,您可以使用CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(在 MySQL 8.0.23 之前)与SOURCE_LOG_FILE | MASTER_LOG_FILESOURCE_LOG_POS | MASTER_LOG_POS选项告诉副本从该点重新读取源的二进制日志(前提是所需的二进制日志仍然存在于源)。

另外创建了一个附加的存储库,即应用程序工作程序元数据存储库,主要用于内部使用,并保存有关多线程复制品上工作线程的状态信息。应用程序工作程序元数据存储库包括每个工作线程的中继日志文件和源二进制日志文件的名称和位置。如果将应用程序元数据存储库创建为表(这是默认设置),则将应用程序工作程序元数据存储库写入mysql.slave_worker_info表中。如果将应用程序元数据存储库写入文件,则将应用程序工作程序元数据存储库写入worker-relay-log.info文件中。对于外部使用,工作线程的状态信息显示在性能模式replication_applier_status_by_worker中。

复制元数据存储库最初包含类似于SHOW REPLICA STATUS语句输出中显示的信息,该语句在第 15.4.2 节“用于控制复制服务器的 SQL 语句”中讨论。此后,复制元数据存储库中添加了更多信息,这些信息不会被SHOW REPLICA STATUS语句显示。

对于连接元数据存储库,以下表显示了mysql.slave_master_info表中的列与SHOW REPLICA STATUS显示的列以及已弃用的master.info文件中的行之间的对应关系。

slave_master_info 表列 SHOW REPLICA STATUS master.info 文件行 描述
Number_of_lines [无] 1 表中的列数(或文件中的行数)
Master_log_name Source_Log_File 2 当前正在从源读取的二进制日志的名称
Master_log_pos Read_Source_Log_Pos 3 已从源读取的二进制日志中的当前位置
Host Source_Host 4 复制源服务器的主机名
User_name Source_User 5 用于连接到源的复制用户帐户名称
User_password 密码(SHOW REPLICA STATUS不显示) 6 用于连接到源的复制用户帐户密码
Port Source_Port 7 用于连接到复制源服务器的网络端口
Connect_retry Connect_Retry 8 复制品在尝试重新连接到源之前等待的时间段(以秒为单位)
Enabled_ssl Source_SSL_Allowed 9 复制端是否支持 SSL 连接
Ssl_ca Source_SSL_CA_File 10 用于证书颁发机构(CA)证书的文件
Ssl_capath Source_SSL_CA_Path 11 证书颁发机构(CA)证书的路径
Ssl_cert Source_SSL_Cert 12 SSL 证书文件的名称
Ssl_cipher Source_SSL_Cipher 13 SSL 连接握手中可能使用的密码列表
Ssl_key Source_SSL_Key 14 SSL 密钥文件的名称
Ssl_verify_server_cert Source_SSL_Verify_Server_Cert 15 是否验证服务器证书
Heartbeat [无] 16 复制心跳之间的间隔时间,单位为秒
Bind Source_Bind 17 连接源端时应使用的复制端网络接口
Ignored_server_ids Replicate_Ignore_Server_Ids 18 要忽略的服务器 ID 列表。请注意,对于Ignored_server_ids,服务器 ID 列表前面会有要忽略的服务器 ID 总数。
Uuid Source_UUID 19 源端的唯一 ID
Retry_count Source_Retry_Count 20 允许的最大重连尝试次数
Ssl_crl [无] 21 SSL 证书吊销列表文件的路径
Ssl_crlpath [无] 22 包含 SSL 证书吊销列表文件的目录路径
Enabled_auto_position Auto_position 23 是否使用 GTID 自动定位
Channel_name Channel_name 24 复制通道的名称
Tls_version Source_TLS_Version 25 源端的 TLS 版本
Public_key_path Source_public_key_path 26 RSA 公钥文件的名称
Get_public_key Get_source_public_key 27 是否从源端请求 RSA 公钥
Network_namespace Network_namespace 28 网络命名空间
Master_compression_algorithm [无] 29 与源端连接的允许压缩算法
Master_zstd_compression_level [无] 30 zstd压缩级别
Tls_ciphersuites [无] 31 TLSv1.3 允许的密码套件
Source_connection_auto_failover [无] 32 是否激活异步连接故障转移机制
Gtid_only [无] 33 通道是否仅使用 GTID 并且不保留位置
slave_master_info 表列 SHOW REPLICA STATUS master.info 文件行 描述

对于应用程序元数据存储库,以下表格显示了mysql.slave_relay_log_info表中的列与SHOW REPLICA STATUS显示的列以及已弃用的relay-log.info文件中的行之间的对应关系。

slave_relay_log_info 表列 SHOW REPLICA STATUS relay-log.info 文件行 描述
Number_of_lines [无] 1 表中的列数或文件中的行数
Relay_log_name 中继日志文件 2 当前中继日志文件的名称
Relay_log_pos Relay_Log_Pos 3 中继日志文件中的当前位置;到达此位置的事件已在副本数据库上执行
Master_log_name 源二进制日志文件 4 从中继日志文件中读取事件的源二进制日志文件的名称
Master_log_pos Exec_Source_Log_Pos 5 在副本上已执行的事件在源二进制日志文件中的相应位置
Sql_delay SQL_Delay 6 副本必须滞后源的秒数
Number_of_workers [无] 7 并行应用复制事务的工作线程数
Id [无] 8 用于内部目的的 ID;目前始终为 1
Channel_name 通道名称 9 复制通道的名称
Privilege_checks_username [无] 10 通道的PRIVILEGE_CHECKS_USER账户的用户名
Privilege_checks_hostname [无] 11 通道的PRIVILEGE_CHECKS_USER账户的主机名
Require_row_format [无] 12 通道是否仅接受基于行的事件
Require_table_primary_key_check [无] 13 通道对于CREATE TABLEALTER TABLE操作是否要求表必须有主键的策略
Assign_gtids_to_anonymous_transactions_type [无] 14 如果通道为尚未具有 GTID 的复制事务分配 GTID,使用副本的本地 UUID,则该值为LOCAL;如果通道使用手动设置的 UUID 进行分配,则该值为UUID。如果通道在这种情况下不分配 GTID,则该值为OFF
Assign_gtids_to_anonymous_transactions_value [无] 15 用于分配给匿名事务的 GTIDs 的 UUID
slave_relay_log_info 表列 SHOW REPLICA STATUS relay-log.info 文件中的行 描述

19.2.5 服务器如何评估复制过滤规则

原文:dev.mysql.com/doc/refman/8.0/en/replication-rules.html

19.2.5.1 数据库级复制和二进制日志选项的评估

19.2.5.2 表级复制选项的评估

19.2.5.3 复制过滤选项之间的交互

19.2.5.4 基于复制通道的过滤器

如果复制源服务器不将语句写入其二进制日志,则该语句不会被复制。如果服务器记录了该语句,则该语句将发送到所有复制端,每个复制端确定是否执行或忽略它。

在源端,您可以通过使用--binlog-do-db--binlog-ignore-db选项来控制要记录更改的数据库。有关服务器在评估这些选项时使用的规则的描述,请参阅第 19.2.5.1 节,“数据库级复制和二进制日志选项的评估”。您不应该使用这些选项来控制要复制的数据库和表。相反,使用复制端的过滤器来控制在复制端执行的事件。

在复制端,关于是否执行或忽略从源端接收到的语句的决定是根据复制端启动时使用的--replicate-*选项进行的。(请参阅第 19.1.6 节,“复制和二进制日志选项和变量”。)这些选项管理的过滤器也可以使用CHANGE REPLICATION FILTER语句动态设置。管理这些过滤器的规则无论是在启动时使用--replicate-*选项创建还是在复制服务器运行时使用CHANGE REPLICATION FILTER创建,都是相同的。请注意,不能在配置为组复制的 MySQL 服务器实例上的组复制特定通道上使用复制过滤器,因为在某些服务器上过滤事务会使组无法达成一致状态。

在最简单的情况下,当没有--replicate-*选项时,复制端执行从源端接收到的所有语句。否则,结果取决于给定的特定选项。

数据库级选项(--replicate-do-db, --replicate-ignore-db)首先进行检查;请参阅 Section 19.2.5.1, “数据库级复制和二进制日志选项的评估”,了解此过程的描述。如果没有使用数据库级选项,则选项检查将继续到可能正在使用的任何表级选项(参见 Section 19.2.5.2, “表级复制选项的评估”,讨论这些选项)。如果使用了一个或多个数据库级选项但没有匹配的选项,则该语句不会被复制。

对仅影响数据库的语句(即,CREATE DATABASE, DROP DATABASE, 和 ALTER DATABASE),数据库级选项始终优先于任何--replicate-wild-do-table选项。换句话说,对于这样的语句,只有在没有适用的数据库级选项时才会检查--replicate-wild-do-table选项。

为了更容易确定给定选项集的影响,建议避免混合使用do-*ignore-*选项,或包含通配符的选项与不包含通配符的选项混合使用。

如果指定了任何--replicate-rewrite-db选项,则它们会在测试--replicate-*过滤规则之前应用。

注意

所有复制过滤选项遵循与 MySQL 服务器中其他地方的数据库和表名称相同的大小写敏感规则,包括lower_case_table_names系统变量的影响。

从 MySQL 8.0.31 开始,在执行任何权限检查之前会应用过滤规则;如果事务被过滤掉,则不会为该事务执行任何权限检查,因此不会引发任何错误。更多信息请参阅 Section 19.5.1.29, “复制期间的复制错误”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-rules-db-options.html

19.2.5.1 数据库级复制和二进制日志选项的评估

在评估复制选项时,复制开始时首先检查是否有适用的--replicate-do-db--replicate-ignore-db选项。当使用--binlog-do-db--binlog-ignore-db时,该过程类似,但选项在源上进行检查。

被检查是否匹配的数据库取决于正在处理的语句的二进制日志格式。如果使用行格式记录了该语句,则被更改数据的数据库是被检查的数据库。如果使用语句格式记录了该语句,则默认数据库(使用USE语句指定)是被检查的数据库。

注意

只有使用行格式的 DML 语句才能被记录。DDL 语句始终作为语句记录,即使binlog_format=ROW。因此,所有 DDL 语句都根据基于语句的复制规则进行过滤。这意味着你必须使用USE语句显式选择默认数据库,以便应用 DDL 语句。

对于复制,所涉及的步骤如下:

  1. 使用了哪种日志格式?

    • 语句。 测试默认数据库。

    • 行。 测试受更改影响的数据库。

  2. 是否有任何--replicate-do-db选项?

    • 是。 数据库是否与它们中的任何一个匹配?

      • 是。 继续到第 4 步。

      • 否。 忽略更新并退出。

    • 否。 继续到第 3 步。

  3. 是否有任何--replicate-ignore-db选项?

    • 是。 数据库是否与它们中的任何一个匹配?

      • 是。 忽略更新并退出。

      • 否。 继续到第 4 步。

    • 否。 继续到第 4 步。

  4. 如果有的话,继续检查表级复制选项。有关如何检查这些选项的描述,请参见Section 19.2.5.2, “Evaluation of Table-Level Replication Options”

    重要

    在这个阶段仍然允许的语句实际上尚未执行。直到所有表级选项(如果有)也被检查,并且该过程的结果允许执行该语句为止,该语句才会被执行。

对于二进制日志记录,所涉及的步骤如下:

  1. 是否有--binlog-do-db--binlog-ignore-db选项?

    • 是的。 继续到第 2 步。

    • 否。 记录该语句并退出。

  2. 是否存在默认数据库(是否已通过USE选择了任何数据库)?

    • 是的。 继续到第 3 步。

    • 否。 忽略该语句并退出。

  3. 存在默认数据库。是否有--binlog-do-db选项?

    • 是的。 有任何匹配的数据库吗?

      • 是的。 记录该语句并退出。

      • 否。 忽略该语句并退出。

    • 否。 继续到第 4 步。

  4. 任何--binlog-ignore-db选项是否与数据库匹配?

    • 是的。 忽略该语句并退出。

    • 否。 记录该语句并退出。

重要提示

对于基于语句的日志记录,在刚才给出的规则中对CREATE DATABASEALTER DATABASEDROP DATABASE语句做了例外。在这些情况下,正在创建、更改或删除的数据库将替换默认数据库,以确定是否记录或忽略更新。

--binlog-do-db有时可能意味着“忽略其他数据库”。例如,当使用基于语句的日志记录时,仅使用--binlog-do-db=sales的服务器不会将与默认数据库不同的sales的语句写入二进制日志。当使用相同选项的基于行的日志记录时,服务器仅记录更改sales中数据的更新。

原文:dev.mysql.com/doc/refman/8.0/en/replication-rules-table-options.html

19.2.5.2 表级复制选项的评估

仅当以下两个条件之一为真时,副本才会检查和评估表选项:

  • 未找到匹配的数据库选项。

  • 找到了一个或多个数据库选项,并根据前一节中描述的规则评估这些选项,以确定“执行”条件。

首先,作为初步条件,副本检查是否启用了基于语句的复制。如果是,并且语句出现在存储函数中,则副本执行该语句并退出。如果启用了基于行的复制,则副本不知道语句是否出现在源上的存储函数中,因此此条件不适用。

注意

对于基于语句的复制,复制事件代表语句(构成给定事件的所有更改与单个 SQL 语句相关联);对于基于行的复制,每个事件代表单个表行的更改(因此,单个语句如UPDATE mytable SET mycol = 1可能会产生许多基于行的事件)。从事件的角度来看,检查表选项的过程对于基于行和基于语句的复制都是相同的。

到达这一点后,如果没有表选项,副本简单地执行所有事件。如果有任何--replicate-do-table--replicate-wild-do-table选项,则事件必须与其中之一匹配才能执行;否则,它将被忽略。如果有任何--replicate-ignore-table--replicate-wild-ignore-table选项,则执行所有事件,除了与这些选项之一匹配的事件。

重要

表级复制过滤器仅适用于在查询中明确提及并操作的表。它们不适用于查询隐式更新的表。例如,一个GRANT语句,更新mysql.user系统表但未提及该表,不受指定mysql.%作为通配符模式的过滤器影响。

以下步骤更详细地描述了此评估。 起点是数据库级选项评估的结束,如第 19.2.5.1 节,“数据库级复制和二进制日志选项的评估”中所述。

  1. 是否有任何表复制选项?

    • 是的。 继续到第 2 步。

    • 没有。 执行更新并退出。

  2. 使用哪种日志格式?

    • 语句。 对执行更新的每个语句执行剩余步骤。

    • 行。 对每个表行更新执行剩余步骤。

  3. 是否有任何--replicate-do-table选项?

    • 是的。 表是否与其中任何表匹配?

      • 是的。 执行更新并退出。

      • 没有。 继续到第 4 步。

    • 没有。 继续到第 4 步。

  4. 是否有任何--replicate-ignore-table选项?

    • 是的。 表是否与其中任何表匹配?

      • 是的。 忽略更新并退出。

      • 没有。 继续到第 5 步。

    • 没有。 继续到第 5 步。

  5. 是否有任何--replicate-wild-do-table选项?

    • 是的。 表是否与其中任何表匹配?

      • 是的。 执行更新并退出。

      • 没有。 继续到第 6 步。

    • 没有。 继续到第 6 步。

  6. 是否有任何--replicate-wild-ignore-table选项?

    • 是的。 表是否与其中任何表匹配?

      • 是的。 忽略更新并退出。

      • 没有。 继续到第 7 步。

    • 没有。 继续到第 7 步。

  7. 是否有另一个表需要测试?

    • 是的。 返回到第 3 步。

    • 没有。 继续到第 8 步。

  8. 是否有任何--replicate-do-table--replicate-wild-do-table选项?

    • 是的。 忽略更新并退出。

    • 没有。 执行更新并退出。

注意

如果单个 SQL 语句同时操作一个被--replicate-do-table--replicate-wild-do-table选项包含的表和另一个被--replicate-ignore-table--replicate-wild-ignore-table选项忽略的表,基于语句的复制会停止。复制实例必须执行或忽略完整的语句(形成一个复制事件),逻辑上无法做到这一点。对于 DDL 语句的基于行的复制也适用这一规则,因为 DDL 语句始终被记录为语句,而不考虑生效的日志格式。唯一能够成功复制同时更新包含和被忽略表的语句类型是已使用binlog_format=ROW记录的 DML 语句。

原文:dev.mysql.com/doc/refman/8.0/en/replication-rules-examples.html

19.2.5.3 复制过滤选项之间的交互

如果您同时使用数据库级和表级复制过滤选项,副本首先根据数据库选项接受或忽略事件,然后根据表选项评估所有这些选项允许的事件。这有时可能导致看起来反直觉的结果。还要注意,结果会根据操作是使用基于语句还是基于行的二进制日志格式而变化。如果您希望确保您的复制过滤器始终以相同的方式运行,独立于二进制日志格式,这在使用混合二进制日志格式时尤为重要,请遵循本主题中的指导。

复制过滤选项的效果在不同的二进制日志格式之间有所不同,这是因为数据库名称的识别方式不同。在基于语句的格式中,DML 语句是基于当前数据库处理的,由USE语句指定。在基于行的格式中,DML 语句是基于修改表所在的数据库处理的。DDL 语句始终基于当前数据库进行过滤,由USE语句指定,而不受二进制日志格式的影响。

涉及多个表的操作也可能会因二进制日志格式的不同而受到复制过滤选项的影响。需要注意的操作包括涉及多表UPDATE语句的事务、触发器、级联外键、更新多个表的存储函数以及调用更新一个或多个表的存储函数的 DML 语句。如果这些操作同时更新被过滤进和被过滤出的表,结果可能会随着二进制日志格式的不同而变化。

如果您需要确保您的复制过滤器在不同的二进制日志格式下都能一致地运行,特别是如果您正在使用混合二进制日志格式(binlog_format=MIXED),请仅使用表级复制过滤选项,不要使用数据库级复制过滤选项。此外,不要使用同时更新被过滤进和被过滤出表的多表 DML 语句。

如果您需要同时使用数据库级和表级复制过滤器,并希望它们尽可能一致地运行,请选择以下策略之一:

  1. 如果您使用基于行的二进制日志格式(binlog_format=ROW),对于 DDL 语句,依赖USE语句设置数据库,不要指定数据库名称。您可以考虑更改为基于行的二进制日志格式以提高与复制过滤的一致性。有关更改二进制日志格式适用的条件,请参见 Section 7.4.4.2, “Setting The Binary Log Format”。

  2. 如果您使用基于语句或混合二进制日志格式(binlog_format=STATEMENTMIXED),对于 DML 和 DDL 语句,依赖USE语句,不要使用数据库名称。此外,不要使用同时更新过滤进和过滤出表的多表 DML 语句。

示例 19.7 一个--replicate-ignore-db选项和一个--replicate-do-table选项

在复制源服务器上,发出以下语句:

USE db1;
CREATE TABLE t2 LIKE t1;
INSERT INTO db2.t3 VALUES (1);

副本设置了以下复制过滤选项:

replicate-ignore-db = db1
replicate-do-table = db2.t3

DDL 语句CREATE TABLEdb1中创建表,如前述USE语句指定。副本根据其--replicate-ignore-db = db1选项过滤掉此语句,因为db1是当前数据库。无论复制源服务器上的二进制日志格式如何,结果都是相同的。然而,DML INSERT语句的结果取决于二进制日志格式:

  • 如果源服务器上使用基于行的二进制日志格式(binlog_format=ROW),副本使用表存在的数据库db2评估INSERT操作。首先评估数据库级选项--replicate-ignore-db = db1,因此不适用。表级选项--replicate-do-table = db2.t3适用,因此副本将更改应用于表t3

  • 如果源端使用基于语句的二进制日志格式(binlog_format=STATEMENT),那么复制端将使用由USE语句设置为db1且未更改的默认数据库来评估INSERT操作。根据其数据库级别的--replicate-ignore-db = db1选项,因此它会忽略该操作,不会将更改应用于表t3。表级别的选项--replicate-do-table = db2.t3不会被检查,因为该语句已经匹配了一个数据库级别的选项并被忽略。

如果在复制端需要--replicate-ignore-db = db1选项,并且在源端使用基于语句(或混合)的二进制日志格式也是必要的,可以通过在INSERT语句中省略数据库名称并依赖于USE语句来使结果保持一致,如下所示:

USE db1;
CREATE TABLE t2 LIKE t1;
USE db2;
INSERT INTO t3 VALUES (1);

在这种情况下,复制端始终基于数据库db2评估INSERT语句。无论操作是以语句为基础还是以行为基础的二进制格式记录,结果都是一样的。

原文:dev.mysql.com/doc/refman/8.0/en/replication-rules-channel-based-filters.html

19.2.5.4 复制通道基于过滤器

本节解释了在存在多个复制通道时如何使用复制过滤器,例如在多源复制拓扑中。在 MySQL 8.0 之前,所有复制过滤器都是全局的,因此过滤器适用于所有复制通道。从 MySQL 8.0 开始,复制过滤器可以是全局的或特定于通道的,使您能够在特定复制通道上配置具有复制过滤器的多源副本。特定于通道的复制过滤器在多源复制拓扑中特别有用,当相同数据库或表存在于多个源上时,并且只需要从一个源复制副本时。

有关设置复制通道的说明,请参见第 19.1.5 节,“MySQL 多源复制”,有关其工作原理的更多信息,请参见第 19.2.2 节,“复制通道”。

重要

多源副本上的每个通道必须从不同源复制。即使您使用复制过滤器在每个通道上选择不同的数据进行复制,也不能从单个副本到单个源设置多个复制通道。这是因为副本的服务器 ID 在复制拓扑中必须是唯一的。源仅通过副本的服务器 ID 来区分副本,而不是通过复制通道的名称,因此它无法识别来自同一副本的不同复制通道。

重要

在配置为组复制的 MySQL 服务器实例上,可以在与组复制无直接关系的复制通道上使用特定于通道的复制过滤器,例如,其中一个组成员还充当来自组外部源的副本。它们不能用于group_replication_appliergroup_replication_recovery通道。在这些通道上进行过滤会使组无法达成一致状态的协议。

重要

对于钻石拓扑结构中的多源复制(其中复制品从两个或更多源复制,这些源源自一个共同的源),当使用基于 GTID 的复制时,请确保多源复制的所有通道上的任何复制过滤器或其他通道配置都是相同的。使用基于 GTID 的复制时,过滤器仅应用于事务数据,而 GTID 不会被过滤掉。这样做是为了使复制品的 GTID 集与源的保持一致,这意味着可以使用 GTID 自动定位而无需每次重新获取被过滤掉的事务。在下游复制品是多源的情况下,并且在钻石拓扑结构中从多个源接收相同事务的情况下,下游复制品现在具有事务的多个版本,结果取决于哪个通道首先应用该事务。尝试的第二个通道使用 GTID 自动跳过跳过事务,因为事务的 GTID 已被第一个通道添加到gtid_executed集中。在通道上具有相同过滤器的情况下,没有问题,因为所有事务的版本都包含相同的数据,因此结果是相同的。然而,如果通道上的过滤器不同,数据库可能变得不一致,复制可能会停滞。

复制过滤器和通道概述

当存在多个复制通道时,例如在多源复制拓扑中,复制过滤器应用如下:

  • 任何指定的全局复制过滤器都会添加到过滤器类型(do_dbdo_ignore_table等)的全局复制过滤器中。

  • 任何特定于通道的复制过滤器都会将过滤器添加到指定通道的指定过滤器类型的复制过滤器中。

  • 如果未配置此类型的通道特定复制过滤器,则每个复制通道将全局复制过滤器复制到其特定于通道的复制过滤器中。

  • 每个通道使用其特定于通道的复制过滤器来过滤复制流。

创建频道特定复制过滤器的语法扩展了现有的 SQL 语句和命令选项。当未指定复制频道时,全局复制过滤器被配置以确保向后兼容性。CHANGE REPLICATION FILTER语句支持FOR CHANNEL子句在线配置频道特定过滤器。使用--replicate-*命令选项配置过滤器可以指定复制频道,形式为--replicate-*filter_type*=*channel_name*:*filter_details*。假设在服务器启动之前存在channel_1channel_2频道;在这种情况下,使用命令行选项--replicate-do-db=db1 --replicate-do-db=channel_1:db2 --replicate-do-db=db3 --replicate-ignore-db=db4 --replicate-ignore-db=channel_2:db5 --replicate-wild-do-table=channel_1:db6.t1% 将导致:

  • 全局复制过滤器: do_db=db1,db3; ignore_db=db4

  • channel_1 上的频道特定过滤器: do_db=db2; ignore_db=db4; wild-do-table=db6.t1%

  • channel_2 上的频道特定过滤器: do_db=db1,db3; ignore_db=db5

在复制品的my.cnf文件中包含时,这些相同规则可以在启动时应用,如下所示:

replicate-do-db=db1
replicate-do-db=channel_1:db2
replicate-ignore-db=db4
replicate-ignore-db=channel_2:db5
replicate-wild-do-table=db6.channel_1.t1%

在这种设置中监视复制过滤器,请使用replication_applier_global_filtersreplication_applier_filters表。

在启动时配置频道特定复制过滤器

与复制过滤器相关的命令选项可以在可选的channel后跟一个冒号,然后是过滤器规范。第一个冒号被解释为分隔符,后续的冒号被解释为字面冒号。以下命令选项支持使用此格式配置频道特定复制过滤器:

  • --replicate-do-db=*channel*:*database_id*

  • --replicate-ignore-db=*channel*:*database_id*

  • --replicate-do-table=*channel*:*table_id*

  • --replicate-ignore-table=*channel*:*table_id*

  • --replicate-rewrite-db=*channel*:*db1-db2*

  • --replicate-wild-do-table=*channel*:*table* *pattern*

  • --replicate-wild-ignore-table=*channel*:*table* *pattern*

所有列出的选项都可以在副本的my.cnf文件中使用,与大多数其他 MySQL 服务器启动选项一样,省略前两个破折号。参见 Overview of Replication Filters and Channels,以及 Section 6.2.2.2, “Using Option Files”中的简短示例。

如果使用冒号但不为过滤选项指定channel,例如--replicate-do-db=:*database_id*,则该选项将为默认复制通道配置复制过滤器。默认复制通道是一旦启动复制就始终存在的复制通道,与手动创建的多源复制通道不同。当既不指定冒号也不指定channel时,该选项将配置全局复制过滤器,例如--replicate-do-db=*database_id*配置全局--replicate-do-db过滤器。

如果配置了多个rewrite-db=*from_name*->*to_name*选项与相同的from_name数据库,所有过滤器将被添加在一起(放入rewrite_do列表中),第一个生效。

用于--replicate-wild-*-table选项的pattern可以包括标识符中允许的任何字符,以及通配符%_。这些与LIKE操作符一起使用时的工作方式相同;例如,tbl%匹配任何以tbl开头的表名,而tbl_匹配与tbl匹配的表名加一个额外字符。

在线更改通道特定的复制过滤器

除了--replicate-*选项外,还可以使用CHANGE REPLICATION FILTER语句配置复制过滤器。这样可以避免重新启动服务器,但在进行更改时必须停止复制 SQL 线程。要使此语句将过滤器应用于特定通道,请使用FOR CHANNEL *channel*子句。例如:

CHANGE REPLICATION FILTER REPLICATE_DO_DB=(db1) FOR CHANNEL channel_1;

当提供FOR CHANNEL子句时,语句将作用于指定通道的复制过滤器。如果指定了多种类型的过滤器(do_dbdo_ignore_tablewild_do_table等),则只有指定的过滤器类型会被语句替换。例如,在具有多个通道的复制拓扑结构中,例如在多源复制中,如果没有提供FOR CHANNEL子句,则语句将作用于全局复制过滤器和所有通道的复制过滤器,使用与FOR CHANNEL情况类似的逻辑。更多信息请参见 Section 15.4.2.2, “CHANGE REPLICATION FILTER Statement”。

移除通道特定的复制过滤器

当配置了通道特定的复制过滤器时,可以通过发出空的过滤器类型语句来移除过滤器。例如,要从名为channel_1的复制通道中移除所有REPLICATE_REWRITE_DB过滤器,请发出:

CHANGE REPLICATION FILTER REPLICATE_REWRITE_DB=() FOR CHANNEL channel_1;

之前使用命令选项或CHANGE REPLICATION FILTER配置的任何REPLICATE_REWRITE_DB过滤器都会被移除。

RESET REPLICA ALL 语句会移除在被语句删除的通道上设置的通道特定的复制过滤器。当被删除的通道重新创建时,任何为副本指定的全局复制过滤器会被复制到它们,而不会应用任何通道特定的复制过滤器。

19.3 复制安全性

原文:dev.mysql.com/doc/refman/8.0/en/replication-security.html

19.3.1 设置复制使用加密连接

19.3.2 加密二进制日志文件和中继日志文件

19.3.3 复制权限检查

为防止未经授权访问存储在复制源服务器和副本之间传输的数据,设置所有涉及的服务器使用您在安装中为任何 MySQL 实例选择的安全措施,如第八章,“安全”中所述。此外,对于复制拓扑中的服务器,考虑实施以下安全措施:

  • 设置源和副本使用加密连接传输二进制日志,以保护这些数据在传输中。必须使用CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO语句激活这些连接的加密,另外还需设置服务器支持加密网络连接。参见第 19.3.1 节,“设置复制使用加密连接”。

  • 在源和副本上加密二进制日志文件和中继日志文件,以保护这些数据在静态状态下,以及在二进制日志缓存中使用的任何数据。二进制日志加密通过binlog_encryption系统变量激活。参见第 19.3.2 节,“加密二进制日志文件和中继日志文件”。

  • 将权限检查应用于复制应用程序,有助于保护复制通道免受未经授权或意外使用特权或不需要的操作。权限检查通过设置一个PRIVILEGE_CHECKS_USER账户来实现,MySQL 用它来验证您是否已为该通道的每个特定事务授权。参见第 19.3.3 节,“复制权限检查”。

对于组复制,可以使用二进制日志加密和权限检查作为复制组成员的安全措施。您还应考虑加密组成员之间的连接,包括组通信连接和分布式恢复连接,并应用 IP 地址白名单以排除不受信任的主机。有关组复制特定安全措施的信息,请参见第 20.6 节,“组复制安全”。

19.3.1 设置复制使用加密连接

原文:dev.mysql.com/doc/refman/8.0/en/replication-encrypted-connections.html

要在复制过程中使用加密连接传输二进制日志,源服务器和副本服务器都必须支持加密网络连接。如果任一服务器不支持加密连接(因为它未被编译或配置为支持),则无法通过加密连接进行复制。

为了为复制设置加密连接,与为客户端/服务器连接设置类似。您必须获取(或创建)一个适当的安全证书,可以在源端使用,并在每个副本上使用来自同一证书颁发机构的类似证书。您还必须获取适当的密钥文件。

有关设置服务器和客户端使用加密连接的更多信息,请参见第 8.3.1 节,“配置 MySQL 使用加密连接”。

要在源端启用加密连接,您必须创建或获取适当的证书和密钥文件,然后将以下配置参数添加到源端 my.cnf 文件的 [mysqld] 部分中,根据需要更改文件名:

[mysqld]
ssl_ca=cacert.pem
ssl_cert=server-cert.pem
ssl_key=server-key.pem

文件的路径可以是相对的或绝对的;我们建议您始终为此目的使用完整路径。

配置参数如下:

  • ssl_ca:证书颁发机构(CA)证书文件的路径名。(ssl_capath类似,但指定了 CA 证书文件的目录路径名。)

  • ssl_cert:服务器公钥证书文件的路径名。此证书可以发送给客户端,并根据其拥有的 CA 证书进行验证。

  • ssl_key:服务器私钥文件的路径名。

要在副本端启用加密连接,使用 CHANGE REPLICATION SOURCE TO 语句(MySQL 8.0.23 及更高版本)或 CHANGE MASTER TO 语句(MySQL 8.0.23 之前)。

  • 要使用 CHANGE REPLICATION SOURCE TOCHANGE MASTER TO)命名副本的证书和 SSL 私钥文件,添加适当的 SOURCE_SSL_*xxx*MASTER_SSL_*xxx*)选项,如下所示:

     -> SOURCE_SSL_CA = 'ca_file_name',
     -> SOURCE_SSL_CAPATH = 'ca_directory_name',
     -> SOURCE_SSL_CERT = 'cert_file_name',
     -> SOURCE_SSL_KEY = 'key_file_name',
    

    这些选项对应于相同名称的--ssl-*xxx*选项,如加密连接的命令选项中所述。要使这些选项生效,还必须设置SOURCE_SSL=1。对于复制连接,为SOURCE_SSL_CASOURCE_SSL_CAPATH中的任一值指定一个值相当于设置--ssl-mode=VERIFY_CA。只有在使用指定信息找到有效匹配的证书颁发机构(CA)证书时,连接尝试才会成功。

  • 要激活主机名身份验证,添加SOURCE_SSL_VERIFY_SERVER_CERT选项,如下所示:

     -> SOURCE_SSL_VERIFY_SERVER_CERT=1,
    

    此选项对应于--ssl-verify-server-cert选项,在 MySQL 5.7 中已弃用,并在 MySQL 8.0 中删除。对于复制连接,指定MASTER_SSL_VERIFY_SERVER_CERT=1相当于设置--ssl-mode=VERIFY_IDENTITY,如加密连接的命令选项中所述。要使此选项生效,还必须设置SOURCE_SSL=1。主机名身份验证无法与自签名证书一起使用。

  • 要激活证书吊销列表(CRL)检查,添加SOURCE_SSL_CRLSOURCE_SSL_CRLPATH选项,如下所示:

     -> SOURCE_SSL_CRL = 'crl_file_name',
     -> SOURCE_SSL_CRLPATH = 'crl_directory_name',
    

    这些选项对应于相同名称的--ssl-*xxx*选项,如加密连接的命令选项中所述。如果未指定,将不进行 CRL 检查。

  • 要指定副本允许的密码、密码套件和加密协议列表,使用SOURCE_SSL_CIPHERSOURCE_TLS_VERSIONSOURCE_TLS_CIPHERSUITES选项,如下所示:

     -> SOURCE_SSL_CIPHER = 'cipher_list',
     -> SOURCE_TLS_VERSION = 'protocol_list',
     -> SOURCE_TLS_CIPHERSUITES = 'ciphersuite_list',
    
    • SOURCE_SSL_CIPHER选项指定了一个由冒号分隔的一个或多个副本允许的密码。

    • SOURCE_TLS_VERSION选项指定了一个由逗号分隔的 TLS 加密协议列表,副本允许用于复制连接,格式类似于tls_version服务器系统变量。连接过程协商使用源和副本都允许的最高 TLS 版本。为了能够连接,副本必须至少与源有一个 TLS 版本相同。

    • SOURCE_TLS_CIPHERSUITES选项(从 MySQL 8.0.19 开始提供)指定了一个以冒号分隔的允许副本使用的一个或多个密码套件列表,如果连接使用 TLSv1.3。如果在使用 TLSv1.3 时将此选项设置为NULL(如果您没有设置该选项,则默认为此),则允许启用默认启用的密码套件。如果将选项设置为空字符串,则不允许任何密码套件,并且因此不使用 TLSv1.3。

    您可以在这些列表中指定的协议、密码和密码套件取决于用于编译 MySQL 的 SSL 库。有关格式、允许的值以及如果不指定选项时的默认值的信息,请参阅第 8.3.2 节,“加密连接 TLS 协议和密码”。

    注意

    在 MySQL 8.0.16 到 8.0.18 中,MySQL 支持 TLSv1.3,但SOURCE_TLS_CIPHERSUITES选项不可用。在这些版本中,如果源和副本之间的连接使用 TLSv1.3,则源必须允许至少一个默认启用的 TLSv1.3 密码套件的使用。从 MySQL 8.0.19 开始,您可以使用该选项指定任何密码套件的选择,包括仅非默认密码套件(如果需要)。

  • 更新源信息后,在副本上启动复制过程,如下所示:

    mysql> START SLAVE;
    

    从 MySQL 8.0.22 开始,首选使用START REPLICA,如下所示:

    mysql> START REPLICA;
    

    你可以使用SHOW REPLICA STATUS(在 MySQL 8.0.22 之前,SHOW SLAVE STATUS)语句来确认已成功建立加密连接。

  • 在副本上要求加密连接并不意味着源要求来自副本的加密连接。如果要确保源仅接受使用加密连接连接的副本,可以在源上创建一个使用REQUIRE SSL选项的复制用户帐户,然后授予该用户REPLICATION SLAVE权限。例如:

    mysql> CREATE USER 'repl'@'%.example.com' IDENTIFIED BY '*password*'
     -> REQUIRE SSL;
    mysql> GRANT REPLICATION SLAVE ON *.*
     -> TO 'repl'@'%.example.com';
    

    如果您在源上有现有的复制用户帐户,可以使用以下语句向其添加REQUIRE SSL

    mysql> ALTER USER 'repl'@'%.example.com' REQUIRE SSL;
    

19.3.2 加密二进制日志文件和中继日志文件

原文:dev.mysql.com/doc/refman/8.0/en/replication-binlog-encryption.html

19.3.2.1 二进制日志加密范围

19.3.2.2 二进制日志加密密钥

19.3.2.3 二进制日志主密钥轮换

从 MySQL 8.0.14 开始,二进制日志文件和中继日志文件可以进行加密,有助于保护这些文件以及其中可能包含的敏感数据,防止外部攻击者滥用,也防止操作系统用户未经授权查看。文件使用的加密算法是 AES(高级加密标准)密码算法,内置于 MySQL Server 中,无法配置。

通过将 MySQL 服务器上的 binlog_encryption 系统变量设置为 ON 来启用此加密。OFF 是默认值。该系统变量为二进制日志文件和中继日志文件设置加密。要启用加密,服务器上不需要启用二进制日志记录,因此可以在没有二进制日志的副本上加密中继日志文件。要使用加密,必须安装和配置一个密钥环组件或插件以提供 MySQL Server 的密钥环服务。有关如何执行此操作的说明,请参见 Section 8.4.4, “The MySQL Keyring”。任何支持的密钥环组件或插件都可以用于存储二进制日志加密密钥。

当首次启用加密时,服务器会在初始化二进制日志和中继日志之前生成一个新的二进制日志加密密钥。该密钥用于为每个二进制日志文件(如果服务器启用了二进制日志记录)和中继日志文件(如果服务器有复制通道)加密文件密码,并从文件密码生成的进一步密钥用于加密文件中的数据。服务器当前正在使用的二进制日志加密密钥称为二进制日志主密钥。两层加密密钥架构意味着可以根据需要轮换(用新的主密钥替换)二进制日志主密钥,只需重新使用新主密钥重新加密每个文件的文件密码,而不是整个文件。中继日志文件对所有通道进行加密,包括在激活加密后创建的新通道。二进制日志索引文件和中继日志索引文件永远不会被加密。

如果在服务器运行时激活加密,则会生成一个新的二进制日志加密密钥。例外情况是,如果之前在服务器上激活了加密,然后禁用了加密,那么之前使用的二进制日志加密密钥将再次被使用。二进制日志文件和中继日志文件立即轮换,新文件和所有后续的二进制日志文件和中继日志文件的文件密码都使用此二进制日志加密密钥进行加密。服务器上仍存在的现有二进制日志文件和中继日志文件不会被加密,但如果不再需要,可以清除它们。

如果通过将binlog_encryption 系统变量更改为 OFF 来停用加密,则二进制日志文件和中继日志文件将立即轮换,并且所有后续记录都将是未加密的。先前加密的文件不会自动解密,但服务器仍然能够读取它们。在服务器运行时激活或停用加密需要BINLOG_ENCRYPTION_ADMIN 权限。

可以通过加密日志文件头部的魔数来区分加密和未加密的二进制日志文件(加密日志文件为0xFD62696E,而未加密日志文件为0xFE62696E)。SHOW BINARY LOGS 语句显示每个二进制日志文件是加密还是未加密。

当二进制日志文件被加密时,mysqlbinlog 无法直接读取,但可以使用--read-from-remote-server选项从服务器读取。从 MySQL 8.0.14 开始,mysqlbinlog 如果尝试直接读取加密的二进制日志文件,将返回适当的错误,但旧版本的mysqlbinlog 根本不会将文件识别为二进制日志文件。如果使用mysqlbinlog 备份加密的二进制日志文件,请注意,使用mysqlbinlog 生成的文件副本以未加密格式存储。

二进制日志加密可以与二进制日志事务压缩结合使用(自 MySQL 8.0.20 起可用)。有关二进制日志事务压缩的更多信息,请参见 Section 7.4.4.5, “Binary Log Transaction Compression”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-binlog-encryption-scope.html

19.3.2.1 二进制日志加密范围

当 MySQL 服务器实例启用二进制日志加密时,加密覆盖范围如下:

  • 写入二进制日志文件和中继日志文件的静态数据从加密开始的时间点起,使用上述两层加密架构进行加密。在启动加密时存在于服务器上的现有二进制日志文件和中继日志文件不会被加密。当这些文件不再需要时,可以清除这些文件。

  • 在发送到 MySQL 客户端(包括mysqlbinlog)的复制事件流中的数据在传输时会被解密,因此应通过使用连接加密(参见第 8.3 节,“使用加密连接”和第 19.3.1 节,“设置复制使用加密连接”)来保护传输中的数据。

  • 在事务期间存储在二进制日志事务和语句缓存中的数据以未加密格式存在于存储缓存的内存缓冲区中。如果超过内存缓冲区可用空间,数据将写入磁盘上的临时文件。从 MySQL 8.0.17 开始,当服务器上启用二进制日志加密时,用于保存二进制日志缓存的临时文件将使用 AES-CTR(AES Counter mode)进行流加密进行加密。由于临时文件是易失性的并且与单个进程绑定,因此它们使用单层加密进行加密,使用仅存在于内存中且永远不会存储在磁盘或密钥环中的随机生成的文件密码和初始化向量。在每个事务提交后,二进制日志缓存被重置:内存缓冲区被清除,用于保存二进制日志缓存的任何临时文件被截断,并为下一个事务使用随机生成的新文件密码和初始化向量。在服务器正常关闭或意外停止后重新启动时,也会进行此重置。

注意

如果在设置binlog_format=STATEMENT时使用LOAD DATA,这不被推荐,因为该语句被认为对基于语句的复制不安全,将在应用更改的副本上创建包含数据的临时文件。当服务器上启用二进制日志加密时,这些临时文件不会被加密。相反,请改用基于行或混合二进制日志格式,这些格式不会创建临时文件。

原文:dev.mysql.com/doc/refman/8.0/en/replication-binlog-encryption-encryption-keys.html

19.3.2.2 二进制日志加密密钥

用于加密日志文件的文件密码的二进制日志加密密钥是为每个 MySQL 服务器实例专门生成的 256 位密钥,使用 MySQL 服务器的密钥环服务生成(参见第 8.4.4 节,“MySQL 密钥环”)。密钥环服务处理二进制日志加密密钥的创建、检索和删除。服务器实例仅为自身创建和删除生成的密钥,但如果存储在密钥环中,则可以读取为其他实例生成的密钥,例如通过文件复制克隆的服务器实例的情况。

重要提示

MySQL 服务器实例的二进制日志加密密钥必须包含在您的备份和恢复程序中,因为如果丢失了解密当前和保留的二进制日志文件或中继日志文件的文件密码所需的密钥,可能无法启动服务器。

密钥环中二进制日志加密密钥的格式如下:

MySQLReplicationKey_{UUID}_{SEQ_NO}

例如:

MySQLReplicationKey_00508583-b5ce-11e8-a6a5-0010e0734796_1

{UUID} 是由 MySQL 服务器生成的真实 UUID(server_uuid 系统变量的值)。{SEQ_NO} 是二进制日志加密密钥的序列号,对于在服务器上生成的每个新密钥,该序列号递增 1。

目前在服务器上使用的二进制日志加密密钥称为二进制日志主密钥。当前二进制日志主密钥的序列号存储在密钥环中。二进制日志主密钥用于加密每个新日志文件的文件密码,这是一个特定于用于加密文件数据的日志文件的随机生成的 32 字节文件密码。文件密码使用 AES-CBC(AES 密码块链接模式)使用 256 位二进制日志加密密钥和随机初始化向量(IV)进行加密,并存储在日志文件的文件头中。文件数据使用从文件密码生成的 256 位密钥和从文件密码生成的随机数也生成的随机数使用 AES-CTR(AES 计数器模式)进行加密。如果知道用于加密文件密码的二进制日志加密密钥,则可以使用 OpenSSL 密码工具包中提供的工具离线解密加密文件。

如果您使用文件复制来克隆一个具有加密功能的 MySQL 服务器实例,使其二进制日志文件和中继日志文件被加密,请确保也复制了密钥环,以便克隆服务器可以从源服务器读取二进制日志加密密钥。当在克隆服务器上激活加密(无论是在启动时还是随后),克隆服务器会意识到与复制文件一起使用的二进制日志加密密钥包括源服务器的生成的 UUID。它会自动生成一个新的二进制日志加密密钥,使用自己生成的 UUID,并将其用于加密后续的二进制日志文件和中继日志文件的文件密码。复制的文件将继续使用源服务器的密钥进行读取。

原文:dev.mysql.com/doc/refman/8.0/en/replication-binlog-encryption-key-rotation.html

19.3.2.3 二进制日志主密钥旋转

当启用二进制日志加密时,您可以在服务器运行时随时通过执行ALTER INSTANCE ROTATE BINLOG MASTER KEY来旋转二进制日志主密钥。当使用此语句手动旋转二进制日志主密钥时,新文件和随后的文件的密码将使用新的二进制日志主密钥加密,同时现有加密的二进制日志文件和中继日志文件的文件密码将使用新的二进制日志主密钥重新加密,因此加密完全更新。您可以定期旋转二进制日志主密钥以符合组织的安全策略,如果怀疑当前或任何以前的二进制日志主密钥可能已被泄露,也可以这样做。

当您手动旋转二进制日志主密钥时,MySQL 服务器按顺序执行以下操作:

  1. 生成一个具有下一个可用序列号的新二进制日志加密密钥,存储在密钥环中,并用作新的二进制日志主密钥。

  2. 所有通道上的二进制日志和中继日志文件都会被旋转。

  3. 新的二进制日志主密钥用于加密新的二进制日志和中继日志文件的文件密码,以及直到再次更改密钥为止的随后文件。

  4. 服务器上现有加密的二进制日志文件和中继日志文件的文件密码将依次使用新的二进制日志主密钥重新加密,从最近的文件开始。任何未加密的文件将被跳过。

  5. 在重新加密过程后不再用于任何文件的二进制日志加密密钥将从密钥环中删除。

需要BINLOG_ENCRYPTION_ADMIN权限才能执行ALTER INSTANCE ROTATE BINLOG MASTER KEY,如果binlog_encryption系统变量设置为OFF,则无法使用该语句。

作为二进制日志主密钥轮换过程的最后一步,清理掉不再适用于任何保留的二进制日志文件或中继日志文件的所有二进制日志加密密钥。如果无法为保留的二进制日志文件或中继日志文件初始化重新加密,那么相关的二进制日志加密密钥不会被删除,以防将来可以恢复文件。例如,如果二进制日志索引文件中列出的文件当前无法读取,或者通道无法初始化,可能会出现这种情况。如果服务器 UUID 更改,例如因为使用 MySQL Enterprise Backup 创建的备份用于设置新的副本,那么在新服务器上发出ALTER INSTANCE ROTATE BINLOG MASTER KEY不会删除包括原始服务器 UUID 的任何早期二进制日志加密密钥。

如果二进制日志主密钥轮换过程的前四个步骤中有任何一个无法正确完成,系统会发出错误消息,解释情况以及对二进制日志文件和中继日志文件的加密状态的影响。先前加密的文件始终保持在加密状态,但它们的文件密码可能仍然使用旧的二进制日志主密钥进行加密。如果您看到这些错误,请首先通过再次发出ALTER INSTANCE ROTATE BINLOG MASTER KEY来重试该过程。然后调查各个文件的状态,看看是什么阻碍了该过程,特别是如果您怀疑当前或任何以前的二进制日志主密钥可能已被泄露。

如果二进制日志主密钥轮换过程的最后一步无法正确完成,系统会发出警告消息,解释情况。警告消息会指出该过程无法清理用于轮换二进制日志主密钥的辅助密钥,或无法清理未使用的二进制日志加密密钥。您可以选择忽略该消息,因为这些密钥是辅助密钥或不再使用,或者您可以再次发出ALTER INSTANCE ROTATE BINLOG MASTER KEY来重试该过程。

如果服务器在二进制日志主密钥轮换过程中停止并重新启动,而二进制日志加密仍然设置为ON,则重新启动后的新二进制日志文件和中继日志文件将使用新的二进制日志主密钥进行加密。但是,现有文件的重新加密不会继续进行,因此在服务器停止之前未重新加密的文件将继续使用先前的二进制日志主密钥进行加密。要完成重新加密并清理未使用的二进制日志加密密钥,请在重新启动后再次发出ALTER INSTANCE ROTATE BINLOG MASTER KEY

ALTER INSTANCE ROTATE BINLOG MASTER KEY 操作不会被写入二进制日志,也不会在副本上执行。因此,在包含多个 MySQL 版本的复制环境中可以执行二进制日志主密钥轮换。要在所有适用的源和副本服务器上定期轮换二进制日志主密钥,您可以在每个服务器上启用 MySQL 事件调度程序,并使用 CREATE EVENT 语句发出 ALTER INSTANCE ROTATE BINLOG MASTER KEY 语句。如果因为怀疑当前或任何以前的二进制日志主密钥可能已被泄露而轮换二进制日志主密钥,则在每个适用的源和副本服务器上发出该语句。在各个服务器上发出该语句可确保您可以验证即时的合规性,即使在滞后的副本、属于多个复制拓扑或当前未在复制拓扑中活动但具有二进制日志和中继日志文件的情况下也是如此。

binlog_rotate_encryption_master_key_at_startup 系统变量控制服务器在重新启动时是否自动轮换二进制日志主密钥。如果此系统变量设置为 ON,则在服务器重新启动时会生成一个新的二进制日志加密密钥,并将其用作新的二进制日志主密钥。如果设置为 OFF,即默认值,则在重新启动后再次使用现有的二进制日志主密钥。当在启动时轮换二进制日志主密钥时,新的二进制日志和中继日志文件的文件密码将使用新密钥加密。现有加密的二进制日志文件和中继日志文件的文件密码不会重新加密,因此它们仍然使用旧密钥加密,该旧密钥仍然可在密钥环中使用。

19.3.3 复制权限检查

原文:dev.mysql.com/doc/refman/8.0/en/replication-privilege-checks.html

19.3.3.1 用于复制 PRIVILEGE_CHECKS_USER 帐户的权限

19.3.3.2 Group Replication Channels 的权限检查

19.3.3.3 从失败的复制权限检查中恢复

默认情况下,MySQL 复制(包括 Group Replication)在将已被另一台服务器接受的事务应用于副本或组成员时不执行权限检查。从 MySQL 8.0.18 开始,您可以创建一个具有适当权限的用户帐户来应用通常在通道上复制的事务,并将其指定为复制应用程序的 PRIVILEGE_CHECKS_USER 帐户,使用 CHANGE REPLICATION SOURCE TO 语句(从 MySQL 8.0.23 开始)或 CHANGE MASTER TO 语句(在 MySQL 8.0.23 之前)。然后,MySQL 检查每个事务是否符合用户帐户的权限,以验证您已授权该通道的操作。该帐户还可以安全地由管理员使用,以应用或重新应用来自 mysqlbinlog 输出的事务,例如从通道上的复制错误中恢复。

使用 PRIVILEGE_CHECKS_USER 帐户有助于保护复制通道免受未经授权或意外使用特权或不需要的操作。在以下情况下,PRIVILEGE_CHECKS_USER 帐户提供了额外的安全层:

  • 您正在在组织网络上的服务器实例和另一个网络上的服务器实例之间进行复制,例如云服务提供商提供的实例。

  • 您希望将多个本地部署或外部部署作为单独的单元进行管理,而不是给予一个管理员帐户对所有部署的权限。

  • 您希望拥有一个管理员帐户,使管理员仅能执行与复制通道和其复制的数据库直接相关的操作,而不是在服务器实例上拥有广泛的权限。

当您为通道指定 PRIVILEGE_CHECKS_USER 帐户时,您可以通过在 CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO 语句中添加以下选项之一或两者来增加应用权限检查的复制通道的安全性:

  • REQUIRE_ROW_FORMAT选项(从 MySQL 8.0.19 开始提供)使复制通道仅接受基于行的复制事件。当设置REQUIRE_ROW_FORMAT时,您必须在源服务器上使用基于行的二进制日志记录(binlog_format=ROW)。在 MySQL 8.0.18 中,REQUIRE_ROW_FORMAT不可用,但仍强烈建议在受保护的复制通道中使用基于行的二进制日志记录。使用基于语句的二进制日志记录时,可能需要一些管理员级别的特权才能使PRIVILEGE_CHECKS_USER账户成功执行事务。

  • REQUIRE_TABLE_PRIMARY_KEY_CHECK选项(从 MySQL 8.0.20 开始提供)使复制通道使用自己的主键检查策略。设置为ON表示始终需要主键,设置为OFF表示永远不需要主键。默认设置为STREAM,使用从源复制的每个事务的值设置sql_require_primary_key系统变量的会话值。当设置PRIVILEGE_CHECKS_USER时,将REQUIRE_TABLE_PRIMARY_KEY_CHECK设置为ONOFF意味着用户帐户无需会话管理级别特权来设置受限制的会话变量,这些变量是更改sql_require_primary_key值所需的。它还规范化了不同源的复制通道的行为。

您授予REPLICATION_APPLIER权限以使用户账户能够出现为复制应用程序线程的PRIVILEGE_CHECKS_USER,并执行 mysqlbinlog 使用的内部BINLOG语句。PRIVILEGE_CHECKS_USER账户的用户名和主机名必须遵循第 8.2.4 节,“指定帐户名称”中描述的语法,并且用户不能是匿名用户(具有空白用户名)或CURRENT_USER。要创建新帐户,请使用CREATE USER语句。要授予此帐户REPLICATION_APPLIER权限,请使用GRANT语句。例如,要创建一个名为priv_repl的用户帐户,该帐户可以由example.com域中的任何主机的管理员手动使用,并且需要加密连接,请执行以下语句:

mysql> SET sql_log_bin = 0;
mysql> CREATE USER 'priv_repl'@'%.example.com' IDENTIFIED BY '*password*' REQUIRE SSL;
mysql> GRANT REPLICATION_APPLIER ON *.* TO 'priv_repl'@'%.example.com';
mysql> SET sql_log_bin = 1;

SET sql_log_bin语句用于使账户管理语句不会被添加到二进制日志中并发送到复制通道(参见第 15.4.1.3 节,“SET sql_log_bin 语句”)。

重要提示

caching_sha2_password身份验证插件是从 MySQL 8.0 开始新创建用户的默认插件(有关详细信息,请参见 Section 8.4.1.2, “Caching SHA-2 Pluggable Authentication”)。要使用使用此插件进行身份验证的用户帐户连接到服务器,您必须设置加密连接,如 Section 19.3.1, “Setting Up Replication to Use Encrypted Connections”中所述,或启用不加密连接以支持使用 RSA 密钥对进行密码交换。

设置用户帐户后,使用GRANT语句授予附加权限,以使用户帐户能够执行您期望应用程序线程执行的数据库更改,例如更新服务器上保存的特定表。这些相同的权限使管理员能够在需要手动执行任何这些事务的情况下使用该帐户在复制通道上执行操作。如果尝试执行未授予适当权限的意外操作,则该操作将被拒绝,并且复制应用程序线程将停止并显示错误。Section 19.3.3.1, “Privileges For The Replication PRIVILEGE_CHECKS_USER Account”解释了帐户需要的其他权限。例如,要授予priv_repl用户帐户向db1中的cust表添加行的INSERT权限,发出以下语句:

mysql> GRANT INSERT ON db1.cust TO 'priv_repl'@'%.example.com';

通过CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(MySQL 8.0.23 之前)为复制通道分配PRIVILEGE_CHECKS_USER帐户。如果复制正在运行,请在CHANGE MASTER TO语句之前发出STOP REPLICA(或在 MySQL 8.0.22 之前,STOP SLAVE)命令,并在其后发出START REPLICA。强烈建议在设置PRIVILEGE_CHECKS_USER时使用基于行的二进制日志记录,并且从 MySQL 8.0.19 开始,您可以使用该语句设置REQUIRE_ROW_FORMAT以强制执行此操作。

当重新启动复制通道时,动态特权的检查从那时开始应用。但是,静态全局特权在应用程序的上下文中不活动,直到重新加载授权表,因为这些特权不会更改为连接的客户端。要激活静态特权,请执行刷新特权操作。可以通过发出FLUSH PRIVILEGES语句或执行mysqladmin flush-privilegesmysqladmin reload命令来完成此操作。

例如,在运行中的 MySQL 8.0.23 及更高版本中,要在通道channel_1上启动特权检查,请执行以下语句:

mysql> STOP REPLICA FOR CHANNEL 'channel_1';
mysql> CHANGE REPLICATION SOURCE TO
     >    PRIVILEGE_CHECKS_USER = 'priv_repl'@'%.example.com',
     >    REQUIRE_ROW_FORMAT = 1 FOR CHANNEL 'channel_1';
mysql> FLUSH PRIVILEGES;
mysql> START REPLICA FOR CHANNEL 'channel_1';

在 MySQL 8.0.23 之前,您可以使用以下显示的语句:

mysql> STOP SLAVE FOR CHANNEL 'channel_1';
mysql> CHANGE MASTER TO
     >    PRIVILEGE_CHECKS_USER = 'priv_repl'@'%.example.com',
     >    REQUIRE_ROW_FORMAT = 1 FOR CHANNEL 'channel_1';
mysql> FLUSH PRIVILEGES;
mysql> START SLAVE FOR CHANNEL 'channel_1';

如果未指定通道且不存在其他通道,则该语句将应用于默认通道。在性能模式replication_applier_configuration表中显示了频道的PRIVILEGE_CHECKS_USER帐户的用户名和主机名,它们已经适当转义,因此可以直接复制到 SQL 语句中以执行单个事务。

在 MySQL 8.0.31 及更高版本中,如果使用Rewriter插件,则应授予PRIVILEGE_CHECKS_USER用户帐户SKIP_QUERY_REWRITE特权。这可以防止此用户发出的语句被重写。有关更多信息,请参见第 7.6.4 节,“Rewriter Query Rewrite Plugin”。

当为复制通道设置REQUIRE_ROW_FORMAT时,复制应用程序不会创建或删除临时表,因此不会设置pseudo_thread_id会话系统变量。它不执行LOAD DATA INFILE指令,因此不会尝试文件操作以访问或删除与数据加载相关的临时文件(作为Format_description_log_event记录)。它不执行INTVARRANDUSER_VAR事件,这些事件用于重现基于语句的复制的客户端连接状态。 (一个例外是与 DDL 查询相关的USER_VAR事件,这些事件将被执行。)它不执行在 DML 事务中记录的任何语句。如果复制应用程序在尝试排队或应用事务时检测到这些类型的事件之一,则不会应用该事件,并且复制将因错误而停止。

无论是否设置了PRIVILEGE_CHECKS_USER账户,都可以为复制通道设置REQUIRE_ROW_FORMAT。即使没有特权检查,当设置此选项时实施的限制也会增加复制通道的安全性。在使用mysqlbinlog时,还可以指定--require-row-format选项,以强制在mysqlbinlog输出中执行基于行的复制事件。

安全上下文。 默认情况下,当使用指定的用户账户启动复制应用程序线程作为PRIVILEGE_CHECKS_USER时,安全上下文将使用默认角色创建,或者如果activate_all_roles_on_login设置为ON,则使用所有角色。

你可以使用角色为作为PRIVILEGE_CHECKS_USER账户使用的账户提供一般的权限集,就像以下示例中所示。在这里,与之前的示例中直接向用户账户授予db1.cust表的INSERT权限不同,这个权限被授予给了角色priv_repl_role,同时还有REPLICATION_APPLIER权限。然后使用该角色将权限集授予两个用户账户,这两个账户现在都可以作为PRIVILEGE_CHECKS_USER账户使用:

mysql> SET sql_log_bin = 0;
mysql> CREATE USER 'priv_repa'@'%.example.com'
                  IDENTIFIED BY '*password*'
                  REQUIRE SSL;
mysql> CREATE USER 'priv_repb'@'%.example.com'
                  IDENTIFIED BY '*password*'
                  REQUIRE SSL;
mysql> CREATE ROLE 'priv_repl_role';
mysql> GRANT REPLICATION_APPLIER TO 'priv_repl_role';
mysql> GRANT INSERT ON db1.cust TO 'priv_repl_role';
mysql> GRANT 'priv_repl_role' TO
                  'priv_repa'@'%.example.com',
                  'priv_repb'@'%.example.com';
mysql> SET DEFAULT ROLE 'priv_repl_role' TO
                  'priv_repa'@'%.example.com',
                  'priv_repb'@'%.example.com';
mysql> SET sql_log_bin = 1;

请注意,当复制应用程序线程创建安全上下文时,它会检查PRIVILEGE_CHECKS_USER账户的权限,但不执行密码验证,并且不执行与账户管理相关的检查,例如检查账户是否被锁定。创建的安全上下文在复制应用程序线程的生命周期内保持不变。

限制。 在 MySQL 8.0.18 版本中,如果在发出RESET REPLICA语句后立即重新启动复制mysqld(由于意外服务器退出或有意重启),则mysql.slave_relay_log_info表中保存的PRIVILEGE_CHECKS_USER账户设置将丢失,必须重新指定。在使用特权检查时,始终在重新启动后验证它们是否存在,并在需要时重新指定。从 MySQL 8.0.19 开始,在这种情况下,PRIVILEGE_CHECKS_USER账户设置将被保留,因此它将从表中检索并重新应用到通道中。

原文:dev.mysql.com/doc/refman/8.0/en/replication-privilege-checks-account.html

19.3.3.1 用于复制 PRIVILEGE_CHECKS_USER 账户的特权

使用CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO语句指定的用户账户作为复制通道的PRIVILEGE_CHECKS_USER账户必须具有REPLICATION_APPLIER特权,否则复制应用程序线程将无法启动。如第 19.3.3 节“复制特权检查”所述,该账户需要进一步的特权,足以应用在复制通道上预期的所有预期事务。这些特权仅在执行相关事务时才会检查。

强烈建议对使用PRIVILEGE_CHECKS_USER账户保护的复制通道使用基于行的二进制日志记录(binlog_format=ROW)。对于基于语句的二进制日志记录,PRIVILEGE_CHECKS_USER账户可能需要一些管理员级别的特权才能成功执行事务。从 MySQL 8.0.19 开始,可以将REQUIRE_ROW_FORMAT设置应用于受保护的通道,限制通道执行需要这些特权的事件。

REPLICATION_APPLIER特权明确或隐含允许PRIVILEGE_CHECKS_USER账户执行复制线程需要执行的以下操作:

  • 设置系统变量gtid_nextoriginal_commit_timestamporiginal_server_versionimmediate_server_version,以及pseudo_replica_modepseudo_slave_mode的值,以在执行事务时应用适当的元数据和行为。

  • 执行内部使用的BINLOG语句来应用mysqlbinlog输出,前提是该账户还具有这些语句中的表和操作的权限。

  • 更新系统表 mysql.gtid_executedmysql.slave_relay_log_infomysql.slave_worker_infomysql.slave_master_info,以更新复制元数据。(如果事件明确访问这些表以进行其他目的,必须在这些表上授予适当的权限。)

  • 应用二进制日志 Table_map_log_event,提供表元数据但不进行任何数据库更改。

如果 CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO 语句的 REQUIRE_TABLE_PRIMARY_KEY_CHECK 选项设置为默认的 STREAMPRIVILEGE_CHECKS_USER 账户需要具有足够权限设置受限制的会话变量,以便它可以在会话期间更改与源复制的设置匹配的 sql_require_primary_key 系统变量的值。SESSION_VARIABLES_ADMIN 权限赋予该账户此功能。此权限还允许账户应用使用使用 --disable-log-bin 选项创建的 mysqlbinlog 输出。如果将 REQUIRE_TABLE_PRIMARY_KEY_CHECK 设置为 ONOFF,则副本始终在复制操作中使用该值作为 sql_require_primary_key 系统变量的值,因此不需要这些会话管理级别的权限。

如果使用表加密,table_encryption_privilege_check 系统变量设置为 ON,并且涉及任何事件的表空间的加密设置与应用服务器的默认加密设置(由 default_table_encryption 系统变量指定)不同,PRIVILEGE_CHECKS_USER 账户需要具有 TABLE_ENCRYPTION_ADMIN 权限才能覆盖默认加密设置。强烈建议不要授予此权限。相反,确保副本上的默认加密设置与其复制的表空间的加密状态匹配,并且复制组成员具有相同的默认加密设置,这样就不需要该权限。

为了从中继日志执行特定的复制事务,或根据需要执行来自 mysqlbinlog 输出的事务,PRIVILEGE_CHECKS_USER 账户必须具有以下权限:

  • 对于以行格式记录的行插入(记录为Write_rows_log_event),需要在相关表上具有INSERT权限。

  • 对于以行格式记录的行更新(记录为Update_rows_log_event),需要在相关表上具有UPDATE权限。

  • 对于以行格式记录的行删除(记录为Delete_rows_log_event),需要在相关表上具有DELETE权限。

如果正在使用基于语句的二进制日志记录(不建议在PRIVILEGE_CHECKS_USER账户下使用),对于像BEGINCOMMIT或以语句格式记录的 DML(记录为Query_log_event)的事务控制语句,PRIVILEGE_CHECKS_USER账户需要有执行事件中包含的语句所需的权限。

如果需要在复制通道上执行LOAD DATA操作,请使用基于行的二进制日志记录(binlog_format=ROW)。使用此日志记录格式时,不需要FILE权限来执行事件,因此不要给PRIVILEGE_CHECKS_USER账户此权限。强烈建议在使用PRIVILEGE_CHECKS_USER账户保护的复制通道上使用基于行的二进制日志记录。如果为通道设置了REQUIRE_ROW_FORMAT,则需要基于行的二进制日志记录。处理LOAD DATA事件创建的任何临时文件的Format_description_log_event会在不进行权限检查的情况下进行。有关更多信息,请参见 Section 19.5.1.19, “Replication and LOAD DATA”。

如果init_replicainit_slave系统变量被设置为指定在复制 SQL 线程启动时要执行的一个或多个 SQL 语句,则PRIVILEGE_CHECKS_USER账户必须具有执行这些语句所需的权限。

不建议将任何 ACL 权限授予PRIVILEGE_CHECKS_USER账户,包括CREATE USERCREATE ROLEDROP ROLEGRANT OPTION,也不允许该账户更新mysql.user表。拥有这些权限,该账户可以用于在服务器上创建或修改用户账户。为避免源服务器上发出的 ACL 语句被复制到安全通道以供执行(在缺少这些权限的情况下会失败),您可以在所有 ACL 语句之前发出SET sql_log_bin = 0,在其后发出SET sql_log_bin = 1,以从源二进制日志中省略这些语句。或者,您可以在执行所有 ACL 语句之前设置一个专用的当前数据库,并使用复制过滤器(--binlog-ignore-db)来在副本中过滤掉这个数据库。

原文:dev.mysql.com/doc/refman/8.0/en/replication-privilege-checks-gr.html

19.3.3.2 组复制通道的权限检查

从 MySQL 8.0.19 开始,除了保护异步和半同步复制外,您还可以选择使用PRIVILEGE_CHECKS_USER帐户来保护组复制使用的两个复制应用程序线程。每个组成员上的group_replication_applier线程用于应用组的事务,每个组成员上的group_replication_recovery线程用于从二进制日志中进行状态传输,作为成员加入或重新加入组时的分布式恢复的一部分。

要保护其中一个线程,停止组复制,然后使用CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(在 MySQL 8.0.23 之前)并指定PRIVILEGE_CHECKS_USER选项,将group_replication_appliergroup_replication_recovery作为通道名称。例如:

mysql> STOP GROUP_REPLICATION;
mysql> CHANGE MASTER TO PRIVILEGE_CHECKS_USER = 'gr_repl'@'%.example.com' 
          FOR CHANNEL 'group_replication_recovery';
mysql> FLUSH PRIVILEGES;
mysql> START GROUP_REPLICATION;

Or from MySQL 8.0.23:
mysql> STOP GROUP_REPLICATION;
mysql> CHANGE REPLICATION SOURCE TO PRIVILEGE_CHECKS_USER = 'gr_repl'@'%.example.com' 
          FOR CHANNEL 'group_replication_recovery';
mysql> FLUSH PRIVILEGES;
mysql> START GROUP_REPLICATION;

对于组复制通道,当通道创建时会自动启用REQUIRE_ROW_FORMAT设置,无法禁用,因此您无需指定此设置。

重要提示

在 MySQL 8.0.19 中,请确保在运行组复制时不要使用CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO语句与PRIVILEGE_CHECKS_USER选项。此操作会导致通道的中继日志文件被清除,可能导致已接收并排队在中继日志中但尚未应用的事务丢失。

Group Replication 要求每个要被组复制的表都必须有一个定义的主键,或者等效的主键,其中等效的主键是一个非空唯一键。与sql_require_primary_key系统变量执行的检查不同,Group Replication 有自己内置的一套用于主键或主键等效的检查。您可以为 Group Replication 通道设置CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO语句的REQUIRE_TABLE_PRIMARY_KEY_CHECK选项为ON。但是,请注意,您可能会发现一些在 Group Replication 内置检查下允许的事务,在设置sql_require_primary_key = ONREQUIRE_TABLE_PRIMARY_KEY_CHECK = ON时不被允许。因此,从 MySQL 8.0.20(引入该选项时)开始,新的和升级的 Group Replication 通道将REQUIRE_TABLE_PRIMARY_KEY_CHECK设置为默认的STREAM,而不是ON

如果在 Group Replication 中使用远程克隆操作进行分布式恢复(参见 Section 20.5.4.2, “Cloning for Distributed Recovery”),从 MySQL 8.0.19 开始,PRIVILEGE_CHECKS_USER账户和相关设置从捐赠方克隆到加入成员。如果设置加入成员在启动时启动 Group Replication,则它会自动使用该账户对适当的复制通道进行特权检查。

在 MySQL 8.0.18 中,由于一些限制,建议不要在 Group Replication 通道中使用PRIVILEGE_CHECKS_USER账户。

原文:dev.mysql.com/doc/refman/8.0/en/replication-privilege-checks-recover.html

19.3.3.3 从失败的复制特权检查中恢复

如果针对PRIVILEGE_CHECKS_USER账户的特权检查失败,则不会执行事务,并且通道上的复制将停止。错误的详细信息和最后应用的事务记录在性能模式replication_applier_status_by_worker表中。按照以下步骤从错误中恢复:

  1. 确定导致错误的复制事件,并验证事件是否预期且来自可信任的来源。您可以使用mysqlbinlog检索和显示围绕错误发生时间记录的事件。有关如何执行此操作的说明,请参见第 9.5 节,“时间点(增量)恢复” Recovery")。

  2. 如果复制的事件是意外的或不是来自已知和可信任的来源,请调查原因。如果您能够确定事件发生的原因,并且没有安全考虑因素,请按照以下描述修复错误。

  3. 如果PRIVILEGE_CHECKS_USER账户应该被允许执行事务,但已经配置错误,请向账户授予缺失的特权,使用FLUSH PRIVILEGES语句或执行mysqladmin flush-privilegesmysqladmin reload命令重新加载授权表,然后重新启动通道上的复制。

  4. 如果需要执行事务并且已经验证了其可信性,但PRIVILEGE_CHECKS_USER账户通常不应具有此特权,您可以临时授予PRIVILEGE_CHECKS_USER账户所需的特权。在应用了复制事件之后,从账户中删除特权,并采取任何必要的步骤确保事件不会再次发生(如果可以避免)。

  5. 如果事务是应该仅在源端而不是在副本上发生的管理操作,或者应该仅在单个复制组成员上发生,可以在停止复制的服务器上跳过事务,然后发出START REPLICA来重新启动通道上的复制。为了避免将来出现这种情况,您可以在这些管理语句之前使用SET sql_log_bin = 0,之后再使用SET sql_log_bin = 1,这样它们就不会在源端记录。

  6. 如果事务是一个不应该在源端或副本端发生的 DDL 或 DML 语句,请在停止复制的服务器上跳过该事务,然后在原始发生事务的服务器上手动撤销该事务,最后发出START REPLICA以重新启动复制。

要跳过一个事务,如果正在使用 GTIDs,请提交一个具有失败事务 GTID 的空事务,例如:

SET GTID_NEXT='aaa-bbb-ccc-ddd:N';
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';

如果没有使用 GTIDs,请发出SET GLOBAL sql_replica_skip_counterSET GLOBAL sql_slave_skip_counter语句以跳过该事件。有关使用此替代方法和有关跳过事务的更多详细信息,请参见 Section 19.1.7.3, “Skipping Transactions”。

19.4 复制解决方案

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions.html

19.4.1 用于备份的复制

19.4.2 处理副本意外停止

19.4.3 监控基于行的复制

19.4.4 使用不同源和副本存储引擎进行复制

19.4.5 用于扩展的复制

19.4.6 将不同数据库复制到不同副本

19.4.7 改善复制性能

19.4.8 在故障转移期间切换源

19.4.9 使用异步连接故障转移切换源和副本

19.4.10 半同步复制

19.4.11 延迟复制

复制可以在许多不同的环境中用于各种目的。本节提供了关于在特定解决方案类型中使用复制的一般注意事项和建议。

有关在备份环境中使用复制的信息,包括设置、备份过程和需要备份的文件,请参见第 19.4.1 节,“用于备份的复制”。

关于在源和副本上使用不同存储引擎的建议和提示,请参见第 19.4.4 节,“使用不同源和副本存储引擎进行复制”。

将复制用作扩展解决方案需要对使用该解决方案的应用程序的逻辑和操作进行一些更改。请参见第 19.4.5 节,“用于扩展的复制”。

出于性能或数据分发原因,您可能希望将不同数据库复制到不同的副本。请参见第 19.4.6 节,“将不同数据库复制到不同副本”。

随着副本数量的增加,源的负载可能会增加,导致性能降低(因为需要将二进制日志复制到每个副本)。有关改善复制性能的提示,包括使用单个辅助服务器作为源,请参见第 19.4.7 节,“改善复制性能”。

关于切换数据源的指导,或将复制品转换为数据源作为紧急故障转移解决方案的一部分,请参阅第 19.4.8 节,“故障转移期间切换数据源”。

关于复制拓扑中服务器特定的安全措施信息,请参阅第 19.3 节,“复制安全性”。

19.4.1 使用复制进行备份

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-backups.html

19.4.1.1 使用 mysqldump 备份副本

19.4.1.2 从副本备份原始数据

19.4.1.3 通过将源或副本设置为只读状态备份

要将复制用作备份解决方案,请将数据从源复制到副本,然后备份副本。副本可以暂停和关闭而不影响源的运行操作,因此您可以生成“实时”数据的有效快照,否则需要关闭源才能完成。

如何备份数据库取决于其大小以及您是仅备份数据还是备份数据和副本状态,以便在发生故障时可以重建副本。因此有两种选择:

  • 如果您使用复制作为解决方案来使您能够备份源上的数据,并且您的数据库大小不是太大,那么mysqldump工具可能适合。请参阅 Section 19.4.1.1, “使用 mysqldump 备份副本”。

  • 对于较大的数据库,mysqldump可能不切实际或低效,您可以备份原始数据文件。使用原始数据文件选项还意味着您可以备份二进制和中继日志,以便在副本故障时重新创建副本。有关更多信息,请参阅 Section 19.4.1.2, “从副本备份原始数据”。

另一种备份策略,可用于源服务器或副本服务器,是将服务器设置为只读状态。备份针对只读服务器执行,然后将其更改回通常的读/写操作状态。请参阅 Section 19.4.1.3, “通过将源或副本设置为只读状态备份”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-backups-mysqldump.html

19.4.1.1 使用 mysqldump 备份副本

使用mysqldump创建数据库副本可以捕获数据库中的所有数据,并以一种格式导入到另一个 MySQL Server 实例中(参见第 6.5.4 节,“mysqldump — A Database Backup Program”)。由于信息的格式是 SQL 语句,因此文件可以轻松分发并应用于正在运行的服务器,以便在紧急情况下访问数据。但是,如果您的数据集很大,使用mysqldump可能不切实际。

提示

考虑使用 MySQL Shell 转储工具,提供多线程并行转储、文件压缩和进度信息显示,以及云功能,如 Oracle Cloud Infrastructure Object Storage 流式传输和 MySQL HeatWave Service 兼容性检查和修改。转储可以使用 MySQL Shell 加载转储工具轻松导入到 MySQL Server 实例或 MySQL HeatWave Service DB System 中。MySQL Shell 的安装说明可在此处找到。

使用mysqldump在开始转储过程之前应停止副本上的复制,以确保转储包含一致的数据集:

  1. 停止副本处理请求。您可以使用mysqladmin完全停止副本上的复制:

    $> mysqladmin stop-slave
    

    或者,您可以仅停止复制 SQL 线程以暂停事件执行:

    $> mysql -e 'STOP SLAVE SQL_THREAD;'
    Or from MySQL 8.0.22:
    $> mysql -e 'STOP REPLICA SQL_THREAD;'
    

    这使得副本可以继续接收来自源二进制日志的数据更改事件,并使用复制接收器线程将其存储在中继日志中,但阻止副本执行这些事件并更改其数据。在繁忙的复制环境中,允许复制接收器线程在备份期间运行可能会加快重新启动复制应用程序线程时的赶上过程。

  2. 运行 mysqldump 来转储您的数据库。您可以转储所有数据库或选择要转储的数据库。例如,要转储所有数据库:

    $> mysqldump --all-databases > fulldb.dump
    
  3. 转储完成后,重新启动复制:

    $> mysqladmin start-slave
    

在上面的示例中,您可能希望将登录凭据(用户名、密码)添加到命令中,并将整个过程打包成一个脚本,以便每天自动运行。

如果您采用这种方法,请确保监控复制过程,以确保运行备份所需的时间不会影响副本跟上源事件的能力。请参见第 19.1.7.1 节,“检查复制状态”。如果副本无法跟上,您可能需要添加另一个副本并分发备份过程。有关如何配置此场景的示例,请参见第 19.4.6 节,“将不同数据库复制到不同副本”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-backups-rawdata.html

19.4.1.2 从复制中备份原始数据

为了保证复制的文件完整性,在关闭 MySQL 复制服务器时备份原始数据文件应该进行。如果 MySQL 服务器仍在运行,后台任务可能仍在更新数据库文件,特别是涉及具有后台进程的存储引擎,如InnoDB。对于InnoDB,这些问题应该在崩溃恢复期间得到解决,但由于在备份过程中关闭复制服务器而不影响源执行的能力,可以利用这一功能。

要关闭服务器并备份文件:

  1. 关闭复制 MySQL 服务器:

    $> mysqladmin shutdown
    
  2. 复制数据文件。您可以使用任何适当的复制或存档工具,包括cptarWinZip。例如,假设数据目录位于当前目录下,您可以将整个目录存档如下:

    $> tar cf /tmp/dbbackup.tar ./data
    
  3. 再次启动 MySQL 服务器。在 Unix 系统下:

    $> mysqld_safe &
    

    在 Windows 系统下:

    C:\> "C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld"
    

通常应该备份整个复制 MySQL 服务器的数据目录。如果您希望能够恢复数据并作为复制运行(例如,在复制发生故障时),除了数据外,您还需要复制的连接元数据存储库和应用程序元数据存储库,以及中继日志文件。这些项目在恢复复制数据后需要用于恢复复制。假设表已用于复制的连接元数据存储库和应用程序元数据存储库(请参阅 Section 19.2.4, “Relay Log and Replication Metadata Repositories”),这是 MySQL 8.0 的默认设置,这些表将与数据目录一起备份。如果文件已用于存储库,这已被弃用,您必须单独备份这些文件。如果中继日志文件已放置在与数据目录不同的位置,则必须单独备份中继日志文件。

如果您丢失了中继日志但仍有relay-log.info文件,您可以检查它以确定复制 SQL 线程在源二进制日志中执行到哪个程度。然后,您可以使用CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(在 MySQL 8.0.23 之前)与SOURCE_LOG_FILE | MASTER_LOG_FILESOURCE_LOG_POS | MASTER_LOG_POS选项告诉复制从那一点重新读取二进制日志。这要求源服务器上的二进制日志仍然存在。

如果您的复制品正在复制LOAD DATA语句,您还应该备份复制品用于此目的的目录中存在的任何SQL_LOAD-*文件。复制品需要这些文件来恢复任何中断的LOAD DATA操作的复制。此目录的位置是系统变量replica_load_tmpdir(从 MySQL 8.0.26 开始)或slave_load_tmpdir(在 MySQL 8.0.26 之前)。如果服务器未使用该变量启动,则目录位置是tmpdir系统变量的值。

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-backups-read-only.html

19.4.1.3 通过将其设置为只读来备份源或复制品

可以通过获取全局读锁并操作 read_only 系统变量来改变要备份服务器的只读状态,从而备份复制设置中的源或复制服务器:

  1. 将服务器设置为只读,以便仅处理检索并阻止更新。

  2. 执行备份。

  3. 将服务器改回正常的读写状态。

注意

本节中的说明将要备份的服务器置于安全状态,以便备份方法从服务器获取数据,例如 mysqldump(参见 第 6.5.4 节,“mysqldump — 数据库备份程序”)。您不应尝试使用这些说明通过直接复制文件来进行二进制备份,因为服务器可能仍然在内存中缓存修改的数据,尚未刷新到磁盘。

本节中的说明描述了如何为源和复制品执行此操作。对于这里讨论的两种场景,假设您有以下复制设置:

  • 一个源服务器 S1

  • 一个复制服务器 R1,其源为 S1

  • 一个连接到 S1 的客户端 C1

  • 一个连接到 R1 的客户端 C2

在任一场景中,获取全局读锁并操作 read_only 变量的语句是在要备份的服务器上执行的,不会传播到该服务器的任何副本。

场景 1:只读源备份

通过在源 S1 上执行以下语句,将源 S1 置于只读状态:

mysql> FLUSH TABLES WITH READ LOCK;
mysql> SET GLOBAL read_only = ON;

当 S1 处于只读状态时,以下属性为真:

  • 由 C1 发送到 S1 的更新请求被阻塞,因为服务器处于只读模式。

  • 由 C1 发送到 S1 的查询结果请求成功。

  • 在 S1 上进行备份是安全的。

  • 在 R1 上进行备份是不安全的。该服务器仍在运行,并且可能正在处理二进制日志或来自客户端 C2 的更新请求。

当 S1 处于只读状态时,执行备份。例如,您可以使用 mysqldump

在 S1 上的备份操作完成后,通过执行以下语句将 S1 恢复到正常运行状态:

mysql> SET GLOBAL read_only = OFF;
mysql> UNLOCK TABLES;

尽管在 S1 上执行备份是安全的(就备份而言),但对性能来说并不是最佳选择,因为 S1 的客户端被阻止执行更新操作。

这种策略适用于在复制设置中备份源,但也可以用于非复制设置中的单个服务器。

场景 2:只读复制备份

通过在复制 R1 上执行以下语句,将复制 R1 置于只读状态:

mysql> FLUSH TABLES WITH READ LOCK;
mysql> SET GLOBAL read_only = ON;

当 R1 处于只读状态时,以下属性为真:

  • 源 S1 仍在运行,因此在源上进行备份是不安全的。

  • 副本 R1 已停止,因此在副本 R1 上进行备份是安全的。

这些属性为一种常见的备份场景提供了基础:让一个副本在一段时间内忙于执行备份不会造成问题,因为它不会影响整个网络,而且系统在备份期间仍在运行。特别是,客户端仍然可以在源服务器上执行更新操作,而备份副本上的备份活动不会对源服务器产生影响。

当 R1 处于只读状态时,执行备份操作。例如,您可以使用mysqldump

完成 R1 上的备份操作后,通过执行以下语句将 R1 恢复到正常运行状态:

mysql> SET GLOBAL read_only = OFF;
mysql> UNLOCK TABLES;

将副本恢复到正常运行状态后,它会通过追赶源的二进制日志中的任何未完成更新再次与源进行同步。

19.4.2 处理复制品意外停止

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-unexpected-replica-halt.html

为了使复制对服务器的意外停止具有弹性(有时被描述为崩溃安全),必须使复制品能够在停止之前恢复其状态。本节描述了复制过程中复制品意外停止的影响,以及如何配置复制品以获得继续复制的最佳恢复机会。

在复制品意外停止后,重新启动时,复制 SQL 线程必须恢复已执行的事务的信息。恢复所需的信息存储在复制品的应用程序元数据存储库中。从 MySQL 8.0 开始,默认情况下,此存储库以名为mysql.slave_relay_log_infoInnoDB表的形式创建。通过使用这种事务性存储引擎,信息始终可以在重新启动时恢复。对应用程序元数据存储库的更新与事务一起提交,这意味着记录在该存储库中的复制品进度信息始终与已应用于数据库的内容一致,即使服务器意外停止也是如此。有关应用程序元数据存储库的更多信息,请参见第 19.2.4 节“中继日志和复制元数据存储库”。

DML 事务和原子 DDL 更新也会在mysql.slave_relay_log_info表中更新复制品的应用程序元数据存储库的复制位置,并将更改应用于数据库,作为一个原子操作。在所有其他情况下,包括不完全原子的 DDL 语句和不支持原子 DDL 的豁免存储引擎,如果服务器意外停止,mysql.slave_relay_log_info表可能会缺少与复制数据相关的更新。在这种情况下,恢复更新是一个手动过程。有关 MySQL 8.0 中原子 DDL 支持的详细信息以及某些语句复制的结果行为,请参见第 15.1.1 节“原子数据定义语句支持”。

复制品从意外停止中恢复的恢复过程取决于复制品的配置。恢复过程的细节受到复制方法的选择、复制品是单线程还是多线程以及相关系统变量设置的影响。恢复过程的总体目标是确定在意外停止发生之前复制品的数据库上已经应用了哪些事务,并检索并应用在意外停止后复制品错过的事务。

  • 对于基于 GTID 的复制,恢复过程需要副本已经接收或提交的事务的 GTID。缺失的事务可以通过 GTID 自动定位从源获取,该过程会自动比较源的事务和副本的事务,并识别缺失的事务。

  • 对于基于文件位置的复制,恢复过程需要准确的复制 SQL 线程(应用程序)位置,显示在副本上应用的最后一个事务。基于该位置,复制 I/O 线程(接收器)从源的二进制日志中检索应该从该点开始在副本上应用的所有事务。

使用基于 GTID 的复制使得配置复制以应对意外停止变得最容易。GTID 自动定位意味着副本可以可靠地识别和检索缺失的事务,即使应用事务序列中存在间隙。

以下信息提供了适用于不同类型副本的设置组合,以确保在复制控制范围内尽可能实现恢复。

重要提示

复制控制范围之外的一些因素可能会影响复制恢复过程和恢复过程后复制的整体状态。特别是,影响各个存储引擎恢复过程的设置可能导致在副本意外停止时丢失事务,因此这些事务对于复制恢复过程不可用。下面列表中提到的innodb_flush_log_at_trx_commit=1设置是使用带有事务的InnoDB的复制设置的关键设置。然而,特定于InnoDB或其他存储引擎的其他设置,特别是与刷新或同步相关的设置,也可能会产生影响。始终检查并应用您选择的存储引擎关于崩溃安全设置的建议。

在副本上的以下设置组合对于意外停止是最具弹性的:

  • 当使用基于 GTID 的复制时(gtid_mode=ON),设置SOURCE_AUTO_POSITION=1 | MASTER_AUTO_POSITION=1,这将激活 GTID 自动定位,使连接到源的连接自动识别并检索丢失的事务。可以使用CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(MySQL 8.0.23 之前)来设置此选项。如果复制品有多个复制通道,则需要为每个通道单独设置此选项。有关 GTID 自动定位的工作原理的详细信息,请参见第 19.1.3.3 节,“GTID 自动定位”。当使用基于文件位置的复制时,不使用SOURCE_AUTO_POSITION=1 | MASTER_AUTO_POSITION=1,而是使用二进制日志位置或中继日志位置来控制复制开始的位置。

  • 从 MySQL 8.0.27 开始,当使用基于 GTID 的复制时(gtid_mode=ON),设置GTID_ONLY=1,这使得复制品在恢复过程中仅使用 GTID,并停止在复制元数据存储库中持久化二进制日志和中继日志文件名和文件位置。可以使用CHANGE REPLICATION SOURCE TO语句来设置此选项。如果复制品有多个复制通道,则需要为每个通道单独设置此选项。使用GTID_ONLY=1时,在恢复过程中,将忽略文件位置信息,并使用 GTID 自动跳过来跳过已经提供的事务,而不是识别正确的文件位置。这种策略更有效,前提是您使用relay_log_purge的默认设置清除中继日志,这意味着只需要检查一个中继日志文件。

  • 设置sync_relay_log=1,指示复制接收线程在每个接收的事务写入后将中继日志同步到磁盘。这意味着副本从源二进制日志中读取的当前位置记录(在应用程序元数据存储库中)永远不会超过保存在中继日志中的事务记录。请注意,尽管这个设置是最安全的,但由于涉及磁盘写入的次数较多,因此也是最慢的。当sync_relay_log > 1sync_relay_log=0(其中同步由操作系统处理)时,在副本意外停止的情况下,可能存在已提交但尚未同步到磁盘的事务。这些事务可能会导致恢复过程失败,如果正在恢复的副本根据中继日志中的信息(最后一次同步到磁盘)尝试重新检索和应用事务而不是跳过它们。设置sync_relay_log=1对于多线程副本尤为重要,如果无法使用中继日志中的信息填补事务序列中的间隙,则恢复过程将失败。对于单线程副本,只有在应用程序元数据存储库中没有相关信息时,恢复过程才需要使用中继日志。

  • 设置innodb_flush_log_at_trx_commit=1,在每个事务提交之前将InnoDB日志同步到磁盘。这个默认设置确保InnoDB表和InnoDB日志被保存在磁盘上,因此不再需要关于事务的中继日志中的信息。结合设置sync_relay_log=1,这个设置进一步确保InnoDB表和InnoDB日志的内容始终与中继日志的内容一致,以便在意外停止时,清除中继日志文件不会导致副本事务历史中存在无法填补的间隙。

  • 设置relay_log_info_repository = TABLE,将复制 SQL 线程位置存储在InnoDBmysql.slave_relay_log_info中,并与事务提交一起更新,以确保始终准确的记录。这个设置是 MySQL 8.0 的默认设置,FILE设置已被弃用。从 MySQL 8.0.23 开始,系统变量本身的使用已被弃用,因此可以省略它并允许其默认值。如果使用了FILE设置,这在早期版本中是默认设置,信息将存储在数据目录中的文件中,在事务应用后更新。这会导致与源的同步丢失的风险,具体取决于副本在处理事务的哪个阶段停止,甚至文件本身的损坏。使用设置relay_log_info_repository = FILE,无法保证恢复。

  • 设置relay_log_recovery = ON,在服务器启动后立即启用自动中继日志恢复。这个全局变量默认为OFF,在运行时是只读的,但您可以在副本启动时使用--relay-log-recovery选项将其设置为ON,以应对副本意外停止。请注意,此设置会忽略现有的中继日志文件,以防它们损坏或不一致。中继日志恢复过程会启动一个新的中继日志文件,并从在应用程序元数据存储库中记录的复制 SQL 线程位置开始从源获取事务。副本的正常清理机制会随着时间删除先前的中继日志文件。

对于多线程复制,设置relay_log_recovery = ON会自动处理中继日志中已执行的事务序列中的任何不一致和间隙。当使用基于文件位置的复制时,这些间隙可能会发生。(有关更多详细信息,请参见第 19.5.1.34 节,“复制和事务不一致性”。)中继日志恢复过程使用与START REPLICA UNTIL SQL_AFTER_MTS_GAPS(或在 MySQL 8.0.22 之前,使用START SLAVE而不是START REPLICA)语句相同的方法处理间隙。当复制达到一致的无间隙状态时,中继日志恢复过程继续从源头开始获取进一步的事务,从复制 SQL 线程位置开始。当使用基于 GTID 的复制时,从 MySQL 8.0.18 开始,多线程复制首先检查MASTER_AUTO_POSITION是否设置为ON,如果是,则省略计算应跳过或不跳过的事务的步骤,因此旧的中继日志不需要用于恢复过程。

19.4.3 监视基于行的复制

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-rbr-monitoring.html

当使用基于行的复制时,通过性能模式仪表阶段监视复制应用程序(SQL)线程的当前进度,使您能够跟踪操作的处理并检查已完成的工作量和估计的工作量。当启用这些性能模式仪表阶段时,events_stages_current 表显示了应用程序线程的阶段及其进度。有关背景信息,请参阅第 29.12.5 节,“性能模式阶段事件表”。

要跟踪所有三种基于行的复制事件类型(写入、更新、删除)的进度:

  • 通过执行以下命令启用三个性能模式阶段:

    mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
     -> WHERE NAME LIKE 'stage/sql/Applying batch of row changes%';
    
  • 等待一些事件被复制应用程序线程处理,然后通过查看events_stages_current表来检查进度。例如,要获取update事件的进度,请执行:

    mysql> SELECT WORK_COMPLETED, WORK_ESTIMATED FROM performance_schema.events_stages_current
     -> WHERE EVENT_NAME LIKE 'stage/sql/Applying batch of row changes (update)'
    
  • 如果启用了binlog_rows_query_log_events,则会将有关查询的信息存储在二进制日志中,并在processlist_info字段中公开。要查看触发此事件的原始查询:

    mysql> SELECT db, processlist_state, processlist_info FROM performance_schema.threads
     -> WHERE processlist_state LIKE 'stage/sql/Applying batch of row changes%' AND thread_id = N;
    

19.4.4 使用不同源和副本存储引擎的复制

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-diffengines.html

在复制过程中,原始源上的表和副本上的复制表使用不同的存储引擎类型并不重要。实际上,default_storage_engine 系统变量不会被复制。

这在复制过程中提供了许多好处,因为您可以针对不同的复制场景利用不同的引擎类型。例如,在典型的扩展场景中(参见 第 19.4.5 节,“使用复制进行扩展”),您希望在源上使用 InnoDB 表以利用事务功能,但在只读数据的副本上使用 MyISAM,因为不需要事务支持。在数据记录环境中使用复制时,您可能希望在副本上使用 Archive 存储引擎。

在源和副本上配置不同的引擎取决于您如何设置初始复制过程:

  • 如果您使用 mysqldump 在源上创建数据库快照,您可以编辑转储文件文本以更改每个表使用的引擎类型。

    另一个 mysqldump 的替代方法是在使用转储构建副本数据之前禁用不想在副本上使用的引擎类型。例如,您可以在副本上添加 --skip-federated 选项来禁用 FEDERATED 引擎。如果要创建的表没有特定的引擎存在,MySQL 将使用默认的引擎类型,通常是 InnoDB。(这要求未启用 NO_ENGINE_SUBSTITUTION SQL 模式。)如果您想以这种方式禁用其他引擎,您可能需要考虑构建一个专用的二进制文件,该文件仅支持您想要的引擎。

  • 如果您使用原始数据文件(二进制备份)设置副本,则无法更改初始表格式。相反,在启动副本后,请使用 ALTER TABLE 来更改表类型。

  • 对于新的源/复制复制设置,如果源上当前没有表,请在创建新表时避免指定引擎类型。

如果您已经在运行复制解决方案,并希望将现有表转换为另一种引擎类型,请按照以下步骤操作:

  1. 停止副本运行复制更新:

    mysql> STOP SLAVE;
    Or from MySQL 8.0.22:
    mysql> STOP REPLICA;
    

    这样可以在不中断的情况下更改引擎类型。

  2. 对每个要更改的表执行ALTER TABLE ... ENGINE='*engine_type*'

  3. 重新开始复制过程:

    mysql> START SLAVE;
    

    或者,从 MySQL 8.0.22 开始:

    mysql> START REPLICA;
    

尽管default_storage_engine变量不会被复制,但要注意包含引擎规范的CREATE TABLEALTER TABLE语句会正确地被复制到副本中。例如,在CSV表的情况下,如果执行以下语句:

mysql> ALTER TABLE csvtable ENGINE='MyISAM';

这个语句会被复制;副本上的表引擎类型会被转换为InnoDB,即使你之前已经将副本上的表类型更改为CSV之外的其他引擎。如果你想保留源和副本上的引擎差异,创建新表时应当小心使用default_storage_engine变量。例如,不要使用:

mysql> CREATE TABLE tablea (columna int) Engine=MyISAM;

使用这种格式:

mysql> SET default_storage_engine=MyISAM;
mysql> CREATE TABLE tablea (columna int);

在复制时,default_storage_engine变量会被忽略,CREATE TABLE语句会在副本上使用副本的默认引擎执行。

19.4.5 利用复制进行规模扩展

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-scaleout.html

您可以将复制用作规模扩展解决方案;也就是说,您希望在多个数据库服务器之间分配数据库查询负载,但在一定的限制范围内。

由于复制是从一个源到一个或多个副本的分发,因此在具有大量读取和少量写入/更新的环境中使用复制以实现规模扩展性效果最佳。大多数网站属于这一类别,用户在浏览网站、阅读文章、帖子或查看产品时进行操作。更新仅在会话管理期间发生,或在进行购买或向论坛添加评论/消息时发生。

在这种情况下,复制使您能够将读取操作分布到副本上,同时仍然使您的网络服务器在需要写入时与源进行通信。您可以在图 19.1 “利用复制提高规模扩展性”中查看此场景的示例复制布局。

图 19.1 利用复制提高规模扩展性

来自客户端的请求被定向到负载均衡器,负载均衡器将客户端数据分发给多个网络客户端。网络客户端进行的写操作被定向到单个 MySQL 源服务器,而网络客户端进行的读操作被定向到三个 MySQL 副本服务器中的一个。复制操作是从 MySQL 源服务器到三个 MySQL 副本服务器进行的。

如果负责数据库访问的代码部分已经被正确抽象化/模块化,那么将其转换为运行在复制设置中应该是非常顺利和容易的。将数据库访问的实现更改为将所有写操作发送到源,将读取操作发送到源或副本。如果您的代码没有达到这种抽象化水平,设置一个复制系统将为您提供整理代码的机会和动力。首先创建一个实现以下功能的包装库或模块:

  • safe_writer_connect()

  • safe_reader_connect()

  • safe_reader_statement()

  • safe_writer_statement()

每个函数名称中的safe_表示该函数负责处理所有错误条件。您可以为函数使用不同的名称。重要的是要为读取连接、写入连接、执行读取和执行写入提供统一的接口。

然后将客户端代码转换为使用包装库。起初,这可能是一个痛苦和可怕的过程,但从长远来看是值得的。所有使用上述方法的应用程序都能够利用源/副本配置,甚至涉及多个副本。代码更容易维护,并且添加故障排除选项很简单。您只需要修改一个或两个函数(例如,记录每个语句花费的时间,或者哪个语句中出现了错误)。

如果您编写了大量代码,可能希望通过编写转换脚本来自动化转换任务。理想情况下,您的代码使用一致的编程风格约定。如果没有,那么最好重新编写它,或者至少通过手动规范化来使用一致的风格。

19.4.6 将不同的数据库复制到不同的副本

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-partitioning.html

可能存在这样的情况,您有一个单一的源服务器,并且希望将不同的数据库复制到不同的副本。例如,您可能希望将不同的销售数据分发给不同的部门,以帮助在数据分析期间分担负载。此布局的示例显示在图 19.2,“复制数据库以分离副本”中。

图 19.2 复制数据库以分离副本

MySQL 源具有三个数据库,databaseA,databaseB 和 databaseC。databaseA 仅复制到 MySQL 副本 1,databaseB 仅复制到 MySQL 副本 2,databaseC 仅复制到 MySQL 副本 3。

您可以通过将源和副本配置为正常操作,然后通过在每个副本上使用--replicate-wild-do-table配置选项来限制每个副本处理的二进制日志语句,从而实现此分离。

重要提示

当使用基于语句的复制时,不应该使用--replicate-do-db来实现此目的,因为基于语句的复制会导致此选项的效果根据当前选择的数据库而变化。这也适用于混合格式复制,因为这样可以使用基于语句的格式复制一些更新。

但是,如果仅使用基于行的复制,则可以放心使用--replicate-do-db来实现此目的,因为在这种情况下,当前选择的数据库对选项的操作没有影响。

例如,要支持如图 19.2,“复制数据库以分离副本”所示的分离,您应该在执行START REPLICA之前,为每个副本配置如下:

  • 副本 1 应使用--replicate-wild-do-table=databaseA.%

  • 副本 2 应使用--replicate-wild-do-table=databaseB.%

  • 副本 3 应使用--replicate-wild-do-table=databaseC.%

在这种配置中,每个副本都接收源自源服务器的整个二进制日志,但仅执行二进制日志中适用于副本上生效的--replicate-wild-do-table选项包含的数据库和表的事件。

如果您有必须在复制开始之前同步到副本的数据,则有多种选择:

  • 将所有数据同步到每个副本,并删除您不想保留的数据库、表或两者。

  • 使用mysqldump为每个数据库创建单独的转储文件,并在每个副本上加载适当的转储文件。

  • 使用原始数据文件转储,并仅包含每个副本所需的特定文件和数据库。

    注意

    这对InnoDB数据库不起作用,除非您使用innodb_file_per_table

19.4.7 改进复制性能

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-performance.html

随着连接到源的副本数量的增加,负载虽然很小,但也会增加,因为每个副本都使用客户端连接到源。此外,由于每个副本必须接收源的二进制日志的完整副本,因此源上的网络负载也可能增加并创建瓶颈。

如果您正在使用大量与一个源连接的副本,并且该源也在忙于处理请求(例如,作为扩展解决方案的一部分),那么您可能希望改进复制过程的性能。

改进复制过程性能的一种方法是创建一个更深层次的复制结构,使源只能复制到一个副本,而其余副本则连接到此主要副本以满足各自的复制需求。此结构示例如 图 19.3,“使用额外的复制源以提高性能” 中所示。

图 19.3 使用额外的复制源以提高性能

服务器 MySQL 源 1 复制到服务器 MySQL 源 2,后者又复制到服务器 MySQL 副本 1、MySQL 副本 2 和 MySQL 副本 3。

要使其正常工作,您必须按以下方式配置 MySQL 实例:

  • 源 1 是所有更改和更新都写入数据库的主要源。两个源服务器都启用了二进制日志记录,这是默认设置。

  • 源 2 是向其余副本提供复制功能的服务器源 1 的副本。源 2 是唯一被允许连接到源 1 的机器。源 2 启用了 --log-slave-updates 选项(默认情况下启用)。通过此选项,源 1 的复制指令也会被写入源 2 的二进制日志中,然后可以被复制到真正的副本中。

  • 副本 1、副本 2 和副本 3 充当源 2 的副本,并复制来自源 2 的信息,实际上包括在源 1 上记录的升级。

上述解决方案减少了主要源上的客户端负载和网络接口负载,应该提高主要源作为直接数据库解决方案时的整体性能。

如果您的副本在源上跟不上复制过程,那么有多种选择可供选择:

  • 如果可能的话,将中继日志和数据文件放在不同的物理驱动器上。为此,请设置relay_log系统变量以指定中继日志的位置。

  • 如果读取二进制日志文件和中继日志文件的磁盘 I/O 活动较大,考虑增加rpl_read_size系统变量的值。该系统变量控制从日志文件中读取的最小数据量,增加该值可能会减少文件读取和 I/O 停顿,尤其是当文件数据当前未被操作系统缓存时。请注意,为从二进制日志和中继日志文件读取的每个线程分配了与此值大小相同的缓冲区,包括源上的转储线程和副本上的协调器线程。因此,设置一个较大的值可能会影响服务器的内存消耗。

  • 如果副本比源慢得多,您可能希望将不同数据库的复制责任分配给不同的副本。参见 Section 19.4.6, “将不同数据库复制到不同副本”。

  • 如果您的源使用事务,并且您不关心副本上的事务支持,请在副本上使用MyISAM或其他非事务引擎。参见 Section 19.4.4, “使用不同源和副本存储引擎进行复制”。

  • 如果您的副本不充当源,并且已经有潜在的解决方案确保在发生故障时可以启动源,则可以在副本上禁用系统变量log_replica_updates(从 MySQL 8.0.26 开始)或log_slave_updates(MySQL 8.0.26 之前)。这可以防止“愚蠢”的副本也将其执行的事件记录到自己的二进制日志中。

19.4.8 故障转移期间切换源

原文:dev.mysql.com/doc/refman/8.0/en/replication-solutions-switch.html

你可以使用CHANGE REPLICATION SOURCE TO语句(MySQL 8.0.23 之前为 CHANGE MASTER TO 选项),这是默认设置。如果您没有使用 GTIDs 进行复制,那么复制品还应该运行 --log-slave-updates=OFF(记录复制品更新是默认设置)。这样,复制品就可以在不重新启动复制品的情况下准备成为源。假设您拥有 图 19.4,“使用复制实现冗余,初始结构” 中显示的结构。

图 19.4 使用复制实现冗余,初始结构

两个网络客户端将数据库读取和写入都直接发送到单个 MySQL 源服务器。MySQL 源服务器会复制到 Replica 1、Replica 2 和 Replica 3。

在这个图中,Source 拥有源数据库,Replica* 主机是复制品,Web Client 机器正在发出数据库读取和写入。只发出读取的 Web 客户端(通常连接到复制品)没有显示,因为它们在故障发生时不需要切换到新服务器。有关读写扩展复制结构的更详细示例,请参见 19.4.5 “使用复制进行扩展”。

每个 MySQL 副本(副本 1副本 2副本 3)都是启用二进制日志记录的副本,并且使用--log-slave-updates=OFF。因为当指定--log-slave-updates=OFF时,从源接收的更新不会写入二进制日志,所以每个副本上的二进制日志最初是空的。如果由于某种原因Source不可用,您可以选择其中一个副本成为新的源。例如,如果选择副本 1,则所有Web Clients应重定向到副本 1,它会将更新写入其二进制日志。然后副本 2副本 3应从副本 1复制。

运行副本时使用--log-slave-updates=OFF的原因是为了防止副本在您导致其中一个副本成为新源时收到更新两次。如果副本 1启用了--log-slave-updates,这是默认设置,它会将从Source接收的任何更新写入自己的二进制日志。这意味着当副本 2Source更改为副本 1作为其源时,它可能会收到已经从Source接收过的副本 1的更新。

确保所有副本都已处理其中继日志中的任何语句。在每个副本上,发出STOP REPLICA IO_THREAD命令,然后检查SHOW PROCESSLIST的输出,直到看到Has read all relay log。当所有副本都满足此条件时,它们可以重新配置到新的设置。在晋升为源的副本副本 1上,发出STOP REPLICARESET MASTER命令。

在其他副本副本 2副本 3上,使用STOP REPLICACHANGE REPLICATION SOURCE TO SOURCE_HOST='Replica1'CHANGE MASTER TO MASTER_HOST='Replica1'(其中'Replica1'代表副本 1的真实主机名)。要使用CHANGE REPLICATION SOURCE TO,添加有关如何从副本 2副本 3连接到副本 1的所有信息(userpasswordport)。在此场景中发出该语句时,无需指定要从中读取的副本 1二进制日志文件的名称或位置,因为第一个二进制日志文件和位置 4 是默认值。最后,在副本 2副本 3上执行START REPLICA

一旦新的复制设置就位,你需要告诉每个 Web 客户端 将其语句发送到 Replica 1。从那时起,Web 客户端 发送到 Replica 1 的所有更新都将写入 Replica 1 的二进制日志中,其中包含自 Source 不可用以来发送到 Replica 1 的每个更新。

结果显示的服务器结构如 图 19.5,“使用复制实现冗余,在源故障后” 所示。

图 19.5 使用复制实现冗余,在源故障后

MySQL 源服务器已经故障,不再连接到复制拓扑。现在两个 Web 客户端将数据库读写都指向 Replica 1,这是新的源。Replica 1 复制到 Replica 2 和 Replica 3。

Source 再次可用时,你应该将其设置为 Replica 1 的副本。为此,在 Source 上发出与之前在 Replica 2Replica 3 上发出的相同的 CHANGE REPLICATION SOURCE TO(或 CHANGE MASTER TO)语句。然后,Source 成为 Replica 1 的副本,并接收它在离线时错过的 Web 客户端 写入数据。

要使 Source 再次成为源,请按照上述步骤操作,就好像 Replica 1 不可用,而 Source 将成为新的源一样。在此过程中,不要忘记在将 Replica 1Replica 2Replica 3 设置为 Source 的副本之前,在 Source 上运行 RESET MASTER。如果你忘记了这一步,副本可能会接收到自 Source 不可用之前的时间点起的旧写入数据。

你应该意识到副本之间没有同步,即使它们共享相同的源,因此某些副本可能比其他副本领先很多。这意味着在某些情况下,前面示例中概述的过程可能不会按预期工作。然而,在实践中,所有副本上的中继日志应该相对接近。

保持应用程序了解源位置的一种方法是为源主机设置动态 DNS 条目。使用 BIND,你可以使用 nsupdate 动态更新 DNS。

19.4.9 利用异步连接故障转移切换源和副本

原文:dev.mysql.com/doc/refman/8.0/en/replication-asynchronous-connection-failover.html

19.4.9.1 源的异步连接故障转移

19.4.9.2 副本的异步连接故障转移

从 MySQL 8.0.22 开始,您可以使用异步连接故障转移机制在现有副本到源的连接失败后自动建立与新源的异步(源到副本)复制连接。异步连接故障转移机制可用于使副本与共享数据的多个 MySQL 服务器或服务器组保持同步。潜在源服务器列表存储在副本上,在连接失败时,根据您设置的加权优先级从列表中选择新源。

从 MySQL 8.0.23 开始,异步连接故障转移机制还支持组复制拓扑结构,通过自动监视组成员变化并区分主服务器和次要服务器。当您将组成员添加到源列表并将其定义为受控组的一部分时,异步连接故障转移机制会更新源列表以使其与成员变化保持一致,随着成员加入或离开自动添加和删除组成员。仅使用在线占多数的组成员进行连接和获取状态。即使最后剩下的受控组成员离开组,也不会自动删除,以保持受控组的配置。但是,如果不再需要,可以手动删除受控组。

从 MySQL 8.0.27 开始,异步连接故障转移机制还可以使作为受控复制组一部分的副本在当前接收者(组的主节点)失败时自动重新连接到发送者。此功能与组复制一起使用,在配置为单主模式的组上工作,其中组的主节点是使用该机制的副本的复制通道。该功能旨在使一组发送者和一组接收者即使某些成员暂时不可用也保持同步。它还将一组接收者与一个或多个不属于受控组的发送者同步。不属于复制组的副本无法使用此功能。

使用异步连接故障转移机制的要求如下:

  • GTIDs 必须在源端和副本端使用 (gtid_mode=ON),并且必须在副本端启用 CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO 语句的 SOURCE_AUTO_POSITION | MASTER_AUTO_POSITION 选项,以便使用 GTID 自动定位连接到源端。

  • 在通道的源列表中,所有源服务器上必须存在相同的复制用户帐户和密码。此帐户用于连接到每个源端。您可以为不同的通道设置不同的帐户。

  • 复制用户帐户必须在 Performance Schema 表上具有 SELECT 权限,例如,通过发出 GRANT SELECT ON performance_schema.* TO '*repl_user*';

  • 由于需要在备用源端的自动重启中使用,因此不能在用于启动复制的语句中指定复制用户帐户和密码。必须在副本端使用 CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO 语句为通道设置这些信息,并记录在复制元数据存储库中。

  • 如果异步连接故障转移机制正在使用的通道位于 Group Replication 单主模式组的主服务器上,在 MySQL 8.0.27 中,默认情况下也会激活副本之间的异步连接故障转移。在这种情况下,必须在复制组中的所有次要服务器以及任何新加入的成员上设置复制通道和复制用户帐户和密码。如果使用 MySQL 的克隆功能提供新服务器,则所有这些都会自动发生。

    重要

    如果您不希望在这种情况下副本之间发生异步连接故障转移,请通过使用 group_replication_disable_member_action 函数为组禁用成员操作 mysql_start_failover_channels_if_primary 来禁用它。当禁用该功能时,您无需在次要组成员上配置复制通道,但如果主服务器下线或进入错误状态,则通道的复制将停止。

从 MySQL Shell 8.0.27 和 MySQL 8.0.27 开始,MySQL InnoDB ClusterSet 可用于为 InnoDB Cluster 部署提供灾难容忍性,方法是将主 InnoDB Cluster 与其在不同位置(如不同数据中心)的一个或多个副本链接起来。考虑使用这种解决方案来简化新的多组部署的设置,用于复制、故障切换和灾难恢复。您可以将现有的 Group Replication 部署作为 InnoDB Cluster 采用。

InnoDB ClusterSet 和 InnoDB Cluster 旨在抽象和简化设置、管理、监控、恢复和修复复制组的过程。InnoDB ClusterSet 自动管理从主集群到副本集群的复制,使用专用的 ClusterSet 复制通道。您可以使用管理员命令在主集群不正常运行时触发受控切换或紧急故障转移。在需求发生变化时,可以在初始设置后轻松地向 InnoDB ClusterSet 部署添加或删除服务器和组。有关更多信息,请参阅 MySQL InnoDB ClusterSet。

dev.mysql.com/doc/refman/8.0/en/replication-asynchronous-connection-failover-source.html

19.4.9.1 异步连接源的故障转移

要激活复制通道的异步连接故障转移,在CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(MySQL 8.0.23 之前)中设置SOURCE_CONNECTION_AUTO_FAILOVER=1。通道必须使用 GTID 自动定位(SOURCE_AUTO_POSITION = 1 | MASTER_AUTO_POSITION = 1)。

重要提示

当与源的现有连接失败时,复制品首先重试由CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO语句的SOURCE_RETRY_COUNT | MASTER_RETRY_COUNT选项指定的次数。尝试之间的间隔由SOURCE_CONNECT_RETRY | MASTER_CONNECT_RETRY选项设置。当这些尝试耗尽时,异步连接故障转移机制接管。请注意,这些选项的默认值是为了连接到单个源而设计的,使复制品在 60 天内重试相同的连接。为了确保可以及时激活异步连接故障转移机制,请将SOURCE_RETRY_COUNT | MASTER_RETRY_COUNTSOURCE_CONNECT_RETRY | MASTER_CONNECT_RETRY设置为最小值,只允许与同一源进行少量重试尝试,以防连接故障是由瞬时网络中断引起的。适当的值是SOURCE_RETRY_COUNT=3 | MASTER_RETRY_COUNT=3SOURCE_CONNECT_RETRY=10 | MASTER_CONNECT_RETRY=10,使复制品在 10 秒间隔内重试 3 次连接。

您还需要为复制通道设置源列表,以指定可用于故障转移的源。您可以使用asynchronous_connection_failover_add_sourceasynchronous_connection_failover_delete_source函数来设置和管理源列表,以添加和删除单个复制源服务器。要添加和删除受管理的服务器组,请改用asynchronous_connection_failover_add_managedasynchronous_connection_failover_delete_managed函数。

函数命名相关复制通道,并指定要添加到或从通道源列表中删除的 MySQL 实例的主机名、端口号、网络命名空间和加权优先级(1-100,100 为最高优先级)。对于受管组,您还需要指定受管服务的类型(目前仅有 Group Replication 可用),以及受管组的标识符(对于 Group Replication,这是group_replication_group_name系统变量的值)。当您添加受管组时,只需添加一个组成员,副本会自动添加当前组成员的其余部分。当您删除受管组时,将一起删除整个组。

在 MySQL 8.0.22 中,异步连接故障转移机制在副本与源的连接失败后被激活,并发出START REPLICA语句尝试连接到新源。在此版本中,如果由于源停止或由于网络故障导致复制接收线程停止,连接将转移。在其他情况下,例如当复制线程被STOP REPLICA语句停止时,连接不会转移。

从 MySQL 8.0.23 开始,异步连接故障转移机制还会在源列表中另一个可用服务器具有更高优先级(权重)设置时转移连接。此功能确保副本始终连接到最合适的源服务器,并适用于受管组和单个(非受管)服务器。对于受管组,源的权重根据其是主服务器还是从服务器而分配。因此,假设您设置受管组以给予主服务器更高的权重,从服务器更低的权重,当主服务器更改时,新主服务器被分配更高的权重,因此副本将连接到新主服务器。如果当前连接的受管源服务器离开受管组,或者不再是受管组中的大多数,异步连接故障转移机制还会更改连接。

在连接故障时,通道的源列表中列出的备用源中具有最高优先级(权重)设置的源将被选择用于第一次连接尝试。 复制品首先检查它是否可以连接到源服务器,或者在管理组的情况下,源服务器在组中是否具有ONLINE状态(而不是RECOVERING或不可用)。 如果最高加权源不可用,则复制品将按权重降序尝试所有列出的源,然后再从最高加权源开始。 如果多个源具有相同的权重,则复制品会随机排序它们。 如果复制品需要重新开始遍历列表,则它会包括并重试原始连接故障发生的源。

源列表存储在mysql.replication_asynchronous_connection_failovermysql.replication_asynchronous_connection_failover_managed表中,并可以在性能模式replication_asynchronous_connection_failoverreplication_asynchronous_connection_failover_managed表中查看。 复制品使用监视线程跟踪管理组的成员资格并更新源列表(thread/sql/replica_monitor)。 CHANGE REPLICATION SOURCE TO | CHANGE MASTER TO语句的SOURCE_CONNECTION_AUTO_FAILOVER选项设置和源列表在远程克隆操作期间传输到复制品的克隆中。

原文:dev.mysql.com/doc/refman/8.0/en/replication-asynchronous-connection-failover-replica.html

19.4.9.2 副本的异步连接故障转移

在 MySQL 8.0.27 及更高版本中,当你在复制通道上设置SOURCE_CONNECTION_AUTO_FAILOVER=1时,副本的异步连接故障转移将自动激活于 Group Replication 主服务器上。该功能旨在设计一个发送者组和一个接收者组,即使一些成员暂时不可用,它们也能保持同步。当该功能处于活动状态并正确配置时,如果正在复制的主服务器离线或进入错误状态,新的主服务器在选举时将在同一通道上开始复制。新的主服务器使用通道的源列表来选择具有最高优先级(权重)设置的源,这可能与原始源不同。

要配置此功能,必须在复制组中的所有成员服务器以及任何新加入的成员上设置复制通道和通道的复制用户帐户和密码。确保SOURCE_RETRY_COUNTSOURCE_CONNECT_RETRY设置为允许少量重试尝试的最小数字,例如 3 和 10。您可以使用CHANGE REPLICATION SOURCE TO设置复制通道,或者如果新服务器是使用 MySQL 的克隆功能进行配置的,则所有这些都会自动发生。当新成员加入时,主服务器会向组成员广播通道的SOURCE_CONNECTION_AUTO_FAILOVER设置。如果您稍后在主服务器上禁用通道的SOURCE_CONNECTION_AUTO_FAILOVER,这也会广播到辅助服务器,并且它们会更改通道的状态以匹配。

注意

在单主模式下参与组的服务器必须使用--skip-replica-start=ON启动。否则,服务器无法作为辅助服务器加入组。

副本的异步连接故障转移是通过 Group Replication 成员操作mysql_start_failover_channels_if_primary来激活和停用的,默认情况下启用。您可以通过在主服务器上禁用该成员操作来为整个组禁用它,使用group_replication_disable_member_action函数,如下例所示:

mysql> SELECT group_replication_disable_member_action("mysql_start_failover_channels_if_primary", "AFTER_PRIMARY_ELECTION");

该功能只能在主服务器上更改,并且必须为整个组启用或禁用,因此不能让一些成员提供故障转移,而其他成员不提供。当禁用mysql_start_failover_channels_if_primary成员操作时,次要成员不需要配置频道,但如果主服务器下线或进入错误状态,则该频道的复制将停止。请注意,如果有多个具有SOURCE_CONNECTION_AUTO_FAILOVER=1的频道,则成员操作将覆盖所有频道,因此它们不能通过该方法单独启用或禁用。在主服务器上将SOURCE_CONNECTION_AUTO_FAILOVER=0设置为禁用单个频道。

当频道具有SOURCE_CONNECTION_AUTO_FAILOVER=1时,源列表会在所有组成员加入时广播,并在更改时也会广播。无论这些源是否是一个受管理的组,其成员资格是否会自动更新,或者是使用asynchronous_connection_failover_add_source()asynchronous_connection_failover_delete_source()asynchronous_connection_failover_add_managed(),或asynchronous_connection_failover_delete_managed()手动添加或更改。所有组成员都会收到当前源列表,记录在mysql.replication_asynchronous_connection_failovermysql.replication_asynchronous_connection_failover_managed表中。因为源不必在受管理的组中,所以您可以设置该功能以将一组接收器与一个或多个备用独立发件人同步,甚至是单个发件人。不属于复制组的独立副本无法使用此功能。

19.4.10 半同步复制

原文:dev.mysql.com/doc/refman/8.0/en/replication-semisync.html

19.4.10.1 安装半同步复制

19.4.10.2 配置半同步复制

19.4.10.3 半同步复制监视

除了内置的异步复制外,MySQL 8.0 还支持由插件实现的半同步复制接口。本节讨论了什么是半同步复制以及它是如何工作的。接下来的章节将涵盖半同步复制的管理接口以及如何安装、配置和监视它。

MySQL 默认情况下是异步复制。源将事件写入其二进制日志,副本在准备好时请求这些事件。源不知道副本是否何时检索和处理事务,并且不能保证任何事件是否会到达任何副本。使用异步复制时,如果源崩溃,它已经提交的事务可能尚未传输至任何副本。在这种情况下,从源切换到副本可能导致切换到相对于源缺少事务的服务器。

使用完全同步复制时,当源提交事务时,所有副本在源返回执行事务的会话之前也已经提交了该事务。完全同步复制意味着可以随时从源切换到任何副本。完全同步复制的缺点是可能会有很多延迟来完成一个事务。

半同步复制介于异步和完全同步复制之间。源会等待至少一个副本接收并记录事件(所需副本数量可配置),然后提交事务。源不会等待所有副本确认接收,并且只需要副本的确认,而不需要事件在副本端完全执行和提交。因此,半同步复制保证了如果源崩溃,它已经提交的所有事务都已传输至至少一个副本。

与异步复制相比,半同步复制提供了改进的数据完整性,因为当提交成功返回时,可以知道数据至少存在于两个地方。在半同步源接收到所需数量的副本的确认之前,事务会被暂停并且不会被提交。

与完全同步复制相比,半同步复制更快,因为它可以配置以平衡数据完整性要求(确认接收事务的副本数量)与提交速度之间的要求,由于需要等待副本,提交速度较慢。

重要提示

使用半同步复制,如果源崩溃并进行故障转移到副本,则失败的源不应重新用作复制源,并应丢弃。它可能有一些事务尚未被任何副本确认,因此在故障转移之前未提交。

如果您的目标是实现一个容错的复制拓扑结构,其中所有服务器以相同顺序接收相同的事务,并且崩溃的服务器可以重新加入组并自动更新,您可以使用组复制来实现这一目标。有关详细信息,请参见第二十章,组复制

与异步复制相比,半同步复制的性能影响是为了增加数据完整性而进行的权衡。减速的量至少是将提交发送到副本并等待副本确认接收的 TCP/IP 往返时间。这意味着半同步复制最适合在快速网络上通信的近距离服务器,并且对于在慢速网络上通信的远程服务器最不利。半同步复制还通过限制二进制日志事件从源到副本发送的速度来对繁忙会话进行速率限制。当一个用户太忙时,这会减慢速度,在某些部署情况下可能会很有用。

源和其副本之间的半同步复制操作如下:

  • 当副本连接到源时,副本指示其是否支持半同步。

  • 如果在源端启用了半同步复制并且至少有一个半同步副本,则在源上执行事务提交的线程将被阻塞,并等待至少一个半同步副本确认已接收到该事务的所有事件,或者直到超时发生。

  • 副本仅在将事件写入其中继日志并刷新到磁盘后才确认接收到事务的事件。

  • 如果超时发生而没有任何副本确认事务,则源将恢复为异步复制。当至少一个半同步副本赶上时,源将恢复为半同步复制。

  • 必须在源端和副本端启用半同步复制。如果在源端禁用了半同步复制,或者在源端启用了半同步复制但没有在任何副本上启用,则源将使用异步复制。

当源正在阻塞(等待来自副本的确认)时,它不会返回到执行事务的会话。当阻塞结束时,源会返回到会话,然后可以继续执行其他语句。此时,在源端事务已经提交,并且至少一个副本已经确认接收到其事件。源在返回到会话之前必须接收每个事务的副本确认数量是可配置的,默认为一个确认(参见 Section 19.4.10.2, “Configuring Semisynchronous Replication”)。

阻塞也会发生在写入二进制日志的回滚之后,这种情况发生在回滚修改非事务表的事务时。即使对于事务表来说回滚的事务没有影响,但对于非事务表的修改无法回滚,必须发送到副本中,因此回滚的事务会被记录。

对于不在事务上下文中发生的语句(也就是说,没有使用START TRANSACTIONSET autocommit = 0启动事务时),自动提交被启用,每个语句都会隐式提交。在半同步复制中,源会为每个这样的语句阻塞,就像为显式事务提交一样。

默认情况下,源在将二进制日志同步到磁盘后等待副本确认事务接收,但在将事务提交到存储引擎之前。作为替代方案,您可以配置源,使其在将事务提交到存储引擎后等待副本确认,使用rpl_semi_sync_source_wait_pointrpl_semi_sync_master_wait_point系统变量。此设置会影响复制特性和客户端在源端可以看到的数据。有关更多信息,请参见 Section 19.4.10.2, “Configuring Semisynchronous Replication”。

从 MySQL 8.0.23 开始,您可以通过启用系统变量replication_sender_observe_commit_onlyreplication_optimize_for_static_plugin_config来提高半同步复制的性能,前者限制回调,后者添加共享锁并避免不必要的锁获取。这些设置在副本数量增加时非常有帮助,因为锁争用可能会降低性能。半同步复制源服务器还可以通过启用这些系统变量获得性能优势,因为它们使用与副本相同的锁定机制。

原文:dev.mysql.com/doc/refman/8.0/en/replication-semisync-installation.html

19.4.10.1 安装半同步复制

半同步复制是使用插件实现的,这些插件必须安装在源服务器和副本上,以使半同步复制在实例上可用。 源和副本有不同的插件。 安装插件后,您可以通过与之关联的系统变量来控制它。 仅当关联的插件已安装时,这些系统变量才可用。

本节描述了如何安装半同步复制插件。 有关安装插件的一般信息,请参见 Section 7.6.1, “安装和卸载插件”。

要使用半同步复制,必须满足以下要求:

  • 安装插件的能力需要支持动态加载的 MySQL 服务器。 要验证这一点,请检查have_dynamic_loading 系统变量的值是否为 YES。 二进制发行版应支持动态加载。

  • 复制必须已经正常工作,请参见 Section 19.1, “配置复制”。

  • 不得配置多个复制通道。 半同步复制仅与默认复制通道兼容。 请参见 Section 19.2.2, “复制通道”。

从 MySQL 8.0.26 开始,提供了实现半同步复制的插件的新版本,一个用于源服务器,一个用于副本。 新插件在系统变量和状态变量中将“主”和“从”替换为“源”和“副本”,您可以安装这些版本而不是旧版本。 不能在实例上同时安装相关插件的新旧版本。 如果使用新版本的插件,则新的系统变量和状态变量可用,但旧的不可用。 如果使用旧版本的插件,则旧的系统变量和状态变量可用,但新的不可用。

插件库文件的文件名后缀因平台而异(例如,Unix 和类 Unix 系统使用.so,Windows 使用.dll)。 插件和库文件的名称如下:

  • 源服务器,旧术语:rpl_semi_sync_master 插件(semisync_master.sosemisync_master.dll 库)

  • 源服务器,新术语(从 MySQL 8.0.26 开始):rpl_semi_sync_source 插件(semisync_source.sosemisync_source.dll 库)

  • 复制品,旧术语:rpl_semi_sync_slave 插件(semisync_slave.sosemisync_slave.dll 库)

  • 复制,新术语(自 MySQL 8.0.26 起):rpl_semi_sync_replica插件(semisync_replica.sosemisync_replica.dll库)

要被源服务器或复制服务器使用,适当的插件库文件必须位于 MySQL 插件目录中(由plugin_dir系统变量命名的目录)。必要时,通过在服务器启动时设置plugin_dir的值来配置插件目录位置。源插件库文件必须存在于源服务器的插件目录中。复制插件库文件必须存在于每个复制服务器的插件目录中。

要设置半同步复制,请使用以下说明。这里提到的INSTALL PLUGINSET GLOBALSTOP REPLICASTART REPLICA语句需要REPLICATION_SLAVE_ADMIN权限(或已弃用的SUPER权限)。

加载插件,请在源端和每个要进行半同步的复制端上使用INSTALL PLUGIN语句,根据需要调整您平台的.so后缀。

在源端:

INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

Or from MySQL 8.0.26:
INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';

在每个复制端:

INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

Or from MySQL 8.0.26:
INSTALL PLUGIN rpl_semi_sync_replica SONAME 'semisync_replica.so';

如果在 Linux 上尝试安装插件时出现类似于此处所示的错误,则必须安装libimf

mysql> INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';
ERROR 1126 (HY000): Can't open shared library
'/usr/local/mysql/lib/plugin/semisync_source.so'
(errno: 22 libimf.so: cannot open shared object file:
No such file or directory)

您可以从dev.mysql.com/downloads/os-linux.html获取libimf

要验证插件安装,请检查信息模式PLUGINS表,或使用SHOW PLUGINS语句(参见第 7.6.2 节,“获取服务器插件信息”)。例如:

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME          | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_source | ACTIVE        |
+----------------------+---------------+

如果插件初始化失败,请检查服务器错误日志以获取诊断消息。

安装半同步复制插件后,默认情况下是禁用的。必须在源端和复制端都启用插件才能启用半同步复制。如果只有一侧启用,则复制是异步的。要启用插件,请在运行时使用SET GLOBAL设置适当的系统变量,或在命令行或选项文件中在服务器启动时设置。例如:

On the source:
SET GLOBAL rpl_semi_sync_master_enabled = 1;

Or from MySQL 8.0.26 with the rpl_semi_sync_source plugin:
SET GLOBAL rpl_semi_sync_source_enabled = 1;
On each replica:
SET GLOBAL rpl_semi_sync_slave_enabled = 1;

Or from MySQL 8.0.26 with the rpl_semi_sync_replica plugin:
SET GLOBAL rpl_semi_sync_replica_enabled = 1;

如果您在运行时在副本上启用半同步复制,您还必须启动复制 I/O(接收器)线程(如果已经运行,则首先停止它),以使副本连接到源并注册为半同步副本:

STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

Or from MySQL 8.0.22:
STOP REPLICA IO_THREAD;
START REPLICA IO_THREAD;

如果复制 I/O(接收器)线程已经在运行,而您没有重新启动它,副本将继续使用异步复制。

在选项文件中列出的设置在每次服务器启动时生效。例如,您可以在源服务器和副本服务器的my.cnf文件中设置变量如下:

 On the source: 

[mysqld]
rpl_semi_sync_master_enabled=1

Or from MySQL 8.0.26 with the rpl_semi_sync_source plugin:
rpl_semi_sync_source_enabled=1
 On each replica: 

[mysqld]
rpl_semi_sync_slave_enabled=1

Or from MySQL 8.0.26 with the rpl_semi_sync_source plugin:
rpl_semi_sync_replica_enabled=1

您可以使用安装插件时提供的系统变量来配置半同步复制插件的行为。有关关键系统变量的信息,请参见 Section 19.4.10.2, “Configuring Semisynchronous Replication”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-semisync-interface.html

19.4.10.2 配置半同步复制

当您为半同步复制安装源和复制品插件时(参见 Section 19.4.10.1,“安装半同步复制”),系统变量变得可用以控制插件行为。

要检查半同步复制状态变量的当前值,请使用 SHOW VARIABLES

mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';

从 MySQL 8.0.26 开始,提供了源和复制品插件的新版本,这些版本在系统变量和状态变量中将“master”和“slave”替换为“source”和“replica”。如果安装新的 rpl_semi_sync_sourcerpl_semi_sync_replica 插件,则新的系统变量和状态变量可用,但旧的则不可用。如果安装旧的 rpl_semi_sync_masterrpl_semi_sync_slave 插件,则旧的系统变量和状态变量可用,但新的则不可用。在一个实例中不能同时安装相关插件的新旧版本。

所有 rpl_semi_sync_*xxx* 系统变量在 Section 19.1.6.2,“复制源选项和变量”和 Section 19.1.6.3,“复制品服务器选项和变量”中有描述。一些关键的系统变量包括:

rpl_semi_sync_source_enabledrpl_semi_sync_master_enabled

控制源服务器上是否启用半同步复制。要启用或禁用插件,请将此变量分别设置为 1 或 0。默认值为 0(关闭)。

rpl_semi_sync_replica_enabledrpl_semi_sync_slave_enabled

控制复制品上是否启用半同步复制。

rpl_semi_sync_source_timeoutrpl_semi_sync_master_timeout

以毫秒为单位的值,控制源在提交时等待来自复制品的确认的超时时间,超时后将回滚到异步复制。默认值为 10000(10 秒)。

rpl_semi_sync_source_wait_for_replica_countrpl_semi_sync_master_wait_for_slave_count

控制源在返回会话之前必须接收的每个事务的副本确认数。默认值为 1,意味着源只等待一个副本确认接收事务事件。

rpl_semi_sync_source_wait_pointrpl_semi_sync_master_wait_point 系统变量控制半同步源服务器在返回事务提交状态给客户端之前等待副本确认事务接收的时间点。这些值是允许的:

  • AFTER_SYNC(默认):源将每个事务写入其二进制日志和副本,并将二进制日志同步到磁盘。源在同步后等待副本确认事务接收。在接收到确认后,源将事务提交到存储引擎并返回结果给客户端,然后客户端可以继续。

  • AFTER_COMMIT:源将每个事务写入其二进制日志和副本,同步二进制日志,并提交事务到存储引擎。源在提交后等待副本确认事务接收。在接收到确认后,源返回结果给客户端,然后客户端可以继续。

这些设置的复制特性如下所示:

  • 使用 AFTER_SYNC,所有客户端在同一时间看到已提交的事务,即在副本确认并在源上提交到存储引擎之后。因此,所有客户端在源上看到相同的数据。

    在源故障的情况下,所有在源上提交的事务已被复制到副本(保存到其中继日志)。源的意外退出并故障转移到副本是无损的,因为副本是最新的。如上所述,在故障转移后不应再重用源。

  • 使用 AFTER_COMMIT,发起事务的客户端只有在服务器提交到存储引擎并接收到副本确认后才会收到返回状态。在提交后和副本确认前,其他客户端可能在提交客户端之前看到已提交的事务。

    如果出现问题导致副本未处理事务,那么在源意外退出并故障转移到副本的情况下,这些客户端可能会看到相对于在源上看到的数据有所丢失。

从 MySQL 8.0.23 开始,您可以通过启用系统变量replication_sender_observe_commit_onlyreplication_optimize_for_static_plugin_config来提高半同步复制的性能,前者限制回调,后者添加共享锁并避免不必要的锁获取。这些设置在副本数量增加时非常有帮助,因为锁争用可能会降低性能。半同步复制源服务器还可以通过启用这些系统变量获得性能优势,因为它们使用与副本相同的锁定机制。

原文:dev.mysql.com/doc/refman/8.0/en/replication-semisync-monitoring.html

19.4.10.3 半同步复制监控

半同步复制的插件公开了许多状态变量,使您能够监视其操作。要检查状态变量的当前值,请使用 SHOW STATUS

mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';

从 MySQL 8.0.26 开始,提供了新版本的源和副本插件,这些插件在系统变量和状态变量中用“source”和“replica”替换了“master”和“slave”这些术语。如果安装了新的 rpl_semi_sync_sourcerpl_semi_sync_replica 插件,则新的系统变量和状态变量可用,而旧的则不可用。如果安装了旧的 rpl_semi_sync_masterrpl_semi_sync_slave 插件,则旧的系统变量和状态变量可用,而新的则不可用。在一个实例中不能同时安装相关插件的新旧版本。

所有 Rpl_semi_sync_*xxx* 状态变量在 第 7.1.10 节,“服务器状态变量” 中有描述。一些示例包括:

  • Rpl_semi_sync_source_clientsRpl_semi_sync_master_clients

    连接到源服务器的半同步副本数量。

  • Rpl_semi_sync_source_statusRpl_semi_sync_master_status

    半同步复制当前是否在源服务器上运行。如果插件已启用且提交确认尚未发生,则值为 1。如果插件未启用或源由于提交确认超时而回退到异步复制,则值为 0。

  • Rpl_semi_sync_source_no_txRpl_semi_sync_master_no_tx

    未被副本成功确认的提交数量。

  • Rpl_semi_sync_source_yes_txRpl_semi_sync_master_yes_tx

    被副本成功确认的提交数量。

  • Rpl_semi_sync_replica_statusRpl_semi_sync_slave_status

    半同步复制当前是否在副本上运行。如果插件已启用且复制 I/O(接收器)线程正在运行,则为 1,否则为 0。

当源端由于提交阻塞超时或副本追赶而在异步或半同步复制之间切换时,它会适当地设置Rpl_semi_sync_source_statusRpl_semi_sync_master_status状态变量的值。源端从半同步自动回退到异步复制意味着即使半同步复制实际上当前不可用,rpl_semi_sync_source_enabledrpl_semi_sync_master_enabled系统变量在源端可能仍然具有值 1。您可以监视Rpl_semi_sync_source_statusRpl_semi_sync_master_status状态变量来确定源端当前是在使用异步还是半同步复制。

19.4.11 延迟复制

原文:dev.mysql.com/doc/refman/8.0/en/replication-delayed.html

MySQL 支持延迟复制,使得副本服务器故意比源服务器晚至少指定的时间执行事务。本节描述了如何在副本上配置复制延迟以及如何监视复制延迟。

在 MySQL 8.0 中,延迟复制的方法取决于两个时间戳,immediate_commit_timestamporiginal_commit_timestamp(参见 Replication Delay Timestamps)。如果复制拓扑中的所有服务器都运行 MySQL 8.0 或更高版本,则使用这些时间戳来测量延迟复制。如果即时源或副本中有任何一个不使用这些时间戳,则使用 MySQL 5.7 中的延迟复制实现(参见 Delayed Replication)。本节描述了所有使用这些时间戳的服务器之间的延迟复制。

默认复制延迟为 0 秒。使用CHANGE REPLICATION SOURCE TO SOURCE_DELAY=*N*语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO MASTER_DELAY=*N*语句(MySQL 8.0.23 之前)将延迟设置为N秒。从源接收的事务直到比其在即时源上提交的时间晚至少N秒才执行。延迟是按事务发生的(而不是像以前的 MySQL 版本中那样按事件发生),实际延迟仅对gtid_log_eventanonymous_gtid_log_event施加。事务中的其他事件总是在这些事件之后立即执行,而不会对它们施加任何等待时间。

注意

START REPLICASTOP REPLICA立即生效并忽略任何延迟。RESET REPLICA将延迟重置为 0。

replication_applier_configuration性能模式表包含DESIRED_DELAY列,显示使用SOURCE_DELAY | MASTER_DELAY选项配置的延迟。replication_applier_status性能模式表包含REMAINING_DELAY列,显示剩余的延迟秒数。

延迟复制可用于几个目的:

  • 用于防止源上用户错误。通过延迟,您可以将延迟副本回滚到错误发生之前的时间。

  • 为了测试系统在出现延迟时的行为。例如,在一个应用程序中,延迟可能是由于副本上的大量负载而引起的。然而,很难生成这种负载水平。延迟复制可以模拟延迟,而无需模拟负载。它还可以用于调试与滞后副本相关的条件。

  • 为了查看数据库在过去的样子,而无需重新加载备份。例如,通过配置一个延迟一周的副本,如果您需要查看数据库在最近几天开发之前的样子,可以检查延迟副本。

复制延迟时间戳

MySQL 8.0 提供了一种新的方法来测量复制拓扑中的延迟(也称为复制滞后),该方法依赖于写入二进制日志的每个事务(而不是每个事件)关联的 GTID 的以下时间戳。

  • original_commit_timestamp: 事务被写入(提交)到原始来源二进制日志时距离时代的微秒数。

  • immediate_commit_timestamp: 事务被写入(提交)到直接来源二进制日志时距离时代的微秒数。

mysqlbinlog的输出以两种格式显示这些时间戳,即从时代开始的微秒数和基于用户定义时区的TIMESTAMP格式,以便更易读。例如:

#170404 10:48:05 server id 1  end_log_pos 233 CRC32 0x016ce647     GTID    last_committed=0
\ sequence_number=1    original_committed_timestamp=1491299285661130    immediate_commit_timestamp=1491299285843771
# original_commit_timestamp=1491299285661130 (2017-04-04 10:48:05.661130 WEST)
# immediate_commit_timestamp=1491299285843771 (2017-04-04 10:48:05.843771 WEST)
 /*!80001 SET @@SESSION.original_commit_timestamp=1491299285661130*//*!*/;
   SET @@SESSION.GTID_NEXT= 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1'/*!*/;
# at 233

通常情况下,事务应用到的所有副本上的original_commit_timestamp始终相同。在源-副本复制中,事务在(原始)源二进制日志中的original_commit_timestamp始终与其immediate_commit_timestamp相同。在副本的中继日志中,事务的original_commit_timestampimmediate_commit_timestamp与源二进制日志中的相同;而在其自己的二进制日志中,事务的immediate_commit_timestamp对应于副本提交事务的时间。

在群组复制设置中,当原始来源是群组的成员时,original_commit_timestamp在事务准备提交时生成。换句话说,当它在原始来源上执行完毕并且其写入集准备发送到群组的所有成员进行认证时。当原始来源是群组外的服务器时,original_commit_timestamp被保留。特定事务的相同original_commit_timestamp被复制到群组中的所有服务器,以及从成员复制的群组外的任何副本。从 MySQL 8.0.26 开始,事务的每个接收者还使用immediate_commit_timestamp在其二进制日志中存储本地提交时间。

视图更改事件,这是组复制独有的特殊情况。包含这些事件的交易由每个组成员生成,但共享相同的 GTID(因此,它们不是首先在源中执行,然后被复制到组中,而是组的所有成员执行并应用相同的交易)。在 MySQL 8.0.26 之前,这些交易的original_commit_timestamp设置为零,并且在可查看的输出中以这种方式显示。从 MySQL 8.0.26 开始,为了提高可观察性,组成员为与视图更改事件相关的交易设置本地时间戳值。

监视复制延迟

在以前的 MySQL 版本中监视复制延迟(滞后)最常见的方法之一是依赖于SHOW REPLICA STATUS输出中的Seconds_Behind_Master字段。然而,在使用比传统源-副本设置更复杂的复制拓扑时,如组复制时,此度量标准并不适用。在 MySQL 8 中添加immediate_commit_timestamporiginal_commit_timestamp提供了关于复制延迟的更精细信息。在支持这些时间戳的拓扑中监视复制延迟的推荐方法是使用以下性能模式表。

  • replication_connection_status:与源的连接的当前状态,提供连接线程排队到中继日志的最后一个和当前交易的信息。

  • replication_applier_status_by_coordinator:仅在使用多线程副本时显示协调器线程的当前状态,提供协调器线程缓冲到工作线程队列的最后一个交易的信息,以及它当前正在缓冲的交易。

  • replication_applier_status_by_worker:应用来自源的交易的线程(们)的当前状态,提供由复制 SQL 线程应用的交易的信息,或者在使用多线程副本时,每个工作线程应用的交易的信息。

使用这些表,您可以监视对应线程处理的最后一个交易和该线程当前正在处理的交易的信息。这些信息包括:

  • 一个交易的 GTID

  • 从副本的中继日志中检索的交易的original_commit_timestampimmediate_commit_timestamp

  • 线程开始处理交易的时间

  • 对于最后处理的交易,线程完成处理的时间

除了性能模式表之外,SHOW REPLICA STATUS的输出还有三个字段显示:

  • SQL_Delay: 一个非负整数,表示使用CHANGE REPLICATION SOURCE TO SOURCE_DELAY=*N*(从 MySQL 8.0.23 开始)或CHANGE MASTER TO MASTER_DELAY=N(在 MySQL 8.0.23 之前)配置的复制延迟,以秒为单位。

  • SQL_Remaining_Delay: 当Replica_SQL_Running_StateWaiting until MASTER_DELAY seconds after master executed event时,此字段包含一个整数,表示延迟剩余的秒数。在其他时候,此字段为NULL

  • Replica_SQL_Running_State: 表示 SQL 线程状态的字符串(类似于Replica_IO_State)。该值与由SHOW PROCESSLIST显示的 SQL 线程的State值相同。

当复制 SQL 线程在执行事件之前等待延迟时间时,SHOW PROCESSLIST将其State值显示为Waiting until MASTER_DELAY seconds after master executed event

19.5 复制笔记和技巧

原文:dev.mysql.com/doc/refman/8.0/en/replication-notes.html

19.5.1 复制功能和问题

19.5.2 MySQL 版本之间的复制兼容性

19.5.3 升级复制拓扑结构

19.5.4 复制故障排除

19.5.5 如何报告复制错误或问题

19.5.1 复制功能和问题

原文:dev.mysql.com/doc/refman/8.0/en/replication-features.html

19.5.1.1 复制和 AUTO_INCREMENT

19.5.1.2 复制和 BLACKHOLE 表

19.5.1.3 复制和字符集

19.5.1.4 复制和 CHECKSUM TABLE

19.5.1.5 创建服务器,修改服务器和删除服务器的复制

19.5.1.6 CREATE ... IF NOT EXISTS 语句的复制

19.5.1.7 复制 CREATE TABLE ... SELECT 语句

19.5.1.8 CURRENT_USER()的复制

19.5.1.9 源和副本上的不同表定义的复制

19.5.1.10 复制和 DIRECTORY 表选项

19.5.1.11 复制 DROP ... IF EXISTS 语句

19.5.1.12 复制和浮点值

19.5.1.13 复制和 FLUSH

19.5.1.14 复制和系统函数

19.5.1.15 复制和分数秒支持

19.5.1.16 调用功能的复制

19.5.1.17 复制 JSON 文档

19.5.1.18 复制和 LIMIT

19.5.1.19 复制和 LOAD DATA

19.5.1.20 复制和 max_allowed_packet

19.5.1.21 复制和 MEMORY 表

19.5.1.22 复制 mysql 系统模式

19.5.1.23 复制和查询优化器

19.5.1.24 复制和分区

19.5.1.25 复制和 REPAIR TABLE

19.5.1.26 复制和保留字

19.5.1.27 复制和行搜索

19.5.1.28 复制和源或副本的关闭

19.5.1.29 复制过程中的副本错误

19.5.1.30 复制和服务器 SQL 模式

19.5.1.31 复制和临时表

19.5.1.32 复制重试和超时

19.5.1.33 复制和时区

19.5.1.34 复制和事务不一致性

19.5.1.35 复制和事务

19.5.1.36 复制和触发器

19.5.1.37 复制和 TRUNCATE TABLE

19.5.1.38 复制和用户名长度

19.5.1.39 复制和变量

19.5.1.40 复制和视图

以下各节提供了关于 MySQL 复制中支持和不支持的内容,以及在复制某些语句时可能发生的特定问题和情况的信息。

基于语句的复制取决于源和副本之间在 SQL 级别的兼容性。换句话说,成功的基于语句的复制要求源服务器和副本服务器都支持使用的任何 SQL 特性。如果您在源服务器上使用了仅在当前版本的 MySQL 中可用的功能,则无法复制到使用较早版本的 MySQL 的副本。这种不兼容性也可能发生在版本系列内以及版本之间。

如果您计划在 MySQL 8.0 和之前的 MySQL 版本系列之间使用基于语句的复制,建议查阅MySQL 参考手册对应早期版本系列的版本,以获取有关该系列复制特性的信息。

使用 MySQL 的基于语句的复制时,可能会出现复制存储过程或触发器的问题。您可以通过改用 MySQL 的基于行的复制来避免这些问题。有关问题的详细列表,请参阅第 27.7 节,“存储程序二进制日志记录”。有关基于行的日志记录和基于行的复制的更多信息,请参阅第 7.4.4.1 节,“二进制日志格式”,以及第 19.2.1 节,“复制格式”。

对于与InnoDB复制相关的其他信息,请参阅第 17.19 节,“InnoDB 和 MySQL 复制”。有关与 NDB Cluster 复制相关的信息,请参阅第 25.7 节,“NDB Cluster 复制”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-auto-increment.html

19.5.1.1 复制和 AUTO_INCREMENT

基于语句的复制AUTO_INCREMENTLAST_INSERT_ID()TIMESTAMP值的执行受以下异常情况的影响:

  • 调用触发器或导致AUTO_INCREMENT列更新的函数的语句在基于语句的复制中无法正确复制。这些语句被标记为不安全。(Bug #45677)

  • 对于具有包含AUTO_INCREMENT列但不是这个复合主键的第一列的复合主键的表进行INSERT不适用于基于语句的日志记录或复制。这些语句被标记为不安全。(Bug #11754117, Bug #45670)

    这个问题不影响使用InnoDB存储引擎的表,因为InnoDB表的AUTO_INCREMENT列需要至少一个键,其中AUTO_INCREMENT列是唯一的或最左边的列。

  • 向具有ALTER TABLE的表添加AUTO_INCREMENT列可能不会在副本和源上产生相同的行顺序。这是因为行编号的顺序取决于用于表的特定存储引擎以及插入行的顺序。如果在源和副本上具有相同的顺序很重要,则在分配AUTO_INCREMENT编号之前必须对行进行排序。假设您想向具有列col1col2的表t1添加AUTO_INCREMENT列,以下语句将生成一个与t1相同但具有AUTO_INCREMENT列的新表t2

    CREATE TABLE t2 LIKE t1;
    ALTER TABLE t2 ADD id INT AUTO_INCREMENT PRIMARY KEY;
    INSERT INTO t2 SELECT * FROM t1 ORDER BY col1, col2;
    

    重要提示

    为了保证源和副本的顺序相同,ORDER BY子句必须命名t1所有列。

    刚刚给出的指令受到CREATE TABLE ... LIKE的限制:外键定义被忽略,DATA DIRECTORYINDEX DIRECTORY表选项也被忽略。如果表定义包含任何这些特征,使用与创建t1相同的CREATE TABLE语句创建t2,但增加AUTO_INCREMENT列。

    无论用于创建和填充具有AUTO_INCREMENT列的副本的方法如何,最后一步是删除原始表,然后重命名副本:

    DROP t1;
    ALTER TABLE t2 RENAME t1;
    

    另请参阅 Section B.3.6.1, “Problems with ALTER TABLE”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-blackhole.html

19.5.1.2 复制和 BLACKHOLE 表

BLACKHOLE存储引擎接受数据但会丢弃它,不会存储。在执行二进制日志记录时,所有对这些表的插入操作都会被记录,无论使用的日志格式是什么。根据使用的基于语句或基于行的日志记录方式,更新和删除操作会有不同的处理方式。在基于语句的日志记录格式下,所有影响BLACKHOLE表的语句都会被记录,但它们的效果会被忽略。在使用基于行的日志记录时,对这些表的更新和删除操作会被简单地跳过,不会被写入二进制日志。每当发生这种情况时,都会记录一个警告。

出于这个原因,我们建议当您使用BLACKHOLE存储引擎复制表时,将binlog_format服务器变量设置为STATEMENT,而不是ROWMIXED

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-charset.html

19.5.1.3 复制和字符集

在使用不同字符集的 MySQL 服务器之间进行复制时,以下内容适用:

  • 如果源数据库具有与全局character_set_server值不同的字符集,则应设计CREATE TABLE语句,使其不会隐式依赖于数据库默认字符集。一个好的解决方法是在CREATE TABLE语句中明确指定字符集和校对规则。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-checksum-table.html

19.5.1.4 复制和 CHECKSUM TABLE

CHECKSUM TABLE 返回一个逐行计算的校验和,使用依赖于表行存储格式的方法。存储格式在 MySQL 版本之间不保证保持不变,因此在升级后校验和值可能会改变。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-create-alter-drop-server.html

19.5.1.5 复制CREATE SERVERALTER SERVERDROP SERVER

CREATE SERVERALTER SERVERDROP SERVER语句不管使用何种二进制日志格式,都不会被写入二进制日志中。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-create-if-not-exists.html

19.5.1.6 复制CREATE ... IF NOT EXISTS语句

当复制各种CREATE ... IF NOT EXISTS语句时,MySQL 会应用以下规则:

  • 每个CREATE DATABASE IF NOT EXISTS语句都会被复制,无论源数据库是否已存在。

  • 类似地,每个不带SELECTCREATE TABLE IF NOT EXISTS语句都会被复制,无论源端表是否已存在。这包括CREATE TABLE IF NOT EXISTS ... LIKECREATE TABLE IF NOT EXISTS ... SELECT的复制遵循稍有不同的规则;更多信息请参见第 19.5.1.7 节,“复制CREATE TABLE ... SELECT语句”。

  • CREATE EVENT IF NOT EXISTS始终会被复制,无论语句中指定的事件是否已存在于源端。

  • 只有成功的CREATE USER语句才会被写入二进制日志。如果语句包含IF NOT EXISTS,则被视为成功,并在至少创建一个在语句中命名的用户时记录;在这种情况下,语句将被记录为原样;这包括对未创建的现有用户的引用。更多信息请参见创建用户二进制日志记录。

  • (MySQL 8.0.29 及更高版本😃 CREATE PROCEDURE IF NOT EXISTSCREATE FUNCTION IF NOT EXISTSCREATE TRIGGER IF NOT EXISTS,如果成功,将完整写入二进制日志(包括IF NOT EXISTS子句),无论语句是否因对象(过程、函数或触发器)已存在而引发警告。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-create-select.html

19.5.1.7 复制 CREATE TABLE ... SELECT 语句

当复制CREATE TABLE ... SELECT语句时,MySQL 应用以下规则:

  • CREATE TABLE ... SELECT总是执行隐式提交(第 15.3.3 节,“导致隐式提交的语句”)。

  • 如果目标表不存在,则记录如下。无论是否存在IF NOT EXISTS都无关紧要。

    • STATEMENTMIXED格式:该语句按原样记录。

    • ROW格式:该语句被记录为一个CREATE TABLE语句,后跟一系列插入行事件。

      在 MySQL 8.0.21 之前,该语句被记录为两个事务。从 MySQL 8.0.21 开始,在支持原子 DDL 的存储引擎上,它被记录为一个事务。更多信息,请参阅第 15.1.1 节,“原子数据定义语句支持”。

  • 如果CREATE TABLE ... SELECT语句失败,则不会记录任何内容。这包括目标表存在且未使用IF NOT EXISTS的情况。

  • 如果目标表存在且使用了IF NOT EXISTS,MySQL 8.0 会完全忽略该语句;不会插入任何内容或记录日志。

MySQL 8.0 不允许CREATE TABLE ... SELECT语句对除了该语句创建的表之外的其他表进行任何更改。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-current-user.html

19.5.1.8 CURRENT_USER() 的复制

以下语句支持使用CURRENT_USER()函数来代替受影响用户或定义者的名称,以及可能的主机:

  • DROP USER

  • RENAME USER

  • GRANT

  • REVOKE

  • CREATE FUNCTION

  • CREATE PROCEDURE

  • CREATE TRIGGER

  • CREATE EVENT

  • CREATE VIEW

  • ALTER EVENT

  • ALTER VIEW

  • SET PASSWORD

当启用二进制日志记录并且在这些语句中使用CURRENT_USER()CURRENT_USER作为定义者时,MySQL 服务器确保在语句被复制时应用于源和副本上的相同用户。在某些情况下,例如更改密码的语句,函数引用在写入二进制日志之前会被展开,以便语句包含用户名称。对于所有其他情况,源上的当前用户名称会作为元数据被复制到副本上,并且副本会将语句应用于元数据中命名的当前用户,而不是副本上的当前用户。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-differing-tables.html

19.5.1.9 源表和副本表定义不同的复制

源表和目标表的复制不必完全相同。源表可以比副本表的副本具有更多或更少的列。此外,源表和副本的对应表列可以使用不同的数据类型,但必须满足一定条件。

注意

不支持不同分区的表之间的复制。参见 Section 19.5.1.24, “复制和分区”。

在所有源表和目标表定义不完全相同的情况下,数据库和表名必须在源表和副本上相同。在以下两个部分中讨论了其他条件,并给出了示例。

19.5.1.9.1 源表或副本表中有更多列的复制

可以将表从源复制到副本,使得源表和副本表的列数不同,但必须满足以下条件:

  • 两个表共有的列必须在源表和副本上以相同顺序定义。(即使两个表具有相同数量的列也是如此。)

  • 两个表共有的列必须在任何额外列之前定义。

    这意味着在副本上执行ALTER TABLE语句,向表中插入一个新列,该列位于两个表共有的列范围内,会导致复制失败,如下例所示:

    假设表t在源和副本上存在,并由以下CREATE TABLE语句定义:

    CREATE TABLE t (
        c1 INT,
        c2 INT,
        c3 INT
    );
    

    假设在副本上执行了以下ALTER TABLE语句:

    ALTER TABLE t ADD COLUMN cnew1 INT AFTER c3;
    

    之前的ALTER TABLE在副本上是允许的,因为表t的两个版本中共有的列c1c2c3在任何不同的列之前都保持在一起。

    然而,在副本上执行以下ALTER TABLE语句会导致复制中断:

    ALTER TABLE t ADD COLUMN cnew2 INT AFTER c2;
    

    在副本上执行刚刚显示的ALTER TABLE语句后,复制失败,因为新列cnew2位于t两个版本共有的列之间。

  • 在列更多的表版本中,每个“额外”列必须有一个默认值。

    列的默认值由多种因素决定,包括其类型、是否使用DEFAULT选项定义、是否声明为NULL,以及创建时服务器 SQL 模式的有效性;更多信息,请参见第 13.6 节,“数据类型默认值”)。

此外,当副本表比源表具有更多列时,两个表中共有的每一列必须在两个表中使用相同的数据类型。

示例。 以下示例说明了一些有效和无效的表定义:

源表中有更多列。 以下表定义是有效的,并且可以正确复制:

source> CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);
replica>  CREATE TABLE t1 (c1 INT, c2 INT);

下表定义会引发错误,因为两个版本表共有的列的定义在副本表上的顺序与源表上的顺序不同:

source> CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);
replica>  CREATE TABLE t1 (c2 INT, c1 INT);

下表定义也会引发错误,因为源表中额外列的定义出现在两个版本共有的列定义之前:

source> CREATE TABLE t1 (c3 INT, c1 INT, c2 INT);
replica>  CREATE TABLE t1 (c1 INT, c2 INT);

副本表中有更多列。 以下表定义是有效的,并且可以正确复制:

source> CREATE TABLE t1 (c1 INT, c2 INT);
replica>  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);

下列定义会引发错误,因为两个版本表共有的列在源表和副本表上的定义顺序不同:

source> CREATE TABLE t1 (c1 INT, c2 INT);
replica>  CREATE TABLE t1 (c2 INT, c1 INT, c3 INT);

下表定义也会引发错误,因为副本版本表中额外列的定义出现在两个版本共有的列定义之前:

source> CREATE TABLE t1 (c1 INT, c2 INT);
replica>  CREATE TABLE t1 (c3 INT, c1 INT, c2 INT);

下表定义失败,因为副本版本表比源版本表多了额外列,并且两个版本的表对于共有列c2使用了不同的数据类型:

source> CREATE TABLE t1 (c1 INT, c2 BIGINT);
replica>  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);
19.5.1.9.2 具有不同数据类型的列的复制

源表和副本表中相应的列的副本应该具有相同的数据类型。然而,并不总是严格执行这一规定,只要满足一定条件即可。

通常可以从具有特定数据类型的列复制到具有相同类型和大小或宽度的另一列,如适用,或更大的列。例如,可以从CHAR(10)列复制到另一个CHAR(10)列,或者从CHAR(10)列复制到CHAR(25)列而不会出现问题。在某些情况下,还可以从源表中具有一种数据类型的列复制到副本中具有不同数据类型的列;当源表中列的数据类型提升为副本中相同大小或更大的类型时,这称为属性提升。

属性提升可用于基于语句和基于行的复制,并且不依赖于源或副本使用的存储引擎。但是,日志格式的选择确实会影响允许的类型转换;具体内容将在本节后面讨论。

重要提示

无论您使用基于语句还是基于行的复制,如果希望使用属性提升,则副本表的副本不能包含比源表的副本更多的列。

基于语句的复制。 在使用基于语句的复制时,一个简单的经验法则是,“如果在源上运行的语句也可以在副本上成功执行,则它也应该成功复制”。换句话说,如果语句使用与副本上给定列类型兼容的值,则可以复制该语句。例如,您可以将适合TINYINT列的任何值插入到BIGINT列中;因此,即使您将副本表中的TINYINT列的类型更改为BIGINT,任何成功插入该列的源上的插入也应该在副本上成功,因为不可能有一个合法的TINYINT值大到足以超过BIGINT列。

基于行的复制:属性提升和降级。 基于行的复制支持较小数据类型和较大类型之间的属性提升和降级。还可以指定是否允许对降级列值进行有损(截断)或无损转换,如本节后面所述。

有损和无损转换。 在目标类型无法表示要插入的值的情况下,必须决定如何处理转换。如果我们允许转换但截断(或以其他方式修改)源值以在目标列中实现“适合”,我们进行的是所谓的有损转换。不需要截断或类似修改以使源列值适合目标列的转换是无损转换。

类型转换模式。 系统变量replica_type_conversions(从 MySQL 8.0.26 开始)或slave_type_conversions(在 MySQL 8.0.26 之前)的全局值控制副本上使用的类型转换模式。此变量接受以下列表中的一组值,描述了每种模式对副本的类型转换行为的影响:

ALL_LOSSY

在此模式下,允许会导致信息丢失的类型转换。

这并不意味着允许非损失转换,仅表示只允许需要损失转换或根本不需要转换的情况;例如,仅启用模式允许将INT列转换为TINYINT(损失转换),但不允许将TINYINT列转换为INT列(非损失)。在这种情况下尝试后者的转换会导致副本停止并显示错误。

ALL_NON_LOSSY

此模式允许不需要截断或其他特殊处理源值的转换;也就是说,它允许目标类型的范围比源类型更宽的转换。

设置此模式不影响是否允许有损转换;这由ALL_LOSSY模式控制。如果只设置了ALL_NON_LOSSY,但没有设置ALL_LOSSY,那么尝试进行可能导致数据丢失的转换(例如INTTINYINT,或CHAR(25)VARCHAR(20))会导致副本停止并显示错误。

ALL_LOSSY,ALL_NON_LOSSY

当设置此模式时,允许所有支持的类型转换,无论它们是否是有损转换。

ALL_SIGNED

将提升的整数类型视为有符号值(默认行为)。

ALL_UNSIGNED

将提升的整数类型视为无符号值。

ALL_SIGNED,ALL_UNSIGNED

尽可能将提升的整数类型视为有符号,否则视为无符号。

[]

当未设置replica_type_conversionsslave_type_conversions时,不允许进行属性提升或降级;这意味着源表和目标表中的所有列必须是相同类型。

这是默认模式。

当整数类型被提升时,其符号性不会被保留。默认情况下,副本将所有这些值视为有符号的。您可以使用ALL_SIGNEDALL_UNSIGNED或两者来控制此行为。ALL_SIGNED告诉副本将所有提升的整数类型视为有符号;ALL_UNSIGNED指示将其视为无符号。如果同时指定两者,副本将尽可能将值视为有符号,否则将视为无符号;它们列出的顺序并不重要。如果至少没有使用ALL_LOSSYALL_NONLOSSY中的一个,那么ALL_SIGNEDALL_UNSIGNED都不会产生任何效果。

更改类型转换模式需要使用新的replica_type_conversionsslave_type_conversions设置重新启动副本。

支持的转换。 支持不同但相似数据类型之间的转换列在以下列表中:

  • 在任何整数类型TINYINTSMALLINTMEDIUMINTINTBIGINT之间。

    这包括这些类型的有符号和无符号版本之间的转换。

    通过将源值截断为目标列允许的最大(或最小)值来进行有损转换。为了确保从无符号到有符号类型的非有损转换,目标列必须足够大,以容纳源列中的值范围。例如,您可以将TINYINT UNSIGNED非有损地降级为SMALLINT,但不能降级为TINYINT

  • 在任何十进制类型DECIMALFLOATDOUBLENUMERIC之间。

    FLOATDOUBLE是非有损转换;DOUBLEFLOAT只能以有损方式处理。从DECIMAL(*M*,*D*)DECIMAL(*M'*,*D'*)的转换,其中*D'* >= *D*(*M'*-*D'*) >= (*M*-*D*)是非有损的;对于任何*M'* < *M**D'* < *D*,或两者都是的情况,只能进行有损转换。

    对于任何十进制类型,如果要存储的值无法适应目标类型,则根据文档中其他地方定义的服务器舍入规则将该值向下舍入。有关十进制类型的此类操作的详细信息,请参见第 14.24.4 节,“舍入行为”。

  • 在任何字符串类型CHARVARCHARTEXT之间,包括不同宽度之间的转换。

    CHARVARCHARTEXT转换为大小相同或更大的CHARVARCHARTEXT列永远不会有损。有损转换通过在副本上仅插入字符串的前N个字符来处理,其中N是目标列的宽度。

    重要提示

    不支持在使用不同字符集的列之间进行复制。

  • 任意二进制数据类型BINARYVARBINARYBLOB之间的转换,包括不同宽度之间的转换。

    BINARYVARBINARYBLOB转换为相同大小或更大的BINARYVARBINARYBLOB列永远不会有损失。有损转换通过仅在副本上插入字符串的前N字节来处理,其中N是目标列的宽度。

  • 任意两个不同大小的BIT列之间。

    当将来自BIT(*M*)列的值插入到BIT(*M'*)列中,其中*M'* > *M*时,BIT(*M'*)列的最高有效位被清除(设置为零),而BIT(*M*)值的M位被设置为BIT(*M'*)列的最低有效位。

    当将来自源BIT(*M*)列的值插入到目标BIT(*M'*)列中,其中*M'* < *M*时,BIT(*M'*)列被赋予最大可能的值;换句话说,目标列被赋予“全置位”值。

类型转换不在前述列表中的类型是不允许的。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-directory.html

19.5.1.10 复制和 DIRECTORY 表选项

如果在源服务器的CREATE TABLE语句中使用了DATA DIRECTORYINDEX DIRECTORY表选项,则该表选项也会在副本上使用。如果在副本主机文件系统中不存在相应的目录,或者存在但对副本 MySQL 服务器不可访问,则可能会出现问题。可以通过在副本上使用NO_DIR_IN_CREATE服务器 SQL 模式来覆盖此行为,这会导致副本在复制CREATE TABLE语句时忽略DATA DIRECTORYINDEX DIRECTORY表选项。结果是MyISAM数据和索引文件将在表的数据库目录中创建。

查看更多信息,请参见第 7.1.11 节,“服务器 SQL 模式”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-drop-if-exists.html

19.5.1.11 复制DROP ... IF EXISTS语句

DROP DATABASE IF EXISTSDROP TABLE IF EXISTSDROP VIEW IF EXISTS语句始终会被复制,即使要删除的数据库、表或视图在源上不存在。这是为了确保一旦副本赶上源,要删除的对象在源或副本上都不再存在。

DROP ... IF EXISTS 语句用于存储程序(存储过程和函数,触发器和事件),即使要删除的存储程序在源上不存在,也会被复制。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-floatvalues.html

19.5.1.12 复制和浮点值

在基于语句的复制中,值从十进制转换为二进制。由于十进制和二进制表示之间的转换可能是近似的,涉及浮点值的比较是不精确的。这对明确使用浮点值的操作,或者隐式转换为浮点的值都是适用的。由于计算机架构、用于构建 MySQL 的编译器等方面的差异,源服务器和副本服务器上对浮点值的比较可能产生不同的结果。参见第 14.3 节,“表达式评估中的类型转换”,以及第 B.3.4.8 节,“浮点值的问题”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-flush.html

19.5.1.13 复制和 FLUSH

一些形式的FLUSH语句不会被记录,因为如果被复制到副本中可能会引起问题:FLUSH LOGSFLUSH TABLES WITH READ LOCK。有关语法示例,请参见 Section 15.7.8.3, “FLUSH Statement”。FLUSH TABLESANALYZE TABLEOPTIMIZE TABLEREPAIR TABLE语句会被写入二进制日志,因此会被复制到副本中。通常这不是问题,因为这些语句不会修改表数据。

然而,在某些情况下,这种行为可能会引起困难。如果在mysql数据库中复制权限表并直接更新这些表而不使用GRANT,则必须在副本上发出FLUSH PRIVILEGES以使新权限生效。此外,如果在重命名作为MERGE表的MyISAM表时使用FLUSH TABLES,则必须在副本上手动发出FLUSH TABLES。除非指定NO_WRITE_TO_BINLOG或其别名LOCAL,否则这些语句将被写入二进制日志。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-functions.html

19.5.1.14 复制和系统函数

在某些情况下,某些函数无法很好地进行复制:

  • USER()CURRENT_USER()(或CURRENT_USER)、UUID()VERSION()LOAD_FILE()函数在复制时不会更改,因此在副本上无法可靠工作,除非启用了基于行的复制。(参见 Section 19.2.1, “复制格式”。)

    MIXED模式下使用基于行的复制时,USER()CURRENT_USER()会自动复制,并在STATEMENT模式下生成警告。(另请参阅 Section 19.5.1.8, “CURRENT_USER()的复制”的复制")。)对于VERSION()RAND()也是如此。

  • 对于NOW(),二进制日志包括时间戳。这意味着源上调用此函数返回的值会被复制到副本中。为了避免在不同时区的 MySQL 服务器之间复制时出现意外结果,请在源和副本上都设置时区。更多信息,请参见 Section 19.5.1.33, “复制和时区”。

    为了解释在不同时区的服务器之间复制时可能出现的问题,假设源位于纽约,副本位于斯德哥尔摩,两台服务器都使用当地时间。进一步假设,在源上,你创建了一个表mytable,对该表执行了一个INSERT语句,然后从表中选择,如下所示:

    mysql> CREATE TABLE mytable (mycol TEXT);
    Query OK, 0 rows affected (0.06 sec)
    
    mysql> INSERT INTO mytable VALUES ( NOW() );
    Query OK, 1 row affected (0.00 sec)
    
    mysql> SELECT * FROM mytable;
    +---------------------+
    | mycol               |
    +---------------------+
    | 2009-09-01 12:00:00 |
    +---------------------+
    1 row in set (0.00 sec)
    

    斯德哥尔摩的当地时间比纽约晚 6 小时;因此,如果你在副本上的确切时刻发出SELECT NOW(),将返回值2009-09-01 18:00:00。因此,如果在复制了刚刚显示的CREATE TABLEINSERT语句之后,从副本的mytable复制,你可能期望mycol包含值2009-09-01 18:00:00。然而,事实并非如此;当你从副本的mytable复制时,你得到的结果与源上完全相同:

    mysql> SELECT * FROM mytable;
    +---------------------+
    | mycol               |
    +---------------------+
    | 2009-09-01 12:00:00 |
    +---------------------+
    1 row in set (0.00 sec)
    

    NOW()不同,SYSDATE()函数不是复制安全的,因为它不受二进制日志中SET TIMESTAMP语句的影响,并且在使用基于语句的日志记录时是不确定的。如果使用基于行的日志记录,则不会出现问题。

    另一种选择是使用--sysdate-is-now选项,使SYSDATE()成为NOW()的别名。这必须在源和副本上都执行才能正常工作。在这种情况下,此函数仍会发出警告,但只要在源和副本上都使用--sysdate-is-now,就可以安全地忽略。

    当使用MIXED模式时,SYSDATE()会自动使用基于行的复制进行复制,并在STATEMENT模式下生成警告。

    另请参阅 Section 19.5.1.33, “Replication and Time Zones”。

  • 以下限制仅适用于基于语句的复制,不适用于基于行的复制。 处理用户级锁的GET_LOCK()RELEASE_LOCK()IS_FREE_LOCK()IS_USED_LOCK()函数在源上处理并在副本上不知道并发上下文。因此,这些函数不应用于插入源表,因为副本上的内容会有所不同。例如,不要发出类似INSERT INTO mytable VALUES(GET_LOCK(...))的语句。

    当使用MIXED模式时,这些函数会自动使用基于行的复制进行复制,并在STATEMENT模式下生成警告。

作为解决方案,当基于语句的复制生效时,您可以使用将有问题的函数结果保存在用户变量中,并在后续语句中引用该变量的策略。例如,以下单行INSERT由于引用UUID()函数而存在问题:

INSERT INTO t VALUES(UUID());

要解决这个问题,可以这样做��

SET @my_uuid = UUID();
INSERT INTO t VALUES(@my_uuid);

该序列的语句之所以能够复制,是因为@my_uuid的值作为用户变量事件存储在二进制日志中,先于INSERT语句,并且可以在INSERT中使用。

相同的思路也适用于多行插入,但使用起来更加繁琐。对于两行插入,您可以这样做:

SET @my_uuid1 = UUID(); @my_uuid2 = UUID();
INSERT INTO t VALUES(@my_uuid1),(@my_uuid2);

但是,如果行数很大或者未知,解决方法就会变得困难或者不可行。例如,你无法将以下语句转换为一个语句,其中一个给定的个人用户变量与每一行相关联:

INSERT INTO t2 SELECT UUID(), * FROM t1;

在存储函数中,RAND() 只要在函数执行过程中仅调用一次,就能正确复制。(你可以将函数执行时间戳和随机数种子视为在源和副本上相同的隐式输入。)

FOUND_ROWS()ROW_COUNT() 函数在基于语句的复制中无法可靠复制。一个解决方法是将函数调用的结果存储在用户变量中,然后在 INSERT 语句中使用。例如,如果你希望将结果存储在名为 mytable 的表中,你可能会像这样做:

SELECT SQL_CALC_FOUND_ROWS FROM mytable LIMIT 1;
INSERT INTO mytable VALUES( FOUND_ROWS() );

但是,如果你正在复制 mytable,你应该使用 SELECT ... INTO,然后将变量存储在表中,就像这样:

SELECT SQL_CALC_FOUND_ROWS INTO @found_rows FROM mytable LIMIT 1;
INSERT INTO mytable VALUES(@found_rows);

这样,用户变量将作为上下文的一部分进行复制,并在副本上正确应用。

当使用 MIXED 模式时,这些函数会在基于行的复制中自动复制,并在 STATEMENT 模式下生成警告。(Bug #12092, Bug #30244)

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-fractional-seconds.html

19.5.1.15 复制和分数秒支持

MySQL 8.0 允许TIMEDATETIMETIMESTAMP值使用微秒(6 位数字)精度的分数秒。请参见第 13.2.6 节,“时间值中的分数秒”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-invoked.html

19.5.1.16 调用特性的复制

调用特性的复制,如可加载函数和存储程序(存储过程和函数、触发器和事件),提供以下特性:

  • 特性的效果始终会被复制。

  • 以下语句使用基于语句的复制进行复制:

    • CREATE EVENT

    • ALTER EVENT

    • DROP EVENT

    • CREATE PROCEDURE

    • DROP PROCEDURE

    • CREATE FUNCTION

    • DROP FUNCTION

    • CREATE TRIGGER

    • DROP TRIGGER

    但是,使用这些语句创建、修改或删除的特性的效果是使用基于行的复制进行复制的。

    注意

    尝试使用基于语句的复制复制调用特性会产生警告“Statement is not safe to log in statement format”。例如,尝试使用基于语句的复制复制可加载函数会生成此警告,因为当前无法由 MySQL 服务器确定函数是否是确定性的。如果您绝对确定调用特性的效果是确定性的,可以安全地忽略此类警告。

  • CREATE EVENTALTER EVENT的情况下:

    • 事件的状态在副本上设置为SLAVESIDE_DISABLED,无论指定的状态如何(这不适用于DROP EVENT)。

    • 在副本上,通过其服务器 ID 标识创建事件的源。INFORMATION_SCHEMA.EVENTS中的ORIGINATOR列存储此信息。有关更多信息,请参见第 15.7.7.18 节,“SHOW EVENTS Statement”。

  • 该功能的实现位于副本中,处于可更新状态,因此如果源失败,副本可以被用作源而不会丢失事件处理。

要确定在 MySQL 服务器上是否有任何在不同服务器(作为源服务器)上创建的计划事件,请以类似于此处所示的方式查询信息模式EVENTS表:

SELECT EVENT_SCHEMA, EVENT_NAME
    FROM INFORMATION_SCHEMA.EVENTS
    WHERE STATUS = 'SLAVESIDE_DISABLED';

或者,您可以使用SHOW EVENTS语句,如下所示:

SHOW EVENTS
    WHERE STATUS = 'SLAVESIDE_DISABLED';

将具有此类事件的副本升级为源时,必须使用ALTER EVENT *event_name* ENABLE来启用每个事件,其中event_name是事件的名称。

如果在创建此副本上的事件时涉及多个源,并且您希望识别仅在具有服务器 ID source_id的给定源上创建的事件,请修改前面在EVENTS表上的查询,包括ORIGINATOR列,如下所示:

SELECT EVENT_SCHEMA, EVENT_NAME, ORIGINATOR
    FROM INFORMATION_SCHEMA.EVENTS
    WHERE STATUS = 'SLAVESIDE_DISABLED'
    AND   ORIGINATOR = '*source_id*'

您可以以类似的方式使用SHOW EVENTS语句中的ORIGINATOR

SHOW EVENTS
    WHERE STATUS = 'SLAVESIDE_DISABLED'
    AND   ORIGINATOR = '*source_id*'

在启用从源复制的事件之前,您应该在副本上禁用 MySQL 事件调度程序(使用类似于SET GLOBAL event_scheduler = OFF;的语句),运行任何必要的ALTER EVENT语句,重新启动服务器,然后在副本上重新启用事件调度程序(使用类似于SET GLOBAL event_scheduler = ON;的语句)-

如果稍后将新源重新降级为副本,则必须手动禁用由ALTER EVENT语句启用的所有事件。您可以通过在单独的表中存储先前显示的SELECT语句中的事件名称,或使用ALTER EVENT语句将事件重命名为具有replicated_前缀的公共前缀来执行此操作。

如果您重命名事件,那么在将此服务器重新降级为副本时,您可以通过查询EVENTS表来识别事件,如下所示:

SELECT CONCAT(EVENT_SCHEMA, '.', EVENT_NAME) AS 'Db.Event'
      FROM INFORMATION_SCHEMA.EVENTS
      WHERE INSTR(EVENT_NAME, 'replicated_') = 1;

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-json.html

19.5.1.17 JSON 文档的复制

在 MySQL 8.0 之前,对 JSON 列的更新始终被写入二进制日志作为完整文档。在 MySQL 8.0 中,可以记录 JSON 文档的部分更新(请参阅 JSON 值的部分更新),这更有效率。记录行为取决于所使用的格式,如下所述:

基于语句的复制。 JSON 部分更新始终被记录为部分更新。在使用基于语句的日志记录时,无法禁用此功能。

基于行的复制。 默认情况下,JSON 部分更新不会被记录为部分更新,而是被记录为完整文档。要启用部分更新的记录,请设置binlog_row_value_options=PARTIAL_JSON。如果复制源设置了此变量,则来自该源的部分更新将由副本处理和应用,而不管副本自身对该变量的设置如何。

运行 MySQL 8.0.2 或更早版本的服务器无法识别用于 JSON 部分更新的日志事件。因此,当从运行 MySQL 8.0.3 或更高版本的服务器复制到此类服务器时,必须通过将此变量设置为''(空字符串)在源端禁用binlog_row_value_options。有关更多信息,请参阅此变量的描述。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-limit.html

19.5.1.18 复制和 LIMIT

DELETEUPDATEINSERT ... SELECT语句中,基于语句的复制LIMIT子句是不安全的,因为受影响的行的顺序未定义。(只有当这些语句还包含ORDER BY子句时,才能通过基于语句的复制正确复制这些语句。)当遇到这样的语句时:

  • 在使用STATEMENT模式时,现在会发出警告,说明该语句对于基于语句的复制不安全。

    在使用STATEMENT模式时,即使 DML 语句包含LIMIT并且还有ORDER BY子句(因此变得确定性),也会发出警告。这是一个已知问题。(Bug #42851)

  • 在使用MIXED模式时,该语句现在会自动使用基于行的模式进行复制。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-load-data.html

19.5.1.19 复制和 LOAD DATA

LOAD DATA 被认为在基于语句的日志记录中是不安全的(参见 Section 19.2.1.3, “二进制日志中安全和不安全语句的确定”)。当设置 binlog_format=MIXED 时,该语句以行格式记录。当设置 binlog_format=STATEMENT 时,请注意,与其他不安全语句不同,LOAD DATA 不会生成警告。

如果您使用 LOAD DATAbinlog_format=STATEMENT,每个要应用更改的副本都会创建一个包含数据的临时文件。然后,副本使用 LOAD DATA 语句来应用更改。即使源上启用了二进制日志加密,此临时文件也不会被加密。如果需要加密,请改用基于行或混合的二进制日志格式,副本不会创建临时文件。

如果使用 PRIVILEGE_CHECKS_USER 帐户来帮助保护复制通道(参见 Section 19.3.3, “复制权限检查”),强烈建议您使用基于行的二进制日志记录(binlog_format=ROW)记录 LOAD DATA 操作。如果为通道设置了 REQUIRE_ROW_FORMAT,则需要基于行的二进制日志记录。使用此日志格式,执行事件不需要 FILE 权限,因此不要给 PRIVILEGE_CHECKS_USER 帐户此权限。如果需要从以语句格式记录的 LOAD DATA INFILE 操作的复制错误中恢复,并且复制的事件是可信的,则可以暂时授予 PRIVILEGE_CHECKS_USER 帐户 FILE 权限,在应用复制的事件后再删除该权限。

mysqlbinlog读取以语句为基础格式记录的LOAD DATA语句的日志事件时,会在临时目录中创建一个生成的本地文件。这些临时文件不会被mysqlbinlog或任何其他 MySQL 程序自动删除。如果您确实使用了以语句为基础的二进制日志记录的LOAD DATA语句,那么在不再需要语句日志后,您应该自行删除这些临时文件。更多信息,请参阅 Section 6.6.9, “mysqlbinlog — 用于处理二进制日志文件的实用程序”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-max-allowed-packet.html

19.5.1.20 复制和 max_allowed_packet

max_allowed_packet设置了 MySQL 服务器和客户端之间的任何单个消息的大小上限,包括副本。如果在源端复制大型列值(例如可能在TEXTBLOB列中找到的值),而max_allowed_packet在源端设置过小,源端将会出现错误,并且副本会关闭复制 I/O(接收器)线程。如果副本端的max_allowed_packet设置过小,也会导致副本停止 I/O 线程。

基于行的复制从源端向副本发送更新行的所有列和列值,包括实际上未被更新的列的值。这意味着,当您使用基于行的复制复制大型列值时,您必须确保将max_allowed_packet设置得足够大,以容纳要复制的任何表中最大行的大小,即使您只复制更新,或者只插入相对较小的值。

在多线程复制(具有replica_parallel_workers > 0slave_parallel_workers > 0)中,确保系统变量replica_pending_jobs_size_maxslave_pending_jobs_size_max的设置值等于或大于源端max_allowed_packet系统变量的设置值。replica_pending_jobs_size_maxslave_pending_jobs_size_max的默认设置为 128M,是max_allowed_packet系统变量的默认设置值 64M 的两倍。max_allowed_packet限制了源端可以发送的数据包大小,但添加事件头可能会产生超过此大小的二进制日志事件。此外,在基于行的复制中,单个事件可能比max_allowed_packet大小显著更大,因为max_allowed_packet的值仅限制表的每列。

实际上,复制端接受的数据包上限由其replica_max_allowed_packetslave_max_allowed_packet设置确定,默认设置为最大设置值 1GB,以防止由于大数据包而导致复制失败。然而,replica_pending_jobs_size_maxslave_pending_jobs_size_max的值控制了复制端可用于保存传入数据包的内存。指定的内存是在所有复制工作队列之间共享的。

replica_pending_jobs_size_maxslave_pending_jobs_size_max的值是一个软限制,如果一个异常大的事件(由一个或多个数据包组成)超过了这个大小,事务将被暂停,直到所有副本工作者的队列为空,然后再处理。所有后续事务都将被暂停,直到大事务完成。因此,虽然大于replica_pending_jobs_size_maxslave_pending_jobs_size_max的异常事件可以被处理,但清空所有副本工作者队列和等待排队后续事务的延迟可能导致副本延迟和副本工作者并发性降低。因此,replica_pending_jobs_size_maxslave_pending_jobs_size_max应设置为足够高,以容纳大多数预期事件大小。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-memory.html

19.5.1.21 复制和 MEMORY 表

当复制源服务器关闭并重新启动时,其MEMORY表会变为空。为了将这种效果复制到副本中,源在启动后第一次使用给定的MEMORY表时,会记录一个事件,通知副本该表必须通过向二进制日志写入DELETE或(从 MySQL 8.0.22 开始)TRUNCATE TABLE语句来清空该表。这个生成的事件在二进制日志中通过注释可识别,如果服务器上使用了 GTID,则会分配一个 GTID。该语句始终以语句格式记录,即使二进制日志格式设置为ROW,并且即使服务器设置为read_onlysuper_read_only模式,也会写入。请注意,在源重新启动并首次使用表之间的间隔期间,副本仍然具有MEMORY表中的过时数据。为了避免这种间隔,当直接查询副本可能返回陈旧数据时,您可以设置init_file系统变量以命名一个包含在启动时在源上填充MEMORY表的语句的文件。

当副本服务器关闭并重新启动时,其MEMORY表会变为空。这会导致副本与源不同步,并可能导致其他故障或导致副本停止:

  • 来自源的行格式更新和删除可能会因为Can't find record in '*memory_table*'而失败。

  • 诸如INSERT INTO ... SELECT FROM *memory_table*之类的语句可能在源和副本上插入不同的行集。

副本还会将一个DELETE或(从 MySQL 8.0.22 开始)TRUNCATE TABLE语句写入其自己的二进制日志,传递给任何下游副本,导致它们清空自己的MEMORY表。

重新启动正在复制MEMORY表的副本的安全方法是首先在源上删除或清空所有MEMORY表中的行,并等待这些更改复制到副本。然后才能安全地重新启动副本。

在某些情况下可能适用另一种重启方法。当binlog_format=ROW时,如果在重新启动复制之前设置replica_exec_mode=IDEMPOTENT(从 MySQL 8.0.26 开始)或slave_exec_mode=IDEMPOTENT(在 MySQL 8.0.26 之前),则可以防止复制停止。这样可以使复制继续进行,但其MEMORY表仍然与源端不同。如果应用逻辑允许MEMORY表的内容安全丢失(例如,如果MEMORY表用于缓存),那么这是可以接受的。replica_exec_mode=IDEMPOTENTslave_exec_mode=IDEMPOTENT对所有表都适用,因此可能会隐藏非MEMORY表中的其他复制错误。

(刚刚描述的方法在 NDB Cluster 中不适用,那里的replica_exec_modeslave_exec_mode始终为IDEMPOTENT,且无法更改。)

MEMORY表的大小受max_heap_table_size系统变量的值限制,该值不会被复制(参见 Section 19.5.1.39,“复制和变量”)。更改max_heap_table_size对于使用ALTER TABLE ... ENGINE = MEMORYTRUNCATE TABLE创建或更新的MEMORY表会生效,或者对于所有在服务器重新启动后的MEMORY表也会生效。如果你在源端增加了此变量的值而在复制端没有这样做,那么源端的表可能会比复制端的表更大,导致在源端成功插入但在复制端出现“表已满”错误。这是一个已知问题(Bug #48666)。在这种情况下,你必须在复制端和源端都设置max_heap_table_size的全局值,然后重新启动复制。建议同时重新启动源端和复制端的 MySQL 服务器,以确保新值在它们各自上完全生效。

查看第 18.3 节,“MEMORY 存储引擎”,了解有关MEMORY表的更多信息。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-mysqldb.html

19.5.1.22 mysql 系统模式的复制

mysql模式中的表进行的数据修改语句根据binlog_format的值进行复制;如果该值为MIXED,则使用基于行的格式复制这些语句。然而,通常间接更新此信息的语句,如GRANTREVOKE以及操作触发器、存储过程和视图的语句,会使用基于语句的复制方式复制到副本。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-optimizer.html

19.5.1.23 复制和查询优化器

如果一个语句被编写成非确定性的方式,即由查询优化器决定,那么源数据库和副本数据库上的数据可能会变得不同。(一般来说,这不是一个好的做法,即使在复制之外也是如此。)非确定性语句的例子包括使用LIMIT而没有ORDER BY子句的DELETEUPDATE语句;详细讨论请参见 Section 19.5.1.18, “Replication and LIMIT”。

原文:dev.mysql.com/doc/refman/8.0/en/replication-features-partitioning.html

19.5.1.24 复制和分区

只要分区表使用相同的分区方案并且结构相同,复制就支持分区表之间的复制,除非特别允许异常情况(参见 Section 19.5.1.9, “源表和副本表上定义不同的复制”)。

不同分区的表之间的复制通常不受支持。这是因为在这种情况下直接作用于分区的语句(比如ALTER TABLE ... DROP PARTITION)可能会在源表和副本表上产生不同的结果。在源表分区但副本表未分区的情况下,任何在源表副本上操作分区的语句都会在副本表上失败。当副本表分区但源表未分区时,在源表上运行直接作用于分区的语句会导致错误。为避免停止复制或在源表和副本表之间创建不一致,始终确保源表和副本表的对应复制表以相同方式分区。

posted @ 2024-06-23 12:24  绝不原创的飞龙  阅读(7)  评论(0编辑  收藏  举报