第19章复制
19.2 复制实现
复制是基于源服务器跟踪其二进制文件中的数据库更改(如更新、删除等)的日志。这些二进制日志记录了从服务器启动那一刻起,所有修改数据库结构或内容的事件。通常,SELECT语句不会被记录,因为它们既不修改数据库也不修改结构和内容。
每个连接到源的副本都会请求这些二进制日志。这意味着它们从源中提取数据,而不是将数据推送到副本。副本还会执行它收到的二进制日志中的事件,这会重复原始更改的效果,就像它们在源上所做的那样。这包括创建表、修改其结构以及根据原始在源上进行的更改插入、删除和更新数据。
由于每个副本都是独立的,因此重播来自源的二进制日志的更改会在每个连接到源的副本上独立发生。此外,由于每个副本仅通过从源读取来更新数据库,并且可以按照自己的节奏进行,因此可以随意启动和停止复制,而不会影响源端或副本端的最新数据库状态。
19.2.1 复制格式
复制在MySQL中之所以有效,是因为写入二进制日志的事件是从源数据库读取的,然后在副本数据库上进行处理。这些事件以不同的格式记录在二进制日志中,具体取决于事件类型。使用的不同复制格式对应于事件发生时使用的二进制日志记录格式,这些记录在源数据库的二进制日志中。二进制日志记录格式和复制期间使用的术语之间的相关性包括:
-
使用基于语句的二进制日志记录时,源代码会将SQL语句写入二进制日志。将源数据库复制到副本数据库的工作原理是执行这些SQL语句。这称为基于语句的复制(Statement-Based Replication,简称SBR),对应于转换为基于MySQL语句的二进制日志记录格式。
-
使用基于行的日志记录时,源数据库会将事件写入二进制日志,指示如何更改各个表行。将源数据库复制到副本数据库的工作原理是将表示对表行更改的事件应用到副本数据库。这称为基于行的复制(Row-Based Replication,简称RBR)。
-
基于行的日志记录是默认方法。
-
您还可以将MySQL配置为混合使用基于语句和基于行的日志记录,具体取决于哪种方法最适合记录更改。这称为混合格式日志记录。使用混合格式日志记录时,默认情况下使用基于语句的日志记录。根据某些语句以及正在使用的存储引擎,日志会自动在特定情况下切换为基于行的记录。使用混合复制格式称为基于混合的复制或混合格式复制。
MySQL NDB Cluster中的默认二进制日志记录格式是8.4。NDB集群复制使用基于行的复制,而NDB存储引擎不兼容使用基于语句的复制。
在使用二进制日志记录格式时,格式部分由所使用的存储引擎决定,并且取决于正在执行的语句。正在运行的MySQL服务器中的日志记录格式由设置binlog_format服务器系统变量控制。此变量可以使用会话或全局范围进行设置。
管理新设置的时间和方式的规则与其他MySQL服务器系统变量相同。设置当前会话的变量仅持续到该会话结束,并且更改对其他会话不可见。全局设置变量对在更改后连接的客户端生效,但不适用于任何当前客户端会话,包括变量设置所在的会话。
要使全局系统变量设置永久化,如果它适用于服务器重新启动,则必须将其保存在选项文件中。
19.2.1.1 基于语句复制和基于行复制的优缺点
基于语句的复制的优点:
- 写入日志文件的数据更少,减少存储空间需求。
- 日志文件包含进行任何更改的所有语句,可用于审核数据库。
基于语句的复制的缺点:
- 对某些DML语句(如INSERT、DELETE、UPDATE和REPLACE)无法使用。
- 依赖于可加载函数或存储程序的语句可能难以复制。
- 锁定读取语句的使用或选项可能导致问题。
- 确定性可加载函数必须应用于副本。
- 无法正确复制的语句会记录警告。
基于行的复制的优点:
- 所有更改都可以复制,最安全的形式。
- 源上需要的行锁更少,实现更高的并发性。
基于行的复制的缺点:
- RBR可以生成更多必须记录的数据。
- 生成大型BLOB值的确定性可加载函数需要更长的时间才能复制。
- 在副本上看不到收到了哪些语句从源代码中执行。
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节“复制表和临时表”中所述,使用基于行的时,不会复制临时表或混合格式。有关更多信息,请参见第19.2.1.1节“基于语句和基于行的优缺点复制”。
使用基于行的或混合格式,因为没有必要。此外,因为临时表只能从线程中读取创建它们,几乎没有获得任何好处复制它们,即使使用基于语句的格式。
您可以从基于语句的二进制切换到基于行的二进制运行时的日志记录格式,即使临时表具有已创建,但无法从基于行或混合切换将二进制日志记录为基于语句的格式的格式,网址为运行时,由于以前模式下的二进制日志。CREATE TEMPORARY TABLE
MySQL服务器跟踪生效的日志记录模式创建每个临时表的时间。当给定客户端会话结束,服务器会记录每个临时表的语句它仍然存在,并且是在基于语句时创建的二进制日志记录正在使用中。如果基于行的格式或混合格式创建表时正在使用二进制日志记录,语句未记录。DROP TEMPORARY TABLE IF EXISTSDROP TEMPORARY TABLE IF EXISTS
涉及临时表的非事务性DML语句在使用binlog_format=ROW时是允许的,只要作为受语句影响的任何非事务性表是临时表。
RBL和非事务表的同步。当许多行受到影响时,将拆分更改集进入多个事件;当语句提交时,所有这些事件将写入二进制日志。执行时在复本上,将对所有表执行表锁定涉及,然后以批处理模式应用行。根据用于副本副本的引擎表,这可能有效,也可能无效。
延迟和二进制日志大小。RBL将每行的更改写入二进制日志,等等它的大小可以迅速增加。这可以显著增加进行更改所需的时间在与源副本匹配的副本上。你应该注意到这种延迟的可能性应用。
读取二进制日志。mysqlbinlog显示基于行的事件在二进制日志中使用BINLOG语句。这语句将事件显示为基数64编码的字符串,其含义不明显。当使用–base64-output=DECODE-ROWS和–verbose选项调用时,mysqlbinlog会格式化二进制日志是人类可读的。当二进制日志事件是以基于行的格式编写的,并且您想要阅读或从复制或数据库故障中恢复,您可以使用此命令读取二进制日志的内容。查看更多信息,请参见第6.6.9.2节“mysqlbinlog行事件显示”。
二进制日志执行错误和副本执行模式。使用replica_exec_mode=IDEMPOTENT通常仅对MySQL NDB集群复制有用,其中默认值。(参见第25.7.10节“NDB群集复制:双向和循环复制”)。当是时,无法应用更改从RBL因为找不到原始行而没有触发错误或导致复制失败。这意味着更新可能未应用于replica,使源和副本不再同步。延迟问题和非事务性的使用当replica_exec_mode时,带有RBR的表可能会导致源和副本进一步分化。更多信息关于replica_exec_mode,请参见第7.1.8节“服务器系统变量”。IDEMPOTENTreplica_exec_modeIDEMPOTENTIDEMPOTENT
对于其他方案,通常将replica_exec_mode设置为就足够了;这是除NDB之外的存储引擎的默认值。STRICT
不支持基于服务器ID进行筛选。您可以使用IGNORE_SERVER_IDS选项根据服务器ID进行筛选对于CHANGE REPLICATION SOURCE到。此选项适用于基于语句和基于行的日志记录格式,但不能当gtid_mode=ON时使用。另一个过滤掉某些副本上的更改的方法是使用包含带有UPDATE和DELETE语句的关系子句的子句。例如。但是,这不能在基于行的情况下正确工作伐木。使用server_id系统变量对于语句筛选,请使用基于语句的日志记录。WHERE@@server_id <> id_valueWHERE @@server_id <> 1
RBL、非事务表和已停止的副本。使用基于行的日志记录时,如果副本服务器是在副本线程更新非事务表,副本数据库可以达到状态不一致。因此,建议您对所有表都使用事务存储引擎(如InnoDB)使用基于行的格式进行复制。使用STOP REPLICA或STOP REPLICA SQL_THREAD在关闭复制副本之前MySQL服务器有助于防止问题发生,并且是无论日志记录格式如何,始终建议使用您使用的存储引擎。
19.2.1.3 二进制日志记录中安全和不安全语句的确定
MySQL复制中语句的“安全性”指的是语句及其效果是否可以使用基于语句的格式正确复制。如果这是正确的,我们将该声明称为安全;否则,我们将其称为不安全。一般来说,如果一个语句是确定性的,那么它是安全的;而如果它是非确定性的函数,则不被认为是不安全的(请参阅本文后面的非确定性函数不被认为是不安全的一节)。此外,使用来自浮点数学函数的函数始终被视为不安全(请参见第19.5.1.12节“复制和浮点值”)。
处理安全和不安全的语句的方式取决于语句是否被认为是安全的,以及当前的二进制日志记录格式(即binlog_format的值)。在使用基于行的日志记录时,安全和不安全语句的处理方式不同。在使用混合格式日志记录时,标记为使用基于行的格式记录不安全;而安全语句则使用基于语句的记录格式。在使用基于语句的日志记录时,标记为不安全的会生成此效果的警告。安全语句则会正常记录。
每个标记为不安全的语句都会生成一个警告。如果一个大批量执行了许多这样的语句,可能会导致错误日志文件过大。为了防止这种情况,MySQL有一个警告抑制机制。每当在过去的50秒内生成了超过50次ER_BINLOG_UNSAFE_STATEMENT警告,就会启用警告抑制。激活后,这会导致此类警告不写入错误日志;相反,对于这类警告中的每50个警告,都会写一个注释到错误日志。这种情况一直持续到最近的50个此类警告是在50秒或更短的时间内发出的;一旦频率降低到这个阈值以下,警告再次出现,正常记录。警告抑制对确定基于语句的日志记录的语句的安全性没有影响,也没有关于如何向客户端发送警告的信息。MySQL客户端仍然会收到每个此类语句的一个警告。
19.2.2 复制通道
在MySQL多源复制中,一个副本可以打开多个复制通道,每个源服务器一个。复制通道表示从源流向的事务的路径副本。每个复制通道都有自己的接收器(I/O)线程、一个或多个应用器(SQL)线程和中继日志。当来自源的交易由通道的接收方接收线程接收时,它们被添加到通道的中继日志文件中,并且传递到通道的应用线程。这使每个通道独立运行。
在一个副本上创建的最大通道数为256。每个复制通道必须具有唯一(非空)名称。错误代码以及多源复制时发出的消息指定生成错误的通道。
多源副本也可以设置为多线程副本,通过将系统变量replica_parallel_workers设置为大于0的值。在多源副本上执行此操作时,每个副本上的通道具有指定数量的应用线程,加上一个协调线程来管理它们。您无法配置单个通道的应用线程数。
多源副本可以在特定的复制通道上进行。特定于通道的复制筛选器可以在同一数据库或表存在于多个数据库或表上时使用,并且您只需要副本即可从一个副本复制它。对于基于GTID的复制,如果同一事务可能从多个来源到达,您可以确保所有通道上的过滤设置相同。
为了提供与以前版本的兼容性,MySQL服务器在启动时自动创建一个默认频道,其名称为空字符串()。这个频道总是当前;它不能由用户创建或销毁。如果没有其他已创建通道(具有非空名称),复制语句仅作用于默认通道,以便所有复制来自旧副本的语句按预期运行。
19.2.2.1 单通道操作命令
想要在MySQL复制操作中对单个复制通道执行以下复制语句:
- FOR CHANNEL channel
- CHANGE REPLICATION SOURCE TO
- START REPLICA
- STOP REPLICA
- SHOW RELAYLOG EVENTS
- FLUSH RELAY LOGS
- SHOW REPLICA STATUS
- RESET REPLICA
- SOURCE_POS_WAIT() 函数具有一个参数。channel
同时,您不允许在通道中使用 START REPLICA、STOP REPLICA 和 SHOW REPLICA STATUS。在通道中使用 FLUSH RELAY LOGS 时,如果事务正在应用,请求者需要等待事务完成并进行轮换。这样可以防止事务被拆分,这对于组复制是不允许的。
以下是根据您的需求生成的代码:
-- 创建复制通道
CREATE REPLICATION CHANNEL channel;
-- 更改复制源
CHANGE REPLICATION SOURCE TO source;
-- 启动复制
START REPLICA;
-- 停止复制
STOP REPLICA;
-- 查看中继日志事件
SHOW RELAYLOG EVENTS;
-- 刷新中继日志
FLUSH RELAY LOGS;
-- 查看复制状态
SHOW REPLICA STATUS;
-- 重置复制
RESET REPLICA;
-- 使用 SOURCE_POS_WAIT() 函数等待指定位置
DO SLEEP(1);
SOURCE_POS_WAIT('channel', 'file_name', position);
19.2.2.2 与以前的复制语句的兼容性
-
当副本具有多个通道且没有指定通道时,有效语句通常作用于所有可用的通道,但有一些特定的例外。
-
FOR CHANNEL channel
:这是一个用于指定操作特定通道的子句。 -
例如,以下语句的行为与所有通道的预期一样,但除某些组复制通道外:
START REPLICA
:启动所有通道的复制线程,但group_replication_recovery
和group_replication_applier
通道除外。STOP REPLICA
:停止复制所有通道(和group_replication_applier
通道除外)的线程。SHOW REPLICA STATUS
:报告除group_replication_applier
频道外的所有频道的状态。RESET REPLICA
:将全部重置渠道。
-
警告:谨慎使用
RESET REPLICA
,因为此语句会删除所有现有频道,清除其中继日志文件,并仅重新创建默认通道。 -
某些复制语句无法在所有通道上运行。在这种情况下,错误1964会在存在多个通道复制品时生成。请提供频道名称作为参数。以下语句和函数在多源复制拓扑中使用时会生成此错误,并且未使用选项来指定要对其执行操作的通道:
SHOW RELAYLOG EVENTS
CHANGE REPLICATION SOURCE TO
SOURCE_POS_WAIT()
-
请注意,默认通道始终存在于单个源复制拓扑中,其中语句和函数的行为与以前版本的MySQL相同。
19.2.2.3 启动选项和复制通道
本节介绍了受添加复制通道的影响的启动选项。这些选项包括:
--log-replica-updates
:将副本接收的所有事务(甚至来自多个sources)写入二进制日志中。--relay-log-purge
:设置后,每个通道都会自动清除自己的中继日志。--replica-transaction-retries
:指定的事务重试次数可以在所有通道的所有应用线程上使用。--skip-replica-start
:任何通道上都不会启动复制线程。--replica-skip-errors
:继续执行并跳过所有通道的错误。--max-relay-log-size=size
:每个中继日志文件的最大大小,达到此限制后将旋转文件。--relay-log-space-limit=size
:所有中继日志的总大小上限,对于每个单独的通道。对于N个通道,这些日志的总大小限制为relay_log_space_limit * N。--replica-parallel-workers=value
:每个通道的复制应用线程数。replica_checkpoint_group
:每个源的接收器线程的等待时间。--relay-log-index=filename
:每个通道的中继日志索引文件的基本名称。请参见第19.2.2.4节“复制通道命名约定”。--relay-log=filename
:表示每个通道的中继日志文件的基本名称。请参见第19.2.2.4节“复制通道命名约定”。--replica-net-timeout=N
:此值是按通道设置的,因此每个通道等待N秒以检查损坏连接。--replica-skip-counter=N
:此值是按通道设置的,因此每个通道从其源跳过N个事件。
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 复制线程
MySQL复制功能通过以下线程类型实现:
-
二进制日志转储线程:源服务器创建一个线程来发送二进制日志内容,当复制副本连接时,这些内容会被复制到该副本。此线程在SHOW PROCESSLIST的输出中标识为Binlog Dump。
-
复制I/O接收器线程:在副本服务器上发出START REPLICA语句时,副本将创建一个I/O(接收器)线程,它连接到源并要求它发送其二进制日志中记录的更新。
-
复制接收器线程:读取源的线程发送的内容(参见上一项),并将它们复制到副本的中继日志中。此线程的状态显示为SHOW REPLICA STATUS输出中的Slave_IO_running。
-
复制SQL应用程序线程:当replica_parallel_workers等于0时,副本将创建一个SQL(应用程序)线程,用于读取复制写入的中继日志并执行包含在其中的事务。当replica_parallel_workers大于等于1时,有N个应用线程和一个协调器线程,用于从中继日志中按顺序读取事务并将它们安排给工作线程应用。每个工作人员都应用协调器分配给它的事务。您可以通过将系统变量设置为大于0的值来为副本上的任务启用进一步的并行化。完成此操作后,副本将创建指定的工作线程数以应用事务,以及一个协调器线程,用于从中继日志中读取事务并将它们分配给工人。将replica_parallel_workers设置为大于0的值称为多线程副本。如果您正在使用多个复制通道,每个通道都将使用此变量指定的线程。
19.2.3.1 监视复制主线程
整理后的文本:
SHOW PROCESSLIST 语句提供信息,告诉您源和副本上有关复制的信息。有关源状态的信息,请参见第 10.14.4 节“复制源线程状态”。有关副本状态的信息,请参见第 10.14.5 节“复制 I/O(接收方)线程状态”和第 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 是为主连接的副本提供服务的线程。该信息表明,所有未完成的更新都已发送到副本,并且源正在等待更多要进行的更新。如果在源服务器上看不到此线程,则表示复制没有运行;也就是说,当前未连接任何副本。
在副本服务器上,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
该信息指示线程 10 是复制 I/O(接收方)线程,即与源服务器通信,线程 11 是正在处理存储在中继日志中的更新的复制 SQL(应用者)线程。在运行 SHOW PROCESSLIST 时,两个线程都处于空闲状态,等待进一步更新。
19.2.3.2 监视复制应用器工作线程
在一个多线程复制中,性能模式表replication_applier_status_by_coordinator和replication_applier_status_by_worker分别显示了复制的协调器线程和应用工作者线程的状态信息。对于一个具有多个通道的复制,每个通道的线程都被标识出来。
如果详细设置被设置为显示信息性消息,那么一个多线程复制的协调器线程也会定期将统计数据打印到复制的错误日志中。这些统计数据的打印取决于协调器线程分配给应用工作者线程的事件量,最大频率为每120秒一次。消息列出了相关复制通道(或默认复制通道,该通道没有名称)的以下统计数据:
- 经过的秒数:当前时间与上次此信息被打印到错误日志之间的秒数差。
- 已分配的事件:协调器线程自启动以来已排队到所有应用工作者线程的事件总数。
- 工人队列超过超限级别的填充情况:当前排队到任何应用工作者线程的事件数量超过了超限级别,该级别设定在16384事件的最大队列长度的90%。如果这个值为零,则没有应用工作者线程在其容量上限运行。
- 由于工人队列满而等待的次数:协调器线程因为一个应用工作者线程的队列已满而不得不等待调度事件的次数。如果这个值为零,则没有应用工作者线程耗尽其容量。
- 由于总大小而等待的次数:协调器线程因为已达到replica_pending_jobs_size_max限制而不得不等待调度事件的次数。这个系统变量设置了可用于尚未应用的应用工作者线程队列的最大内存量(以字节为单位)。如果一个异常大的事件超过了这个大小,事务会被保留,直到所有应用工作者线程的队列都为空,然后进行处理。所有后续事务都会被保留,直到大事务完成。
- 由于时钟冲突而等待的次数:协调器线程因为一个事件所依赖的事务尚未提交而不得不等待调度事件的次数(以纳秒计)。如果replica_parallel_type被设置为DATABASELOGICAL_CLOCK,则这个值总是零。
- 当工人占用时等待的次数(计数):协调器线程短暂休眠的次数,可能在两种情况下发生。第一种情况是协调器线程分配一个事件并发现应用工作者线程的队列填充超过了最大队列长度的10%的欠载级别,在这种情况下它会最多休眠1毫秒。第二种情况是replica_parallel_type被设置为LOGICAL_CLOCK且协调器线程需要将事务的第一个事件分配到一个应用工作者线程的队列,它只对一个空队列的工人这样做,所以如果没有队列是空的,协调器线程会休眠直到有一个变空。
- 当工人占用时等待的时间(以纳秒计):协调器线程在等待一个空的应用工作者线程队列时休眠的时间(即在上面描述的第二种情况,其中replica_parallel_type被设置为LOGICAL_CLOCK且需要分配事务的第一个事件)。
19.2.4 中继日志和复制元数据存储库
副本服务器创建了多个信息存储库,主要用于复制过程。这些存储库包括:
-
中继日志:通过复制 I/O(接收器)线程写入,包含从复制源服务器的二进制文件中读取的事务日志。中继日志中的事务由复制 SQL(applier)线程应用于副本。有关中继日志的详细信息,请参阅第 19.2.4.1 节“中继日志”。
-
连接元数据存储库:包含复制接收器线程需要连接到复制源服务器并从源的二进制日志中获取的信息。连接元数据存储库将写入表 mysql.slave_master_info。
-
应用程序元数据存储库:包含复制应用程序线程所需的信息,用于从副本的中继日志中读取和应用事务。应用程序元数据存储库将写入表 mysql.slave_relay_log_info。
连接元数据存储库和应用程序元数据存储库统称为复制元数据存储库。有关这些内容的详细信息,请参阅第 19.2.4.2 节“复制元数据存储库”。
为了确保复制能够灵活应对意外停止,将使用 InnoDB 事务存储引擎创建和使用表。对副本的 Applier 元数据存储库表进行的更新与事务一起进行,即副本的进度始终与已应用于数据库的内容保持一致,即使在服务器意外停止的情况下也是如此。有关在副本上对意外停止最具弹性的设置组合的信息,请参阅第 19.4.2 节“处理副本的意外停止”。
19.2.4.1 中继日志
中继日志与二进制日志类似,由一组编号文件和包含所有已用中继日志名称的索引文件组成。默认情况下,中继日志文件位于数据目录中。"中继日志文件"通常指单个编号文件,而"中继日志"则包括所有编号的中继日志文件及索引文件。
中继日志文件格式与二进制日志相同,可以使用mysqlbinlog工具读取。如果二进制日志事务使用压缩,中继日志也会以相同的方式压缩事务有效负载。
对于默认复制通道,中继日志文件名格式为host_name-relay-bin.nnnnnn,其中host_name是副本服务器主机,nnnnnn是序列号。非默认复制通道的文件名格式为host_name-relay-bin-channel。
副本使用索引文件来跟踪当前正在使用的中继日志文件。默认中继日志索引文件名为host_name-relay-bin.index,非默认复制通道则为host_name-relay-bin-channel.index。
可以通过relay_log和relay_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 LOGS或mysqladmin flush-logs命令时,以及当前中继日志文件大小过大时。复制SQL(应用者)线程会自动删除每个已执行完所有事件的中继日志文件且不再需要的日志文件。
19.2.4.2 复制元数据存储库
已为您整理好下文:
副本服务器创建两个复制元数据存储库,连接元数据存储库和应用元数据存储库。在副本服务器关闭时,复制元数据存储库也会关闭。当基于二进制日志文件位置的复制正在使用时,如果副本重新启动,它会读取两个存储库以确定其之前从源读取二进制日志的位置,并在处理自己的中继日志时继续前进。另一方面,如果基于GTID的复制正在使用中,则副本不会使用复制元数据存储库来为此目的,但它确实需要它们用于其他目的,包括它们包含的元数据。
连接元数据存储库包含的信息是复制I/O(接收器)线程需要连接到复制源服务器并从源的二进制日志中读取所需的信息。此存储库中的元数据包括连接配置、复制用户帐户详细信息、连接的SSL设置以及复制接收方当前从源的二进制日志中读取的文件名和位置。
应用元数据存储库包含复制SQL(应用者)线程需要读取和应用副本的中继日志中的事务的信息。此存储库中的元数据包括文件名和位置,最多到复制应用程序线程已执行的中继日志中的事务,以及等效位置和源的二进制日志中的位置。它还包含应用事务的过程,如工作线程和渠道。
警告消息可能会显示,如果mysqld无法初始化复制元数据存储库的表,但允许复制副本继续启动。这种情况最可能在从不支持将存储库的表用于它们的版本的MySQL升级时发生。
不要尝试手动更新或插入表中的行,这可能导致未定义的行为并且是不支持的。执行任何需要对其中一个或两个表进行写锁定的操作是不允许的,尽管在任何情况下都只允许执行只读取语句。
连接元数据存储库的访问权限应仅限于数据库管理员,因为它包含复制用户帐户名和密码,用于连接到源。使用受限访问模式保护包含此表的数据库备份。
RESET REPLICA清除复制元数据存储库,但复制连接参数取决于MySQL服务器的版本。有关详细信息,请参阅RESET REPLICA说明。
您可以设置CHANGE REPLICATION SOURCE TO语句的选项,以防止复制通道在复制元数据中持久化文件名和文件位置。这样可以避免写入和读取基于GTID的复制实际上不需要的情况。通过设置,连接元数据存储库和应用器元数据存储库在副本排队并应用事务时不会更新,或者当复制线程停止和开始时。它在内存中跟踪文件位置,并可以使用SHOW REPLICA STATUS查看(如果需要)。只有在以下情况下,复制元数据才会同步存储库:GTID_ONLY, CHANGE REPLICATION SOURCE TO, RESET REPLICA。
当发出RESET REPLICA ALL语句时,删除而不是更新存储库,因此它们是隐式同步的。在初始化复制通道时也是如此。如果复制元数据存储库从文件转换为表,创建为表是违约;不推荐使用文件。创建和应用元数据存储库表使用InnoDB事务存储引擎。对应用程序元数据存储库表的更新与事务一起提交,这意味着副本在其中记录的进度信息始终与应用于数据库的内容一致,即使在服务器意外停止的情况下。
当您备份副本的数据或传输数据以创建新的副本时,请确保包含复制元数据存储库。对于克隆操作,请注意,创建复制元数据存储库作为表时,它们在克隆过程中被复制到收件人操作中,但如果它们是文件,则不复制。当基于位置的二进制日志文件的复制处于使用时,需要恢复复制元数据存储库才能重新启动复制后还原、复制或克隆副本。如果没有中继日志文件,但仍有Applier元数据存储库,可以检查确定复制SQL线程在源的二进制日志中的位置。然后可以使用CHANGE REPLICATION SOURCE TO语句,其中包含告诉副本从该点重新读取源中的二进制日志的和选项(前提是所需的二进制日志仍然存在于源上)。
19.2.5 服务器如何评估复制过滤规则
在评估复制选项时,副本的开头是检查是否有任何 --replicate-do-db 或 --replicate-ignore-db 选项适用。使用 --binlog-do-db 或 --binlog-ignore-db 时,进程是相似的,但选项在源上被选中。
检查匹配项的数据库取决于二进制文件正在处理的语句的日志格式。如果语句已使用行格式记录,数据库要更改数据的位置是要检查的数据库。如果该语句已使用语句格式记录,该语句格式为默认数据库(使用 USE 语句指定)是数据库已选中。
注意:只能使用行格式记录 DML 语句。DDL的语句始终记录为语句,即使 binlog_format=ROW 也是如此。所有 DDL 因此,语句始终根据基于语句的复制规则。这意味着你必须使用 USE 语句显式选择默认数据库,以便要应用的 DDL 语句。
对于复制,下面列出了所涉及的步骤:
- 使用哪种日志记录格式?
- 测试默认数据库。
- 测试受更改影响的数据库。
- 是否有任何 --replicate-do-db 选项?
- 是的。数据库是否匹配其中任何一个?
- 是的。继续执行步骤 4。
- 不。忽略更新并退出。
- 不。继续执行步骤 3。
- 是的。数据库是否匹配其中任何一个?
- 是否有任何 --replicate-ignore-db 选项?
- 是的。数据库是否匹配其中任何一个?
- 是的。忽略更新并退出。
- 不。继续执行步骤 4。
- 不。继续执行步骤 4。
- 是的。数据库是否匹配其中任何一个?
如果有关这些选项的说明选中,请参见第 19.2.5.2 节 “表级复制选项的评估”。
重要:在此阶段仍允许的声明不是但实际上被执行了。该语句在以下情况下不会执行所有表级选项(如果有)也已选中,并且该过程的结果允许执行陈述。
对于二进制日志记录,下面列出了所涉及的步骤:
- 是否有任何 --binlog-do-db 或 --binlog-ignore-db 选项?
- 是的。继续执行步骤 2。
- 不。记录语句并退出。
- 是否有默认数据库(是否选择了任何数据库由 USE)?
- 是的。继续执行步骤 3。
- 不。忽略该语句并退出。
- 有一个默认数据库。是否有任何 --binlog-do-db 选项?
- 是的。它们中的任何一个与数据库匹配吗?
- 是的。记录语句并退出。
- 不。忽略该语句并退出。
- 不。继续执行步骤 4。
- 是的。它们中的任何一个与数据库匹配吗?
- 执行任何 --binlog-ignore-db 选项匹配数据库?
- 是的。忽略该语句并退出。
- 不。记录语句并退出。
重要:对于基于语句的日志记录,规则中会出现例外只是为 CREATE 提供的数据库,更改 DATABASE 和 DROP DATABASE 语句。在这些情况下,数据库在确定是否记录时,正在创建、更改或删除将替换默认数据库或忽略更新。
–binlog-do-db 有时可能意味着“忽略其他数据库”。例如,当使用基于语句的日志记录,仅使用 --binlog-do-db=sales 运行的服务器不会写入默认值的二进制日志语句 database 不同于 sales。使用时使用相同选项的基于行的日志记录,服务器仅记录日志那些更改中数据的更新。
19.2.5.1 数据库级复制和二进制日志记录选项的评估
副本仅在满足以下两个条件之一时检查和评估表选项:
- 未找到匹配的数据库选项。
- 找到一个或多个数据库选项,并对其进行了评估(根据第19.2.5.1节“数据库级复制和二进制日志记录选项的评估”中描述的规则)。
前提条件是副本检查是否启用了基于语句的复制。如果启用了基于行的复制,则副本不知道语句是否发生在存储函数中,因此此条件不适用。
对于基于语句的复制,复制事件表示单个SQL语句;对于基于行的复制,每个事件表示单个表行中的更改。当在事件项中检查表选项时,基于行的复制和基于语句的复制都遵循相同的过程。
如果没有表选项,则副本只执行所有事件。如果有 --replicate-do-table 或 --replicate-wild-do-table 选项,则事件必须与其中一个选项匹配才能执行;否则,它将被忽略。如果有 --replicate-ignore-table 或 --replicate-wild-ignore-table 选项,则执行所有事件,但与这些选项匹配的事件除外。
19.2.5.2 表级复制选项的评估
表级复制筛选器仅应用于在查询中显式提及并对其进行操作的表。它们不适用于由查询生成的表。例如,更新系统表但未提及该表的GRANT语句不受通配符模式的影响。
以下是评估过程的详细步骤:
-
是否有任何表复制选项?
- 是:继续执行步骤2。
- 否:执行更新并退出。
-
使用哪种日志记录格式?
- 陈述:对每个语句执行其余步骤以执行更新。
- 排:执行每次更新的其余步骤,针对表行。
-
是否有任何 --replicate-do-table 选项?
- 是:表格是否匹配其中任何一个?
- 是:执行更新并退出。
- 否:继续执行步骤4。
- 否:继续执行步骤4。
- 是:表格是否匹配其中任何一个?
-
是否有任何 --replicate-ignore-table 选项?
- 是:表格是否匹配其中任何一个?
- 是:忽略更新并退出。
- 否:继续执行步骤5。
- 否:继续执行步骤5。
- 是:表格是否匹配其中任何一个?
-
是否有任何 --replicate-wild-do-table 选项?
- 是:表格是否匹配其中任何一个?
- 是:执行更新并退出。
- 否:继续执行步骤6。
- 否:继续执行步骤6。
- 是:表格是否匹配其中任何一个?
-
是否有任何 --replicate-wild-ignore-table 选项?
- 是:表格是否匹配其中任何一个?
- 是:忽略更新并退出。
- 否:继续执行步骤7。
- 否:继续执行步骤7。
- 是:表格是否匹配其中任何一个?
-
还有另一个表要测试吗?
- 是:返回步骤3。
- 否:继续执行步骤8。
-
是否有任何 --replicate-do-table 或 --replicate-wild-do-table 选项?
- 是:忽略更新并退出。
- 否:执行更新并退出。
19.2.5.3 复制过滤选项之间的交互
整理后的文本:
复制筛选选项的效果因二进制日志记录格式的不同而异,因为数据库名称的确定方式不同。对于基于语句的格式,DML语句是根据USE语句指定的当前数据库进行处理的。而对于基于行的格式,DML语句是根据修改后的表所在的数据库进行处理的。始终过滤DDL语句,无论二进制日志记录格式如何,都是基于当前数据库,如USE语句所指定。
涉及多个表的操作也可能受到影响,具体取决于二进制日志记录格式。需要注意的操作包括涉及多表UPDATE语句、触发器、级联外键、更新多个表的存储函数和DML语句,用于调用存储函数更新一个或多个表。如果这些操作同时更新过滤表和过滤表,结果可能因二进制日志记录格式而有所不同。
如果需要保证复制筛选器正常运行,无论二进制日志记录格式如何,始终如一,特别是当使用混合二进制日志记录格式时(binlog_format=MIXED),仅使用表级复制筛选选项,并且不使用数据库级复制筛选选项。另外,不要使用更新筛选和筛选出的表。
如果需要结合使用数据库级和表级复制筛选器,并希望这些筛选器作为尽可能始终如一地选择以下选项之一的策略:
-
如果使用基于行的二进制日志记录格式(binlog_format=ROW),用于DDL语句,依靠USE语句来设置数据库,并且不指定数据库名称。可以考虑更改为基于行的二进制日志记录格式以改进复制筛选的一致性。
-
如果使用基于语句或混合二进制日志记录格式(binlog_format=STATEMENT 或 MIXED),对于DML和DDL语句,依赖USE语句和不使用数据库名称。此外,不要使用多表更新筛选输入和筛选输出的DML语句。
示例: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 TABLE在由前面的USE语句设置的数据库中创建表。副本根据其replicate-ignore-db = db1选项过滤掉此语句,因为当前数据库。无论二进制日志记录如何,此结果都是相同的。但是,DML INSERT语句的结果因二进制日志记录格式而异:
-
如果源上使用基于行的二进制日志记录格式(binlog_format=ROW),则副本使用该表所在的数据库,命名为db2。因此,表级选项replicate-do-table = db2.t3确实适用,因此副本应用更改为表db2.t3。
-
如果基于语句的二进制日志记录格式正在源(binlog_format=STATEMENT)上使用,副本使用default数据库,该数据库由USE语句设置为且尚未更改。根据replicate-ignore-db = db1选项,它忽略了该操作,并且不会将更改应用于表db2.t3。这导致表级选项replicate-do-table = db2.t3未被选中,因为语句已匹配数据库级选项,但被忽略。
19.2.5.4 基于复制通道的过滤器
复制筛选器和通道概述
在存在多个复制通道的情况下,例如在多源复制拓扑中,复制过滤器的应用方式如下:
-
任何指定的全局复制筛选器都将添加到全局复制筛选器中,如do_db、do_ignore_table等。
-
任何特定于通道的复制筛选器都会将筛选器添加到指定通道的复制过滤器中,指定的筛选器类型。
-
每个复制通道都会复制全局复制筛选器,如果没有通道,则到其特定于通道的复制过滤器配置了此类型的特定复制筛选器。
-
每个通道都使用其特定于通道的复制筛选器筛选复制流。
用于创建特定于通道的复制筛选器的语法扩展了现有的SQL语句和命令选项。未将复制通道指定为全局复制筛选器配置是为了确保向后兼容性。CHANGE REPLICATION FILTER语句支持在线配置特定于频道的过滤器。要配置的命令选项可以使用形式指定复制通道。
全局复制筛选器和通道特定过滤器的配置示例:
全局复制筛选器: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
在启动时配置特定于通道的复制筛选器,复制筛选器相关的命令选项可以采取可选通道后跟一个冒号,后跟过滤器规范。以下命令选项支持使用此功能的特定于通道的复制过滤器格式:
–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
除了选项之外,还可以使用CHANGE REPLICATION FILTER语句配置复制筛选器,这样就无需重新启动服务器,但复制SQL线程必须停止,同时进行更改。例如:
CHANGE REPLICATION FILTER REPLICATE_DO_DB=(db1) FOR CHANNEL channel_1;
当提供子句时,语句作用于指定通道的复制过滤器。如果多种类型的过滤器(如do_db、do_ignore_table等)被指定,只有指定的筛选器类型被语句替换。
删除特定于通道的复制筛选器
当特定于通道的复制筛选器配置后,您可以通过发出空filter type语句来删除它。例如,要从名为channel_1的复制通道中删除REPLICATE_REWRITE_DB:
CHANGE REPLICATION FILTER REPLICATE_REWRITE_DB=() FOR CHANNEL channel_1;
任何以前使用命令选项或CHANGE REPLICATION FILTER配置的过滤器将被删除。重新创建已删除的一个或多个频道时,为副本指定的任何全局复制筛选器都将复制到它们,并且没有特定于通道的复制过滤器应用。