MySQL
MySQL安装升级
MySQL RPM包安装参考
MySQL编译化安装参考
MySQL Server版本升级
MySQL 操作手册/说明
MySQL主从配置
MySQL Slave状态参数详解
MySQL导入导出操作
库,表,字段的字符集修改方法
根据字段生成自定义SQL语句
MySQL查询流程概述
MySQL 常用脚本
MySQL数据库冷备脚本
MySQL内存占用分析
MySQL内存消耗分析
检查MySQL引起的高内存占用
InnoDB下的内存分析和优化计算
MySQL常见问题
MySQL告警:Aborted connection日志的分析
MySQL使用命令kill进程后出现killed死锁问题
从库重起初始化relaylog失败
MySQL性能优化
MySQL查询慢性能分析
本文档使用 MrDoc 发布
-
+
home page
MySQL主从配置
复制使数据从一台 MySQL 数据库服务器(源)复制到一台或多台 MySQL 数据库服务器(副本)。默认情况下复制是异步的;副本不需要永久连接以从源接收更新。根据配置,您可以复制所有数据库、选定数据库,甚至是数据库中选定的表。 **MySQL 中复制的优点包括:** 横向扩展解决方案 - 在多个副本之间分散负载以提高性能。在此环境中,所有写入和更新都必须在复制源服务器上进行。然而,读取可能发生在一个或多个副本上。该模型可以提高写入性能(因为源专用于更新),同时显着提高越来越多的副本的读取速度。 - **数据安全——因为数据被复制到副本,并且副本可以暂停复制过程,所以可以在副本上运行备份服务而不会破坏相应的源数据。** - **分析 - 可以在源上创建实时数据,而信息分析可以在副本上进行,而不会影响源的性能。** - **远程数据分发 - 您可以使用复制创建本地数据副本供远程站点使用,而无需永久访问源。** 有关如何在此类场景中使用复制的信息,请参阅 第 16.3 节 “复制解决方案”。 MySQL 5.7 支持不同的复制方法。传统的方法是基于从源的二进制日志中复制事件,并且需要在源和副本之间同步日志文件和其中的位置。基于全局事务标识符(GTID)的较新方法是事务性的,因此不需要处理日志文件或这些文件中的位置,这大大简化了许多常见的复制任务。只要在源上提交的所有事务也已应用到副本上,使用 GTID 的复制就可以保证源和副本之间的一致性。有关 MySQL 中 GTID 和基于 GTID 的复制的更多信息,请参阅 第 16.1.3 节,“使用全局事务标识符进行复制”。有关使用基于二进制日志文件位置的复制的信息,请参阅 第 16.1 节,“配置复制”。 MySQL 中的复制支持不同类型的同步。最初的同步类型是单向异步复制,其中一台服务器充当源,而一台或多台其他服务器充当副本。这与作为 NDB Cluster 特征的同步复制形成对比 (请参阅第 20 章,MySQL NDB Cluster 7.5 和 NDB Cluster 7.6)。在 MySQL 5.7 中,除了内置的异步复制之外,还支持半同步复制。使用半同步复制,在返回到执行事务的会话之前对源块执行提交,直到至少一个副本确认它已接收并记录事务的事件;请参阅 第 16.3.9 节,“半同步复制”。MySQL 5.7 还支持延迟复制,以便副本故意落后于源至少指定的时间;请参阅 第 16.3.10 节,“延迟复制”。对于需要同步复制的场景 ,使用 NDB Cluster(见第 20 章,MySQL NDB Cluster 7.5 和 NDB Cluster 7.6)。 有许多解决方案可用于在服务器之间设置复制,使用的最佳方法取决于数据的存在和您使用的引擎类型。有关可用选项的更多信息,请参阅第 16.1.2 节,“设置基于二进制日志文件位置的复制”。 有两种核心类型的复制格式,基于语句的复制 (SBR),它复制整个 SQL 语句,以及基于行的复制 (RBR),它只复制更改的行。您还可以使用第三种类型,即基于混合的复制 (MBR)。有关不同复制格式的更多信息,请参阅 第 16.2.1 节,“复制格式”。 复制是通过许多不同的选项和变量来控制的。有关更多信息,请参阅 第 16.1.6 节,“复制和二进制日志记录选项和变量”。 您可以使用复制来解决许多不同的问题,包括性能、支持不同数据库的备份,以及作为减轻系统故障的更大解决方案的一部分。有关如何解决这些问题的信息,请参阅 第 16.3 节 “复制解决方案”。 有关复制期间如何处理不同数据类型和语句的注意事项和提示,包括复制功能、版本兼容性、升级和潜在问题及其解决方案的详细信息,请参见第 16.4 节 “复制注意事项和提示”。有关 MySQL 复制新手经常问到的一些问题的答案,请参阅第 A.14 节,“MySQL 5.7 常见问题:复制”。 有关复制的实现、复制如何工作、二进制日志的过程和内容、后台线程以及用于决定如何记录和复制语句的规则的详细信息,请参阅 第 16.2 节,“复制实现”。 ------------ ## 16.1 配置复制 > 16.1.1 基于二进制日志文件位置的复制配置概述 16.1.2 设置基于二进制日志文件位置的复制 16.1.3 使用全局事务标识符复制 16.1.4 在线服务器上更改复制模式 16.1.5 MySQL 多源复制 16.1.6 复制和二进制日志选项和变量 16.1.7 常见的复制管理任务 本节介绍如何配置 MySQL 中可用的不同类型的复制,包括复制环境所需的设置和配置,包括创建新复制环境的分步说明。本节的主要组成部分是: 有关使用二进制日志文件位置设置两个或多个服务器进行复制的指南, 第 16.1.2 节“设置基于二进制日志文件位置的复制”处理服务器的配置并提供在源之间复制数据的方法和复制品。 有关使用 GTID 事务设置两个或更多服务器进行复制的指南,第 16.1.3 节“使用全局事务标识符进行复制”涉及服务器的配置。 二进制日志中的事件使用多种格式记录。这些被称为基于语句的复制 (SBR) 或基于行的复制 (RBR)。第三种类型,混合格式复制 (MIXED),在适当的时候自动使用 SBR 或 RBR 复制来利用 SBR 和 RBR 格式的优点。第 16.2.1 节“复制格式”中讨论了不同的格式 。 第 16.1.6 节“复制和二进制日志记录选项和变量”中 提供了有关适用于复制的不同配置选项和变量的详细信息 。 一旦开始,复制过程应该几乎不需要管理或监控。但是,有关您可能想要执行的常见任务的建议,请参阅 第 16.1.7 节,“常见复制管理任务”。 ### 16.1.1 基于二进制日志文件位置的复制配置概述 本节介绍基于二进制日志文件位置方法的 MySQL 服务器之间的复制,其中作为源(数据库更改的源)运行的 MySQL 实例将更新和更改作为“事件”写入二进制日志。根据记录的数据库更改,二进制日志中的信息以不同的日志格式存储。副本配置为从源读取二进制日志并在副本的本地数据库上执行二进制日志中的事件。 每个副本都会收到一份二进制日志全部内容的副本。副本有责任决定应该执行二进制日志中的哪些语句。除非您另外指定,否则源二进制日志中的所有事件都在副本上执行。如果需要,您可以将副本配置为仅处理适用于特定数据库或表的事件。 > *重要: 您不能将源配置为仅记录某些事件。* 每个副本都会记录二进制日志坐标:它从源读取和处理的文件名和文件中的位置。这意味着多个副本可以连接到源并执行同一二进制日志的不同部分。由于副本控制此过程,因此单个副本可以与服务器连接和断开连接,而不会影响源的操作。此外,由于每个副本都记录了二进制日志中的当前位置,因此副本可能会断开连接,重新连接,然后继续处理。 源和每个副本必须配置一个唯一的 ID(使用`server_id`系统变量)。此外,每个副本都必须配置有关源主机名、日志文件名和该文件中位置的信息。可以使用`CHANGE MASTER TO`副本上的语句从 MySQL 会话中控制这些详细信息。详细信息存储在副本的连接元数据存储库中,它可以是文件或表(请参阅 第 16.2.4 节,“中继日志和复制元数据存储库”)。 ### 16.1.2 设置基于二进制日志文件位置的复制 > 16.1.2.1 设置复制源配置 16.1.2.2 创建复制用户 16.1.2.3 获取复制源的二进制日志坐标 16.1.2.4 选择数据快照的方法 16.1.2.5 设置副本 16.1.2.6 向复制拓扑添加副本 本节介绍如何设置 MySQL 服务器以使用基于二进制日志文件位置的复制。设置复制有多种不同的方法,使用的确切方法取决于您设置复制的方式以及源数据库中是否已有数据。 有一些通用任务对所有设置都是通用的: 在源上,您必须启用二进制日志记录并配置唯一的服务器 ID。这可能需要重新启动服务器。请参阅 第 节,“设置复制源配置”。 在要连接到源的每个副本上,您必须配置唯一的服务器 ID。这可能需要重新启动服务器。请参阅 第 16.1.2.5.1 节,“设置副本配置”。 或者,在读取二进制日志以进行复制时,为您的副本创建一个单独的用户,以便在对源进行身份验证期间使用。请参阅 第 16.1.2.2 节,“为复制创建用户”。 在创建数据快照或开始复制过程之前,您应该在源上记录二进制日志中的当前位置。配置副本时需要此信息,以便副本知道二进制日志中的何处开始执行事件。请参阅 第 16.1.2.3 节,“获取复制源的二进制日志坐标”。 如果您已经在源上有数据并希望使用它来同步副本,则需要创建数据快照以将数据复制到副本。您使用的存储引擎会影响您创建快照的方式。使用 时MyISAM,必须停止处理源上的语句以获取读锁,然后获取其当前二进制日志坐标并转储其数据,然后才能允许源继续执行语句。如果不停止语句的执行,数据转储和源的状态信息不匹配,导致副本上的数据库不一致或损坏。有关复制的更多信息 MyISAM源,请参阅 第 16.1.2.3 节,“获取复制源的二进制日志坐标”。如果您使用InnoDB,则不需要读锁,并且足够长的事务传输数据快照就足够了。有关更多信息,请参阅 第 14.20 节,“InnoDB 和 MySQL 复制”。 使用连接到源的设置配置副本,例如主机名、登录凭据以及二进制日志文件名和位置。请参阅 第 16.1.2.5.2 节,“在副本上设置源配置”。 > 说明: 设置过程中的某些步骤需要 SUPER特权。如果您没有此权限,则可能无法启用复制。 配置基本选项后,选择您的方案: 要为不包含数据的源和副本的全新安装设置复制,请参阅 第 16.1.2.5.3 节,“在新源和副本之间设置复制”。 要使用来自现有 MySQL 服务器的数据设置新源的复制,请参阅 第 16.1.2.5.4 节,“使用现有数据设置复制”。 要将副本添加到现有复制环境,请参阅 第 16.1.2.6 节,“将副本添加到复制拓扑”。 在管理 MySQL 复制服务器之前,请阅读整章并尝试第 13.4.1 节“控制复制源服务器的 SQL 语句”和 第 13.4.2 节“控制副本服务器的 SQL 语句”中提到的所有语句 。还要熟悉第 16.1.6 节,“复制和二进制日志记录选项和变量”中描述的复制启动选项 。 #### 16.1.2.1 设置复制源配置 要将源配置为使用基于二进制日志文件位置的复制,您必须确保启用二进制日志记录,并建立唯一的服务器 ID。 复制拓扑中的每个服务器都必须配置一个唯一的服务器 ID,您可以使用server_id系统变量指定该 ID 。此服务器 ID 用于标识复制拓扑中的各个服务器,并且必须是 1 和 (2 32 )-1之间的正整数。您可以server_id通过发出如下语句来动态更改该 值: ``` SET GLOBAL server_id = 2; ``` 默认服务器 ID 为 0 时,源拒绝来自副本的任何连接,副本拒绝连接到源,因此无法在复制拓扑中使用此值。除此之外,您可以选择如何组织和选择服务器 ID,只要每个服务器 ID 与复制拓扑中的任何其他服务器使用的每个其他服务器 ID 不同。 > 注意: 如果先前为服务器 ID 设置了值 0,则必须重新启动服务器以使用新的非零服务器 ID 初始化源。否则,不需要重新启动服务器,除非您需要启用二进制日志记录或进行其他需要重新启动的配置更改。 必须在源上启用 二进制日志记录,因为二进制日志是将更改从源复制到其副本的基础。如果使用该log-bin 选项在源上未启用二进制日志记录,则无法进行复制。要在尚未启用的服务器上启用二进制日志记录,您必须重新启动服务器。在这种情况下,关闭 MySQL 服务器并编辑 my.cnf或my.ini文件。在[mysqld]配置文件的部分中,添加`log-bin`和 `server-id`选项。如果这些选项已经存在,但已被注释掉,请取消注释这些选项并根据您的需要更改它们。例如,要使用日志文件名前缀启用二进制日志记录 mysql-bin,并将服务器 ID 配置为 1,请使用以下行: ``` [mysqld] log-bin=mysql-bin server-id=1 ``` 进行更改后,重新启动服务器。 说明: 以下选项会影响此过程: 为了在使用InnoDB事务的复制设置中获得最大可能的持久性和一致性 ,您应该在my.cnf的源文件中使用如下变量: ``` innodb_flush_log_at_trx_commit=1 sync_binlog=1 ``` 并且确保在源文件中未启用系统变量`skip_networking`。如果网络已禁用,副本将无法与源通信并且复制失败。 #### 16.1.2.2 创建复制用户 每个副本都使用 MySQL 用户名和密码连接到源,因此源上必须有一个用户帐户可用于副本连接。设置副本时,用户名由命令中的`MASTER_USER`选项指定`CHANGE MASTER TO`。任何帐户都可以用于此操作,前提是它已被授予`REPLICATION SLAVE` 特权。您可以选择为每个副本创建不同的帐户,或者为每个副本使用相同的帐户连接到源。 尽管您不必专门为复制创建帐户,但您应该知道复制用户名和密码以纯文本形式存储在复制元数据存储库中(请参阅 第 16.2.4.2 节,“复制元数据存储库”)。因此,您可能希望创建一个单独的帐户,该帐户仅具有复制过程的权限,以最大程度地减少其他帐户受到损害的可能性。 要创建新帐户,请使用`CREATE USER`。要授予此帐户复制所需的权限,请使用`GRANT` 语句。如果您仅以复制为目的的创建帐户,则该帐户只需要 `REPLICATION SLAVE`权限。例如,要设置一个repl可以从example.com域内的任何主机连接以进行复制的新用户 ,请在源上发出以下语句: ``` mysql> mysql>CREATE USER 'repl'@'%.example.com' IDENTIFIED BY 'password';GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.example.com'; ``` 有关操作用户帐户的语句的更多信息,请参阅第 13.7.1 节,“帐户管理语句”。 #### 16.1.2.3 获取复制源的二进制日志坐标 要将副本配置为在正确的点开始复制过程,您需要在其二进制日志中记录源的当前坐标。 > 警告: 此过程使用FLUSH TABLES WITH READ LOCK,它会阻止 COMMIT对InnoDB表的操作。 如果您计划关闭源以创建数据快照,您可以选择跳过此过程,而是将二进制日志索引文件的副本与数据快照一起存储。在这种情况下,源会在重新启动时创建一个新的二进制日志文件。因此,副本必须开始复制过程的源二进制日志坐标是该新文件的开始,它是源上的下一个二进制日志文件,紧随复制的二进制日志索引文件中列出的文件之后。 要获取源的二进制日志坐标,请执行以下步骤: 通过使用命令行客户端连接到源,在源上启动会话,并通过执行以下语句刷新所有表并阻止写入语句: ``` mysql> FLUSH TABLES WITH READ LOCK; ``` > 警告 让您从中发出FLUSH TABLES语句的客户端保持 运行状态,以便读取锁定保持有效。如果退出客户端,则锁定被释放。 在源上的不同会话中,使用该 `SHOW MASTER STATUS`语句来确定当前的二进制日志文件名和位置: ``` mysql > SHOW MASTER STATUS; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000003 | 73 | test | manual,mysql | +------------------+----------+--------------+------------------+ ``` 该File列显示日志文件的名称,该列显示文件Position中的位置。在这个例子中,二进制日志文件是mysql-bin.000003,位置是 73。记录这些值。稍后在设置副本时需要它们。它们表示副本应开始处理来自源的新更新的复制坐标。 如果源之前在未启用二进制日志记录的情况下运行,则`SHOW MASTER STATUS`或`mysqldump --master-data`显示的日志文件名和位置值为空。在这种情况下,您稍后在指定源的日志文件和位置时需要使用的值为空字符串 ( '') 和4。 您现在拥有了启用副本所需的信息,以便在正确的位置从二进制日志开始读取以开始复制。 下一步取决于您是否有源上的现有数据。选择以下选项之一: 如果您的现有数据需要在开始复制之前与副本同步,请让客户端保持运行状态,以便锁定保持原位。这可以防止进行任何进一步的更改,以便复制到副本的数据与源同步。继续 第 16.1.2.4 节,“选择数据快照的方法”。 如果您正在设置新的复制拓扑,您可以退出第一个会话以释放读锁。有关如何继续的信息,请参阅 第 16.1.2.5.3 节,“在新源和副本之间设置复制”。 #### 16.1.2.4 选择数据快照的方法 如果源上的数据库包含现有数据,则需要将此数据复制到每个副本。有多种方法可以从源转储数据。以下部分描述了可能的选项。 要选择转储数据库的适当方法,请在以下选项中进行选择: 使用mysqldump工具创建要复制的所有数据库的转储。这是推荐的方法,尤其是在使用 InnoDB. 如果您的数据库存储在二进制可移植文件中,您可以将原始数据文件复制到副本。这比使用mysqldump并在每个副本上导入文件更有效,因为它会INSERT在重播语句时跳过更新索引的开销 。InnoDB 不推荐使用这样的存储引擎。 ##### 16.1.2.4.1 使用 mysqldump 创建数据快照 要在现有源中创建数据的快照,请使用mysqldump工具。完成数据转储后,在开始复制过程之前将此数据导入副本。 以下示例将所有数据库转储到名为dbdump.db的文件中,并包括`--master-data`自动附加副本所需的`CHANGE MASTER TO`语句以启动复制过程的选项: ``` shell> mysqldump --all-databases --master-data > dbdump.db ``` > 说明: 如果不使用 --master-data,则需要手动锁定单独会话中的所有表。请参阅第 16.1.2.3 节,“获取复制源的二进制日志坐标”。 可以使用mysqldump工具从转储中排除某些数据库。如果要选择包含在转储中的数据库,请不要使用`--all-databases`. 选择以下选项之一: 使用`--ignore-table`选项排除数据库中的所有表 。 仅命名要使用该`--databases`选项转储的那些数据库 。 有关更多信息,请参阅第 4.5.4 节,“ mysqldump — 数据库备份程序”。 要导入数据,请将转储文件复制到副本,或者在远程连接到副本时从源访问文件。 ##### 16.1.2.4.2 使用原始数据文件创建数据快照 本节介绍如何使用构成数据库的原始文件创建数据快照。对使用具有复杂缓存或日志算法的存储引擎的表使用此方法需要额外的步骤来生成完美的“时间点”快照:初始复制命令可能会遗漏缓存信息和日志更新,即使您已获得全局读锁。存储引擎如何对此做出响应取决于其崩溃恢复能力。 如果使用InnoDB表,则可以使用MySQL Enterprise Backup 组件中的`mysqlbackup`命令来生成一致的快照。此命令记录与要在副本上使用的快照对应的日志名称和偏移量。MySQL Enterprise Backup 是作为 MySQL Enterprise 订阅的一部分包含的商业产品。有关详细信息,请参阅 第 27.2 节,“MySQL 企业备份概述”。 如果源和副本中的`ft_stopword_file`, `ft_min_word_len`或者 `ft_max_word_len`的配置值不同,而且你复制的表具有全文索引,则此方法也无法可靠地工作。 假设上述例外不适用于您的数据库,请使用冷备份 技术获取InnoDB表的可靠二进制快照 : 优雅关闭MySQL服务器,然后手动复制数据文件。 当 MySQL 数据文件存在于单个文件系统上时,要创建 MyISAM 表的原始数据快照,您可以使用标准文件复制工具(例如 cp 或 copy)、远程复制工具(例如 scp 或 rsync)、归档工具(例如 zip) 或 tar,或文件系统快照工具,例如 dump。 如果您仅复制某些数据库,请仅复制与这些表相关的文件。 对于 InnoDB,所有数据库中的所有表都存储在系统表空间文件中,除非您启用了 `innodb_file_per_table` 选项。 复制不需要以下文件: - 与mysql数据库相关的文件。 - 副本的连接元数据存储库文件(如果使用)(请参阅第 16.2.4 节,“中继日志和复制元数据存储库”)。 - 源的二进制日志文件,二进制日志索引文件除外,如果您要使用它来定位副本的源二进制日志坐标。 - 任何中继日志文件。 根据您是否使用InnoDB 表,选择以下选项之一: 如果您正在使用InnoDB表,并且还要通过原始数据快照获得最一致的结果,请在此过程中关闭源服务器,如下所示: 获取读锁并获取源的状态。请参阅 第 16.1.2.3 节,“获取复制源的二进制日志坐标”。 在单独的会话中,关闭源服务器: ``` shell> mysqladmin shutdown ``` 制作 MySQL 数据文件的副本。以下示例显示了执行此操作的常用方法。您只需要选择其中之一: ``` shell>tar cf /tmp/db.tar ./datazip -r /tmp/db.zip ./datarsync --recursive ./data /tmp/dbdata ``` 重新启动源服务器。 如果您不使用InnoDB 表,您可以从源获取系统快照,而无需关闭服务器,如以下步骤所述: 获取读锁并获取源的状态。请参阅 第 16.1.2.3 节,“获取复制源的二进制日志坐标”。 制作 MySQL 数据文件的副本。以下示例显示了执行此操作的常用方法。您只需要选择其中之一: ``` shell>tar cf /tmp/db.tar ./datazip -r /tmp/db.zip ./datarsync --recursive ./data /tmp/dbdata ``` 在您获取读锁的客户端中,释放锁: ``` mysql> UNLOCK TABLES; ``` 创建数据库的存档或副本后,在开始复制过程之前将文件复制到每个副本。 #### 16.1.2.5 设置副本 以下部分描述了如何设置副本。在继续之前,请确保您拥有: 使用必要的配置属性配置源。请参阅 第 16.1.2.1 节,“设置复制源配置”。 获取源的状态信息,或在数据快照关闭期间制作的源二进制日志索引文件的副本。请参阅 第 16.1.2.3 节,“获取复制源的二进制日志坐标”。 在源上,释放读锁: ``` mysql> UNLOCK TABLES; ``` ##### 16.1.2.5.1 设置副本配置 每个副本必须有一个唯一的服务器 ID,由`server_id`系统变量指定 。如果您要设置多个副本,则每个副本都必须具有`server_id`与源和任何其他副本不同的唯一值。如果尚未设置副本的服务器 ID,或者当前值与您为源服务器或其他副本选择的值冲突,您必须更改它。默认 `server_id`值为 0,副本拒绝连接到源。 您可以server_id 通过发出如下语句来动态更改该值: ``` SET GLOBAL server_id = 21; ``` 如果server_id 之前设置了默认值 0,则必须重新启动服务器以使用新的非零服务器 ID 初始化副本。否则,更改服务器 ID 时不需要重新启动服务器,除非您进行其他需要它的配置更改。例如,如果在服务器上禁用了二进制日志记录,而您希望为副本启用它,则需要重新启动服务器才能启用此功能。 如果要关闭副本服务器,则可以编辑[mysqld]配置文件的 部分以指定唯一的服务器 ID。例如: ``` [mysqld] server-id=21 ``` 副本不需要启用二进制日志记录即可进行复制。但是,副本上的二进制日志意味着副本的二进制日志可用于数据备份和崩溃恢复。启用了二进制日志记录的副本也可以用作更复杂的复制拓扑的一部分。如果要在副本上启用二进制日志记录,请使用配置文件部分中`[mysqld]`配置下的`log-bin`选项 。需要重新启动服务器才能在以前未使用它的服务器上启动二进制日志记录。 ##### 16.1.2.5.2 在副本上设置源配置 要将副本设置为与复制源通信,请使用必要的连接信息配置副本。为此,请在副本上执行以下语句,将选项值替换为与您的系统相关的实际值: ``` mysql> CHANGE MASTER TO MASTER_HOST='ipaddress',MASTER_USER='username',MASTER_PASSWORD='userpassword',MASTER_LOG_FILE='log_file_name',MASTER_LOG_POS=log_position; ``` > 说明 主从复制不能使用 Unix 套接字文件。您必须能够使用 TCP/IP 连接到源 MySQL 服务器。 该`CHANGE MASTER TO`语句还有其他选项。例如,可以使用 SSL 设置安全复制。有关选项的完整列表以及有关字符串值选项的最大允许长度的信息,请参阅第 13.4.2.1 节,“CHANGE MASTER TO 语句”。 后续步骤取决于您是否有要导入副本的现有数据。有关更多信息,请参见 第 16.1.2.4 节,“选择数据快照的方法”。选择以下选项之一: 如果您没有要导入的数据库快照,请参阅 第 16.1.2.5.3 节,“在新源和副本之间设置复制”。 如果您有要导入的数据库快照,请参阅 第 16.1.2.5.4 节,“使用现有数据设置复制”。 ##### 16.1.2.5.3 在新源和副本之间设置复制 当没有要导入的先前数据库的快照时,将副本配置为从新源开始复制。 要在源和新副本之间设置复制: 启动副本并连接到它。 执行一条`CHANGE MASTER TO` 语句来设置源配置。请参阅 第 16.1.2.5.2 节,“在副本上设置源配置”。 在每个副本上执行这些设置步骤。 如果您正在设置新服务器,但有来自不同服务器的数据库的现有转储要加载到您的复制配置中,也可以使用此方法。通过将数据加载到新源,数据会自动复制到副本。 如果要使用来自不同现有数据库服务器的数据设置新的复制环境以创建新源,请在新源上运行从该服务器生成的转储文件。数据库更新会自动传播到副本: ``` shell> mysql -h master < fulldb.dump ``` ##### 16.1.2.5.4 使用现有数据设置复制 使用现有数据设置复制时,请在开始复制之前将快照从源传输到副本。将数据导入副本的过程取决于您在源上创建数据快照的方式。 选择以下选项之一: 如果您使用mysqldump: 使用该`--skip-slave-start`选项启动副本, 以便不启动复制。 导入转储文件: ``` shell> mysql < fulldb.dump ``` 如果您使用原始数据文件创建了快照: 将数据文件提取到副本的数据目录中。例如: ``` shell> tar xvf dbdump.tar ``` 您可能需要设置文件的权限和所有权,以便副本服务器可以访问和修改它们。 使用该`--skip-slave-start`选项启动副本, 以便不启动复制。 使用来自源的复制坐标配置副本。这告诉副本二进制日志文件和文件中复制需要开始的位置。此外,使用源的登录凭据和主机名配置副本。有关`CHANGE MASTER TO`所需语句的更多信息,请参阅 第 16.1.2.5.2 节,“在副本上设置源配置”。 启动复制线程: ``` mysql> START SLAVE; ``` 执行此过程后,副本将连接到源并复制自拍摄快照以来源上发生的任何更新。 如果`server_id`源的系统变量设置不正确,副本将无法连接到它。同样,如果您没有为副本正确设置`server_id` ,您会在副本的错误日志中收到以下错误: >Warning: You should set server-id to a non-0 value if master_host is set; we will force server id to 2, but this MySQL server will not act as a slave 如果由于任何其他原因无法复制,您还会在副本的错误日志中找到错误消息。 副本存储有关您在其连接元数据存储库中配置的源的信息。连接元数据存储库可以采用文件或表的形式,由`master_info_repository`系统变量的值设置决定 。当副本运行时 `master_info_repository=FILE`,两个文件存储在数据目录中,命名为 `master.info`和 `relay-log.info`。如果 `master_info_repository=TABLE` 相反,此信息将保存在mysql数据库的 `master_slave_info`表中。在任何一种情况下,都不要删除或编辑该文件或表。始终使用`CHANGE MASTER TO` 更改复制参数的语句。副本可以使用语句中指定的值自动更新状态文件。有关更多信息,请参阅第 16.2.4 节,“中继日志和复制元数据存储库”。 >说明 连接元数据存储库的内容会覆盖在命令行或 中指定的某些服务器选项my.cnf。有关更多详细信息,请参阅 第 16.1.6 节,“复制和二进制日志记录选项和变量”。 源的单个快照足以支持多个副本。要设置其他副本,请使用相同的源快照并按照刚才描述的过程的副本部分进行操作。 #### 16.1.2.6 向复制拓扑添加副本 您可以在不停止源服务器的情况下向现有复制配置添加另一个副本。为此,您可以通过复制现有副本的数据目录并为新副本提供不同的服务器 ID(由用户指定)和服务器 UUID(在启动时生成)来设置新副本。 要复制现有副本: 停止现有副本并记录副本状态信息,特别是源的二进制日志文件和中继日志文件位置。您可以在 Performance Schema 复制表中查看副本状态(请参阅 第 24.12.11 节,“Performance Schema 复制表”),或通过发出`SHOW SLAVE STATUS` 如下命令: ``` mysql> STOP SLAVE; mysql>SHOW SLAVE STATUS\G ``` 关闭现有副本: ``` shell> mysqladmin shutdown ``` 将数据目录从现有副本复制到新副本,包括日志文件和中继日志文件。您可以通过使用tar或来创建存档 WinZip,或者使用诸如cp或rsync 之类的工具执行直接复制来完成此操作 。 >重要说明: 在复制之前,请确认与现有副本相关的所有文件实际上都存储在数据目录中。例如,InnoDB 系统表空间、撤消表空间和重做日志可能存储在其他位置。 InnoDB表空间文件和每个表文件的表空间可能已在其他目录中创建。副本的二进制日志和中继日志可能位于数据目录之外的它们自己的目录中。检查为现有副本设置的系统变量并查找已指定的任何替代路径。如果你找到了,也复制这些目录。 在复制期间,如果文件已用于复制元数据存储库(请参阅 第 16.2.4 节,“中继日志和复制元数据存储库”),这是 MySQL 5.7 中的默认值,请确保您还将这些文件从现有副本复制到新副本。如果表已用于存储库,则表位于数据目录中。 复制后,从新副本上的数据目录副本中删除该`auto.cnf`文件,以便新副本以不同的生成服务器UUID启动。服务器 UUID 必须是唯一的。 添加新副本时遇到的一个常见问题是新副本失败并显示一系列警告和错误消息,如下所示: ``` 071118 16:44:10 [Warning] Neither --relay-log nor --relay-log-index were used; so replication may break when this MySQL server acts as a slave and has his hostname changed!! Please use '--relay-log=new_replica_hostname-relay-bin' to avoid this problem. 071118 16:44:10 [ERROR] Failed to open the relay log './old_replica_hostname-relay-bin.003525' (relay_log_pos 22940879) 071118 16:44:10 [ERROR] Could not find target log during relay log initialization 071118 16:44:10 [ERROR] Failed to initialize the master info structure ``` 如果`relay_log`未指定系统变量,则会发生这种情况 ,因为中继日志文件包含主机名作为其文件名的一部分。如果`relay_log_index`未使用系统变量,则中继日志索引文件也是如此 。有关这些变量的更多信息,请参阅第 16.1.6 节,“复制和二进制日志记录选项和变量”。 为避免此问题,请`relay_log`在现有副本上使用的新副本上使用相同的值 。如果未在现有副本上明确设置此选项,请使用 `existing_replica_hostname-relay-bin`. 如果这不可能,请将现有副本的中继日志索引文件复制到新副本,并在新副本上设置 `relay_log_index`系统变量以匹配现有副本上使用的内容。如果未在现有副本上明确设置此选项,请使用 `existing_replica_hostname-relay-bin.index`. 或者,如果您在执行本节中的剩余步骤后已尝试启动新副本,并且遇到了与前面所述类似的错误,请执行以下步骤: 如果您还没有这样做,请`STOP SLAVE`在新副本上发出问题 。 如果您已经再次启动现有副本,也请`STOP SLAVE`对现有副本发出问题。 将现有副本的中继日志索引文件的内容复制到新副本的中继日志索引文件中,确保覆盖文件中已有的任何内容。 继续执行本节中的其余步骤。 复制完成后,重新启动现有副本。 在新副本上,编辑配置并为新副本提供一个唯一的服务器 ID(使用`server_id`系统变量),源或任何现有副本均未使用该 ID 。 启动新的副本服务器,指定` --skip-slave-start`选项以便复制尚未启动。使用 Performance Schema 复制表或问题`SHOW SLAVE STATUS`来确认新副本与现有副本相比具有正确的设置。还显示服务器 ID 和服务器 UUID,并验证这些对于新副本是否正确且唯一。 通过发出一条`START SLAVE`语句来启动复制线程 : ``` mysql> START SLAVE; ``` 新副本现在使用其连接元数据存储库中的信息来启动复制过程。 ### 16.1.3 使用全局事务标识符复制 > 16.1.3.1 GTID 格式和存储 16.1.3.2 GTID 生命周期 16.1.3.3 GTID 自动定位 16.1.3.4 使用 GTID 设置复制 16.1.3.5 使用 GTID 进行故障转移和横向扩展 16.1.3.6 使用 GTID 进行复制的限制 16.1.3.7 用于操作 GTID 的存储函数示例 本节解释使用全局事务标识符的基于事务的复制 (GTID)。使用 GTID 时,可以识别和跟踪每个事务,因为它在原始服务器上提交并被任何副本应用;这意味着在启动新副本或故障转移到新源时,无需使用 GTID 来引用日志文件或这些文件中的位置,这大大简化了这些任务。因为基于GTID的复制完全是基于事务的,所以很容易判断源和副本是否一致;只要在源上提交的所有事务也在副本上提交,就可以保证两者之间的一致性。您可以将基于语句或基于行的复制与 GTID 一起使用(请参阅第 16.2.1 节,“复制格式”); 但是,为了获得最佳结果,我们建议您使用基于行的格式。 GTID 始终保留在源和副本之间。这意味着您始终可以通过检查其二进制日志来确定应用于任何副本的任何事务的来源。此外,一旦在给定服务器上提交具有给定 GTID 的事务,该服务器将忽略具有相同 GTID 的任何后续事务。因此,在源上提交的事务只能在副本上应用一次,这有助于保证一致性。 本节讨论以下主题: - 如何定义和创建 GTID,以及它们在 MySQL 服务器中的表示方式(请参阅 第 16.1.3.1 节,“GTID 格式和存储”)。 - GTID 的生命周期(参见 第 16.1.3.2 节,“GTID 生命周期”)。 - 用于同步使用 GTID 的副本和源的自动定位功能(请参阅 第 16.1.3.3 节,“GTID 自动定位”)。 - 设置和启动基于 GTID 的复制的一般过程(请参阅第 16.1.3.4 节,“使用 GTID 设置复制”)。 - 使用 GTID 时配置新复制服务器的建议方法(请参阅第 16.1.3.5 节,“使用 GTID 进行故障转移和扩展”)。 - 使用基于 GTID 的复制时应注意的限制和限制(请参阅第 16.1.3.6 节,“使用 GTID 进行复制的 限制”)。 - 可用于处理 GTID 的存储函数(请参阅 第 16.1.3.7 节,“操作 GTID 的存储函数示例”)。 有关与基于 GTID 的复制相关的 MySQL 服务器选项和变量的信息,请参阅 第 16.1.6.5 节,“全局事务 ID 系统变量”。另请参阅 第 12.19 节,“与全局事务标识符(GTID)一起使用的函数”,其中描述了 MySQL 5.7 支持的与 GTID 一起使用的 SQL 函数。 #### 16.1.3.1 GTID 格式和存储 全局事务标识符 (GTID) 是在源服务器(源)上创建并与提交的每个事务相关联的唯一标识符。此标识符不仅对于它起源的服务器是唯一的,而且对于给定复制拓扑中的所有服务器也是唯一的。 GTID 分配区分在源上提交的客户端事务和在副本上复制的复制事务。当客户端事务在源上提交时,它会被分配一个新的 GTID,前提是该事务已写入二进制日志。客户端事务保证具有单调增加的 GTID,生成的数字之间没有间隙。如果客户端事务未写入二进制日志(例如,因为事务被过滤掉,或者事务是只读的),则不会在源服务器上为其分配 GTID。 复制的事务保留与分配给源服务器上的事务相同的 GTID。GTID 在复制事务开始执行之前就存在,即使复制事务没有写入副本上的二进制日志,或者在副本上被过滤掉,GTID 也会持久化。MySQL 系统表mysql.gtid_executed用于保存在 MySQL 服务器上应用的所有事务的分配 GTID,但存储在当前活动的二进制日志文件中的那些事务除外。 GTID 的自动跳过功能意味着在源上提交的事务只能在副本上应用一次,这有助于保证一致性。一旦在给定服务器上提交了具有给定 GTID 的事务,该服务器将忽略执行具有相同 GTID 的后续事务的任何尝试。不会引发错误,并且不会执行事务中的任何语句。 如果具有给定 GTID 的事务已开始在服务器上执行,但尚未提交或回滚,则任何尝试在具有相同 GTID 块的服务器上启动并发事务。服务器既不开始执行并发事务,也不将控制权返回给客户端。一旦事务的第一次尝试提交或回滚,在同一 GTID 上阻塞的并发会话可能会继续进行。如果第一次尝试回滚,一个并发会话将继续尝试事务,并且在同一 GTID 上阻塞的任何其他并发会话保持阻塞状态。如果第一次尝试提交,所有并发会话将停止被阻塞,并自动跳过事务的所有语句。 GTID 表示为一对坐标,以冒号 ( :)分隔,如下所示: ``` GTID = source_id:transaction_id ``` 该`source_id`标识的原始服务器。通常,源的`server_uuid`用于此目的。`transaction_id`是通过在事务提交源上的顺序确定一个序列号。例如,要提交的第一个`transaction_id`为其1的事务 ,而要在同一原始服务器上提交的第十个事务分配`transaction_id`为 10。事务在 GTID 中不可能具有序列号0。例如,最初在具有 UUID 的服务器上提交的第 23 个事务 3E11FA47-71CA-11E1-9E33-C80AA9429562具有以下 GTID: ``` 3E11FA47-71CA-11E1-9E33-C80AA9429562:23 ``` 事务的 GTID 显示在mysqlbinlog的输出中 ,它用于标识 Performance Schema 复制状态表中的单个事务,例如, replication_applier_status_by_worker。gtid_next 系统变量 ( @@GLOBAL.gtid_next)存储的值是单个 GTID。 GTID 集 GTID 集是包含一个或多个单个 GTID 或 GTID 范围的集合。GTID 集以多种方式在 MySQL 服务器中使用。例如,gtid_executed和 gtid_purged系统变量存储的值 是 GTID 集。该START SLAVE 条款UNTIL SQL_BEFORE_GTIDS和 UNTIL SQL_AFTER_GTIDS可用于制作副本处理交易最多只在GTID集中的最后GTID后在GTID组第一GTID,或停止。内置函数GTID_SUBSET()和 GTID_SUBTRACT()需要 GTID 集作为输入。 来自同一服务器的一系列 GTID 可以合并为一个表达式,如下所示: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5 上面的例子表示第一至MySQL服务器,其上第五交易始发 server_uuid是 3E11FA47-71CA-11E1-9E33-C80AA9429562。来自同一服务器的多个单个 GTID 或 GTID 范围也可以包含在单个表达式中,GTID 或范围用冒号分隔,如下例所示: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49 一个 GTID 集可以包括单个 GTID 和 GTID 范围的任意组合,并且可以包括源自不同服务器的 GTID。此示例显示已应用来自多个源的事务的副本的gtid_executed系统变量 ( @@GLOBAL.gtid_executed) 中存储的 GTID 集 : 2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19 当从服务器变量返回 GTID 集时,UUID 按字母顺序排列,数字间隔按升序合并。 GTID 集的语法如下: gtid_set: uuid_set[, uuid_set] ... | '' uuid_set: uuid: interval[: interval]... uuid: hhhhhhhh- hhhh- hhhh- hhhh-hhhhhhhhhhhh h: [0-9|自动对焦] interval: n[- n] ( n>= 1) mysql.gtid_executed 表 GTID 存储在数据库中名为gtid_executed,的表 中 mysql。该表中的一行包含它所代表的每个 GTID 或一组 GTID,原始服务器的 UUID,以及该组的开始和结束事务 ID;对于仅引用单个 GTID 的行,这最后两个值是相同的。 该mysql.gtid_executed表是在安装或升级 MySQL 服务器时创建的(如果它不存在),使用CREATE TABLE 类似于此处显示的语句: 创建表 gtid_executed ( source_uuid CHAR(36) 非空, interval_start BIGINT(20) 非空, interval_end BIGINT(20) 非空, PRIMARY KEY (source_uuid, interval_start) ) 警告 与其他 MySQL 系统表一样,不要尝试自己创建或修改此表。 该mysql.gtid_executed表供 MySQL 服务器内部使用。它使副本能够在副本上禁用二进制日志记录时使用 GTID,并在二进制日志丢失时启用 GTID 状态的保留。请注意,mysql.gtid_executed 如果您发出RESET MASTER. GTIDs存储在mysql.gtid_executed 表中,只有当gtid_mode是 ON或ON_PERMISSIVE。存储 GTID 的点取决于二进制日志记录是启用还是禁用: 如果二进制日志被禁用(log_binis OFF),或者如果 log_slave_updates被禁用,服务器会将属于每个事务的 GTID 与表中的事务一起存储。此外,该表以用户可配置的速率定期压缩;有关更多信息,请参阅 mysql.gtid_executed 表压缩。此情况仅适用于禁用二进制日志记录或副本更新日志记录的副本。它不适用于复制源服务器,因为在源服务器上,必须启用二进制日志记录才能进行复制。 如果启用了二进制日志( log_binis ON),每当二进制日志轮换或服务器关闭时,服务器都会将所有写入前一个二进制日志的事务的 GTID 写入mysql.gtid_executed表中。这种情况适用于复制源服务器或启用了二进制日志记录的副本。 如果服务器意外停止,当前二进制日志文件中的 GTID 集不会保存在 mysql.gtid_executed表中。这些 GTID 在恢复期间从二进制日志文件添加到表中。例外情况是在服务器重新启动时未启用二进制日志记录。在这种情况下,服务器无法访问二进制日志文件来恢复 GTID,因此无法启动复制。 启用二进制日志记录时,该 mysql.gtid_executed表不会保存所有已执行事务的 GTID 的完整记录。该信息由gtid_executed系统变量的全局值提供 。始终使用 @@GLOBAL.gtid_executed在每次提交后更新的 来表示 MySQL 服务器的 GTID 状态,并且不查询 mysql.gtid_executed表。 mysql.gtid_executed 表压缩 随着时间的推移,该 mysql.gtid_executed表可能会充满许多行,这些行引用了源自同一服务器的各个 GTID,并且其事务 ID 构成一个范围,类似于此处显示的内容: +--------------------------------------+------------------------ ------+--------------+ | source_uuid | 间隔开始| 间隔结束| |--------------------------------------+--------- ------+--------------| | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 37 | | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 38 | 38 | | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 39 | 39 | | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40 | 40 | | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 41 | 41 | | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 42 | 42 | | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 43 | 43 | ... 为了节省空间,MySQL 服务器mysql.gtid_executed通过用跨越整个事务标识符间隔的单行替换每组这样的行来定期压缩 表,如下所示: +--------------------------------------+------------------------ ------+--------------+ | source_uuid | 间隔开始| 间隔结束| |--------------------------------------+--------- ------+--------------| | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 43 | ... 您可以通过设置gtid_executed_compression_period 系统变量来控制在压缩表之前允许经过的事务数,从而控制压缩率 。此变量的默认值为 1000,这意味着默认情况下,每 1000 个事务后执行表压缩。设置 gtid_executed_compression_period 为 0 将根本无法执行压缩,如果执行此操作,您应该准备好应对gtid_executed表可能需要的磁盘空间量的潜在大量增加 。 笔记 当启用二进制日志,价值 gtid_executed_compression_period 是不使用,并且 mysql.gtid_executed表上的每个二进制日志旋转压缩。 mysql.gtid_executed表的 压缩由名为 的专用前台线程执行 thread/sql/compress_gtid_table。此线程未列在 的输出中SHOW PROCESSLIST,但可以将其视为threads表中的一行 ,如下所示: mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G **************************** 1. 行 ******************** ******* THREAD_ID:26 名称:线程/sql/compress_gtid_table 类型:前景 PROCESSLIST_ID:1 PROCESSLIST_USER: NULL PROCESSLIST_HOST: NULL PROCESSLIST_DB: NULL PROCESSLIST_COMMAND:守护进程 PROCESSLIST_TIME:1509 PROCESSLIST_STATE:暂停 PROCESSLIST_INFO: NULL PARENT_THREAD_ID:1 角色:空 仪器仪表:是的 历史:是的 CONNECTION_TYPE: NULL THREAD_OS_ID:18677 的thread/sql/compress_gtid_table螺纹通常休眠,直到 gtid_executed_compression_period 交易已经被执行,那么唤醒到的执行压缩mysql.gtid_executed如前所述表。然后它会休眠直到发生另一个 gtid_executed_compression_period 事务,然后醒来再次执行压缩,无限期地重复这个循环。禁用二进制日志记录时将此值设置为 0 意味着线程始终处于睡眠状态并且永远不会唤醒。 16.1.3.2 GTID 生命周期 GTID 的生命周期包括以下步骤: 在复制源服务器上执行并提交事务。这个客户端事务被分配了一个由源的 UUID 和这个服务器上尚未使用的最小非零事务序列号组成的 GTID。GTID 被写入源的二进制日志(在日志中紧跟在事务本身之前)。如果客户端事务未写入二进制日志(例如,因为事务被过滤掉,或者事务是只读的),则不会为其分配 GTID。 如果为事务分配了 GTID,则 GTID 通过在事务开始时将其写入二进制日志(作为Gtid_log_event)在提交时以原子方式持久化 。每当二进制日志轮换或服务器关闭时,服务器都会将写入前一个二进制日志文件的所有事务的 GTID 写入 mysql.gtid_executed表中。 如果为事务分配了 GTID,则通过将 GTID 添加到gtid_executed系统变量 ( @@GLOBAL.gtid_executed) 中的一组 GTID 中,该 GTID 将非原子地(在事务提交后不久)外化。此 GTID 集包含所有已提交 GTID 事务集的表示,它在复制中用作表示服务器状态的令牌。启用二进制日志记录(根据源的要求),gtid_executed系统变量中的 GTID 集 是所应用事务的完整记录,但 mysql.gtid_executed表不是,因为最近的历史记录仍在当前的二进制日志文件中。 在将二进制日志数据传输到副本并存储在副本的中继日志中后(使用此过程的既定机制,请参阅 第 16.2 节,“复制实现”,了解详细信息),副本读取 GTID 并设置其gtid_next系统的值 变量作为此 GTID。这告诉副本必须使用此 GTID 记录下一个事务。重要的是要注意副本设置gtid_next在会话上下文中。 副本验证没有线程尚未获得 GTID 的所有权gtid_next以处理事务。通过首先读取和检查复制事务的 GTID,在处理事务本身之前,副本不仅保证没有具有此 GTID 的先前事务已应用于副本,而且还没有其他会话已读取此 GTID 但尚未提交相关事务。因此,如果多个客户端尝试同时应用同一个事务,服务器会通过只让其中一个执行来解决这个问题。该gtid_owned 系统变量(@@GLOBAL.gtid_owned) 副本显示当前正在使用的每个 GTID 以及拥有它的线程的 ID。如果 GTID 已经被使用,则不会引发错误,并且使用自动跳过功能来忽略事务。 如果尚未使用 GTID,则副本将应用复制的事务。由于 gtid_next设置为源已经分配的 GTID,副本不会尝试为该事务生成新的 GTID,而是使用存储在gtid_next. 如果在副本上启用了二进制日志记录,则 GTID 在提交时通过在事务开始时将其写入二进制日志(作为Gtid_log_event)以原子方式持久化 。每当二进制日志轮换或服务器关闭时,服务器都会将写入前一个二进制日志文件的所有事务的 GTID 写入 mysql.gtid_executed表中。 如果在副本上禁用了二进制日志记录,则 GTID 会通过将其直接写入mysql.gtid_executed表以原子方式持久化 。MySQL 在事务中附加一条语句以将 GTID 插入表中。在这种情况下,该 mysql.gtid_executed表是应用在副本上的事务的完整记录。请注意,在 MySQL 5.7 中,将 GTID 插入表的操作对于 DML 语句是原子的,但对于 DDL 语句不是原子的,因此如果在涉及 DDL 语句的事务后服务器意外退出,GTID 状态可能会变得不一致。从 MySQL 8.0 开始,DDL 语句和 DML 语句的操作都是原子的。 在副本上提交复制事务后不久,GTID 通过将其添加到副本的gtid_executed系统变量 ( @@GLOBAL.gtid_executed) 中的一组 GTID 以非原子方式外部化 。至于源,这个 GTID 集包含所有提交的 GTID 事务集的表示。如果在副本上禁用了二进制日志记录,则该 mysql.gtid_executed表也是应用在副本上的事务的完整记录。如果在副本上启用了二进制日志记录,这意味着某些 GTID 仅记录在二进制日志中,则gtid_executed系统变量中的 GTID 集是唯一完整的记录。 在源上完全过滤掉的客户端事务未分配 GTID,因此它们不会添加到gtid_executed系统变量中的事务集 或添加到mysql.gtid_executed表中。但是,在副本上完全过滤掉的复制事务的 GTID 会保留下来。如果在副本上启用了二进制日志记录,则过滤掉的事务将作为 aGtid_log_event后跟一个仅包含BEGINand COMMIT语句的空事务写入二进制日志。如果禁用二进制日志记录,则将过滤掉的事务的 GTID 写入mysql.gtid_executed表中。为过滤掉的事务保留 GTID 可确保 mysql.gtid_executedtable 和gtid_executed系统变量中的 GTID 集可以压缩。它还确保在副本重新连接到源时不会再次检索过滤掉的事务,如 第 16.1.3.3 节,“GTID 自动定位”中所述。 在多线程副本(带有 slave_parallel_workers > 0)上,事务可以并行应用,因此复制的事务可以无序提交(除非 slave_preserve_commit_order=1已设置)。发生这种情况时,gtid_executed系统变量中的 GTID集 包含多个 GTID 范围,它们之间存在间隙。(在源或单线程副本上,有单调增加的 GTID,数字之间没有间隙。)多线程副本上的间隙仅出现在最近应用的事务中,并且随着复制的进行而填充。当复制线程使用STOP SLAVE语句,应用正在进行的事务以填补间隙。在关闭(例如服务器故障)或使用 KILL语句停止复制线程的情况下,间隙可能仍然存在。 为哪些更改分配了 GTID? 典型的场景是服务器为提交的事务生成一个新的 GTID。但是,GTID 也可以分配给事务以外的其他更改,并且在某些情况下,单个事务可以分配多个 GTID。 写入二进制日志的每个数据库更改(DDL 或 DML)都会分配一个 GTID。这包括自动提交的更改,以及使用BEGIN和COMMIT或 START TRANSACTION语句提交的更改 。GTID 还分配给数据库和非表数据库对象(例如过程、函数、触发器、事件、视图、用户、角色或授权)的创建、更改或删除。 非事务性更新和事务性更新都分配有 GTID。此外,对于非事务性更新,如果在尝试写入二进制日志缓存时发生磁盘写入失败并因此在二进制日志中创建间隙,则为由此产生的事件日志事件分配一个 GTID。 当一个表被二进制日志中生成的语句自动删除时,会为该语句分配一个 GTID。当副本开始应用来自刚刚启动的源的事件,并且正在使用基于语句的复制 ( binlog_format=STATEMENT) 并且已打开临时表的用户会话断开连接时,临时表将自动删除。使用MEMORY存储引擎的表在服务器启动后第一次被访问时会被自动删除,因为在关闭期间行可能已经丢失。 当事务未写入原始服务器上的二进制日志时,服务器不会为其分配 GTID。这包括回滚的事务和在原始服务器上禁用二进制日志记录时执行的事务,无论是全局(--skip-log-bin 在服务器的配置中指定)还是针对会话 ( SET @@SESSION.sql_log_bin = 0)。这还包括使用基于行的复制时的无操作事务 ( binlog_format=ROW)。 XA 事务为事务XA PREPARE阶段和事务XA COMMIT或XA ROLLBACK阶段分配了单独的 GTID 。XA 事务是持久准备的,以便用户可以在发生故障时提交或回滚它们(在复制拓扑中可能包括故障转移到另一台服务器)。因此,事务的两部分是分开复制的,因此它们必须有自己的 GTID,即使回滚的非 XA 事务没有 GTID。 在以下特殊情况下,单个语句可以生成多个事务,因此会分配多个 GTID: 调用提交多个事务的存储过程。为过程提交的每个事务生成一个 GTID。 多表DROP TABLE 语句删除不同类型的表。 CREATE TABLE ... SELECT使用基于行的复制时会发出 一条 语句 ( binlog_format=ROW)。为CREATE TABLE操作生成一个 GTID,为行插入操作生成一个 GTID。 该gtid_next系统变量 默认情况下,对于在用户会话中提交的新事务,服务器会自动生成并分配一个新的 GTID。当事务应用于副本时,来自原始服务器的 GTID 将被保留。您可以通过设置gtid_next 系统变量的会话值来更改此行为: 当gtid_next设置为 AUTOMATIC,这是默认值,并且事务提交并写入二进制日志时,服务器会自动生成并分配一个新的 GTID。如果事务因其他原因回滚或未写入二进制日志,则服务器不会生成和分配 GTID。 如果您设置gtid_next为有效的 GTID(由 UUID 和交易序列号组成,以冒号分隔),则服务器会将该 GTID 分配给您的交易。gtid_executed即使事务未写入二进制日志或事务为空,也会分配并添加此 GTID 。 请注意,设置 gtid_next为特定 GTID 后,并且事务已提交或回滚,SET @@SESSION.gtid_next必须在任何其他语句之前发出显式语句。AUTOMATIC如果您不想显式分配更多GTID,您可以使用它来将 GTID 值设置回。 当复制应用程序线程应用复制事务时,它们使用此技术,@@SESSION.gtid_next显式设置 为在源服务器上分配的复制事务的 GTID。这意味着来自原始服务器的 GTID 被保留,而不是由副本生成和分配新的 GTID。这也意味着gtid_executed即使在副本上禁用了二进制日志记录或副本更新日志记录,或者当事务是无操作或在副本上被过滤掉时,GTID 也会添加到 副本上。 客户端可以通过@@SESSION.gtid_next在执行事务之前设置特定的 GTID来模拟复制的事务。mysqlbinlog使用此技术 生成二进制日志的转储,客户端可以重播该转储以保留 GTID。通过客户端提交的模拟复制事务完全等同于通过复制应用线程提交的复制事务,事后无法区分。 该gtid_purged系统变量 该集在GTIDs的 gtid_purged系统变量(@@GLOBAL.gtid_purged)包含所有已提交服务器上的交易GTIDs,但在任何服务器上的二进制日志文件不存在。 gtid_purged是 的子集 gtid_executed。以下类别的 GTID 位于 gtid_purged: 在副本上禁用二进制日志记录的情况下提交的复制事务的 GTID。 写入已清除的二进制日志文件的事务的 GTID。 由语句显式添加到集合中的 GTID SET @@GLOBAL.gtid_purged。 您可以更改 的值, gtid_purged以便在服务器上记录某个 GTID 集中的事务已被应用,尽管它们不存在于服务器上的任何二进制日志中。当您将 GTID 添加到 时 gtid_purged,它们也会添加到gtid_executed. 此操作的一个示例用例是当您在服务器上还原一个或多个数据库的备份时,但您没有包含服务器上事务的相关二进制日志。在 MySQL 5.7 中,您只能更改 gtid_purgedwhen gtid_executed(因此 gtid_purged)为空的值。有关如何执行此操作的详细信息,请参阅 的说明 gtid_purged。 gtid_executed和 gtid_purged系统变量中 的 GTID 集 在服务器启动时初始化。每个二进制日志文件都以 event 开头 Previous_gtids_log_event,它包含所有以前的二进制日志文件中的一组 GTID(由前面文件的 Previous_gtids_log_eventGTID 和Gtid_log_event前面文件本身中的 each 的 GTID 组成)。的内容 Previous_gtids_log_event在最早和最近的二进制日志文件来计算的 gtid_executed,并 gtid_purged套在服务器启动时: gtid_executed计算为 Previous_gtids_log_event最新二进制日志文件中的 GTID、该二进制日志文件中事务的 GTID 以及存储在mysql.gtid_executed表中的 GTID 的联合 。此 GTID 集包含gtid_purged服务器上已使用(或显式添加到)的所有 GTID ,无论它们当前是否在服务器上的二进制日志文件中。它不包括服务器上当前正在处理的事务的 GTID ( @@GLOBAL.gtid_owned)。 gtid_purged通过首先将Previous_gtids_log_event最新二进制日志文件中的 GTID 和该二进制日志文件中事务的 GTID相加来计算 。此步骤提供当前或曾经记录在服务器上的二进制日志中的一组 GTID ( gtids_in_binlog)。接下来,Previous_gtids_log_event最旧的二进制日志文件中的 GTID从 gtids_in_binlog. 此步骤提供当前记录在服务器上的二进制日志中的一组 GTID ( gtids_in_binlog_not_purged)。最后,gtids_in_binlog_not_purged减去 gtid_executed. 结果是服务器上已经使用过但当前没有记录在服务器上的二进制日志文件中的一组GTID,这个结果用于初始化 gtid_purged. 如果这些计算中涉及 MySQL 5.7.7 或更早版本的二进制日志,则可能会为gtid_executed和 计算错误的 GTID 集gtid_purged,并且即使稍后重新启动服务器,它们仍然不正确。有关详细信息,请参阅binlog_gtid_simple_recovery 系统变量的描述,该 变量控制如何迭代二进制日志以计算 GTID 集。如果那里描述的情况之一适用于服务器,请设置 binlog_gtid_simple_recovery=FALSE 在启动它之前在服务器的配置文件中。该设置使服务器迭代所有二进制日志文件(不仅仅是最新的和最旧的)以查找 GTID 事件开始出现的位置。如果服务器有大量没有 GTID 事件的二进制日志文件,则此过程可能需要很长时间。 重置 GTID 执行历史 如果您需要重置服务器上的 GTID 执行历史记录,请使用该RESET MASTER语句。例如,您可能需要在执行测试查询以验证启用 GTID 的新服务器上的复制设置后执行此操作,或者当您想将新服务器加入复制组但它包含一些不被接受的不需要的本地事务时执行此操作通过组复制。 警告 RESET MASTER谨慎 使用以避免丢失任何想要的 GTID 执行历史记录和二进制日志文件。 发布前RESET MASTER,请确保您有服务器的二进制日志文件和二进制日志索引文件(如果有)的备份,并获取并保存gtid_executed系统变量全局值中保存的GTID集 (例如,通过发布SELECT @@GLOBAL.gtid_executed语句并保存结果)。如果要从该 GTID 集中删除不需要的事务,请使用mysqlbinlog检查事务的内容以确保它们没有价值,不包含必须保存或复制的数据,并且不会导致服务器上的数据更改。 当您发出 时RESET MASTER,将执行以下重置操作: 所述的值 gtid_purged系统变量被设置为空字符串('')。 gtid_executed系统变量 的全局值(但不是会话值) 设置为空字符串。 该mysql.gtid_executed表被清除(参见 mysql.gtid_executed Table)。 如果服务器启用了二进制日志,则删除现有的二进制日志文件并清除二进制日志索引文件。 请注意,RESET MASTER即使服务器是禁用二进制日志记录的副本,也是重置 GTID 执行历史记录的方法。 RESET SLAVE对 GTID 执行历史没有影响。
Nathan
Aug. 10, 2021, 6:37 p.m.
转发文档
Collection documents
Last
Next
手机扫码
Copy link
手机扫一扫转发分享
Copy link
本站将从https://wiki.netimed.cn
转移到
https://www.netimed.cn
,悉知!
联系邮箱:service@netimed.cn
Markdown文件
PDF文件
Docx文件
share
link
type
password
Update password