1.1. MySQL 复制
复制是 MySQL 的一项功能,允许服务器将更改从一个实例复制到另一个实例。 master 将所有数据和结构更改记录到二进制日志中。 slave 从 master 请求该二进制日志并在本地应用其内容。
1) MySQL 复制
MySQL 中的复制功能用于将更改从一个服务器( master )复制到一个或多个 slave 。 master 将更改写入二进制日志, slave 请求 master 的二进制文件并应用其内容。日志文件的格式影响 slave 应用更改的方式。 MySQL 支持基于语句的、基于行的以及混合格式的日志记录。
2) slave 数量
一个 master 的 slave 数量没有限制。但是,每个额外 slave 使用 master 上的较少资源,所以您应该仔细考虑生产设置中每个 slave 的好处。给定环境中 master 的最佳 slave 数量取决于许多因素:模式大小、写入次数、 master 和 slave的相对性能以及 CPU 和内存可用性等因素。一般准则是将每个 master 的 slave 数量限制为不超过 30 。
3) 网络故障
MySQL 中的复制功能在网络故障时继续工作。每个 slave 跟踪其已经处理了多少日志并在网络连接恢复时自动继续处理。此行为是自动的,不需要特殊配置。
1) 复制 master 和 slave
主 /slave 关系是一对多关系:
u 每个 slave 从一个 master 读取日志。
u 一个 master 可以将日志传送给许多 slave 。
u 一个 slave 可以用作另一个 slave 的 master 。
4) 中继 slave
一个 slave 可以用作另一个 slave 的 master 。最顶层 master 的直接 slave 请求并应用该 master 处发生的更改,而该slave 将更改向下中继到其 slave ,以此类推,直到复制到达该链的末尾。这样可以通过多个级别的复制来传播更新,允许更复杂的拓扑。每个额外级别会向系统添加更多传播延迟,从而较浅设置遇到的复制滞后要比较深设置少。每个 slave 仅能有一个 master ,一个 slave 不能从多个 master 进行复制。如果一个 slave 用作其他服务器的 master ,该 slave 常常称为中继 slave 。
5) 使用 BLACKHOLE 存储引擎进行复制
BLACKHOLE 存储引擎无提示地放弃所有数据更改,而不发出警告。二进制日志继续成功记录这些更改。当中继 slave将所有更改复制到深一层的 slave ,但是自身不需要将数据存储在特定表中时,将 BLACKHOLE 用于这些表。例如,如果您具有的中继 slave 单独用来对少量表执行经常长时间运行的业务智能报表,您可以将其他所有复制的表配置为使用BLACKHOLE ,从而服务器不会存储其不需要的数据,同时将所有更改复制到其 slave 。
2) 复杂拓扑
可以使用更复杂的拓扑:
u 双向拓扑具有两个 master ,每个 master 是另一个 master 的 slave 。
u 循环拓扑具有任意数量的服务器。每个服务器是一个 master 并且是另一个 master 的 slave 。对任何 master的更改将复制到所有 master 。
u 并非每个 slave 都必须是 master 。
MySQL 复制不执行冲突解析。
什么是冲突解析?在典型配置中,客户机仅将更改写入 master ,但是从任何服务器读取更改。在服务器允许对相似数据进行并发更新的环境中,数据在多个服务器上的最终状态可能变得不一致。应用程序负责防止或管理冲突操作。 MySQL复制不执行冲突解决解析。包括多个 master 的所有拓扑中都可能发生冲突。这包括诸如前面显示的简单分层结构(如果中继 slave 接受客户机的更改)。冲突在循环拓扑中特别常见。
例如,设想使用循环拓扑实现复制的电子商务公司,其中两个服务器分别处理“ Luxury Brands ”和“ Special Events”团队中的应用程序。假设应用程序不管理冲突操作,并且发生以下事件:
a) “ Luxury Brands ”团队将奢侈品的价格涨了 20% 。
b) “ Special Events ”团队因为将要来临的特殊节日将价格高于 500 美元的所有产品降了 50 美元。
c) 一个成本 520 美元的产品属于这两个类别,前面两个操作对其值进行了更新。每个服务器上产品的最终价格取决于每个服务器执行操作的顺序。
如果两个操作几乎同时发生,将发生以下操作:
a) “ Luxury Brands ”团队中的服务器将产品的价格增加 20% ,从 520 美元涨到 624 美元
b) “ Special Events ”团队中的服务器将产品价格减少 50 美元,从 520 美元降到 470 美元
c) 每个服务器将更改复制到另一个服务器,导致“ Luxury Brands ”服务器假设该产品的最终值为 574 美元,“ Special Events ”服务器假设最终值为 564 美元。
d) 复制环境中的其他服务器根据其应用操作的顺序假设最终值。
类似地,如果“ Luxury Brands ”团队添加一个新产品并且该产品在“ Special Events ”团队进行其更改时尚未完全复制,或者如果两个团队添加在不同服务器上具有相同主键的产品,则会出现冲突。虽然基于行的复制可以解决一些冲突,不过许多冲突仅能在应用程序级别被阻止。
注: MySQL Cluster 在内部使用复制,这在某些方面与 MySQL 服务器中的复制不同,并且提供冲突检测(和可选解析)。
3) 复制适用场景
复制适用场景:
l 水平向外扩展:实现复制的最常见原因是在一个或多个 slave 中分布查询工作负荷,从而提高整个应用程序中读取操作的性能,并通过减少 master 的读取工作负荷来提高其上的写入操作性能。请访问
http://dev.mysql.com/doc/refman/5.6/en/faqsreplication.html#qandaitem-B-13-1-8
查看关于如何通过使用向外扩展复制来提高系统性能的有用示例。
l 业务智能和分析:业务智能报表和分析处理会使用大量资源,需要大量时间来执行。在复制的环境中,可以在slave 上运行此类查询,从而 master 可以继续处理生产工作负荷,而不受长时间运行的 I/O 密集型报表的影响。
l 地理数据分布:具有分布式地理位置的公司可以受益于复制,在每个区域具有服务器,用于处理本地数据并在组织中复制该数据。这样可以向客户和员工提供地理相邻性的性能和管理优势,同时还使公司了解整个公司的数据。注:多源复制仅能通过循环拓扑间接进行。
4) 高可用性复制
复制适用于各种高可用性场景:
l 受控切换:在硬件或系统升级期间使用副本来代替生产服务器。
l 服务器冗余:在系统故障时执行故障转移到副本服务器。
l 联机模式更改:在具有多个服务器的环境中执行滚动升级来避免整个系统故障。
l 软件升级:在环境升级过程中在不同版本的 MySQL 之间进行复制。 slave 运行的版本必须比 master 新。在升级过程中发出的查询必须受升级过程中使用的所有版本的支持。
1.2. 配置复制
配置复制需要为每个服务器配置唯一 server-id ;复制拓扑中的每个服务器必须具有唯一的 server-id ,一个无符号的32 位整数,值从 (默认)到 4,294,967,295 。 server-id 为 0 的服务器(无论是 slave 还是 master )拒绝使用其他服务器进行复制。
1) master 配置:
a) 启用二进制日志和启用 TCP/IP 网络。
b) 创建具有 REPLICATION SLAVE 权限的新用户。
c) 备份主数据库,并且如果需要则记录日志坐标。
每个 master 必须分配有 IP 地址和 TCP 端口,因为复制无法使用 UNIX 套接字文件。每个 master 还必须启用二进制日志记录,因为在复制过程中,每个 master 将其日志内容发送到每个 slave 。每个 slave 必须登录到 master 中才能从中进行复制。如果您正由于此目的而在 master 上创建新用户,该新用户必须具有 REPLICATION SLAVE 权限:
GRANT REPLICATION SLAVE ON *.* TO
如果您正使用已经包含已填充数据库的 master 创建复制拓扑,必须首先为 slave 创建该数据库的副本(例如,通过执行 master 的备份并将该备份恢复到 slave )。如果您使用全局事务标识符 (Global Transaction Identifier, GTID) ,则不需要记录日志坐标。
2) slave 配置
a) 从 master 恢复备份。
b) 在每个 slave 上发出 CHANGE MASTER TO 语句,包含: master 的网络位置、复制帐户用户名和口令、开始复制操作的日志坐标(如果需要)
c) 使用 START SLAVE 开始复制。
每个 slave 仅连接到一个 master 。要告知 slave 关于 master 的信息,请使用 CHANGE MASTER TO... 语句。在slave 上发出 CHANGE MASTER TO … 语句来配置复制 master 连接详细信息:
mysql> CHANGE MASTER TO
-> MASTER_HOST = 'host_name',
-> MASTER_PORT = port_num,
-> MASTER_USER = 'user_name',
-> MASTER_PASSWORD = 'password',
-> MASTER_LOG_FILE = 'master_log_name',
-> MASTER_LOG_POS = master_log_pos;
CHANGE MASTER TO 的后续调用保留每个未指定选项的值,更改 master 的主机或端口还会重置日志坐标;以下语句更改口令,但是保留所有其他设置:
mysql> CHANGE MASTER TO MASTER_PASSWORD='newpass';
l MASTER_HOST 和 MASTER_PORT 值指定 master 的主机名和 TCP 端口号;
l MASTER_USER 和 MASTER_PASSWORD 值指定具有 REPLICATION SLAVE 权限的 master 上帐户的帐户详细信息。要提高安全性,还可以在启用 SSL 的服务器上使用 MASTER_SSL 和相关选项加密复制期间 slave 和master 之间的网络通信。
l MASTER_LOG_FILE 和 MASTER_LOG_POS 值包含 slave 开始进行复制的二进制日志位置的日志坐标。可以通过执行 SHOW MASTER STATUS 语句从 master 获取文件和位置:
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000014 | 51467 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
如果使用 mysqldump 执行 master 的数据库备份作为 slave 的起点,可以使用 --master-data 选项在备份中包括日志坐标:
mysqldump -uroot -p --master-data -B world_innodb > backup.sql
如果您使用 GTID ,则指定 MASTER_AUTO_POSITION=1 ,而不是日志坐标。
3) 使用 GTID 进行复制
使用 CHANGE MASTER TO... 启用 GTID 复制:
l 告知 slave 通过 GTID 标识事务:
CHANGE MASTER TO MASTER_AUTO_POSITION=1;
l 您不需要提供日志坐标,例如:
– MASTER_LOG_FILE
– MASTER_LOG_POS
l 不能在同一 CHANGE MASTER TO... 语句中提供 MASTER_AUTO_POSITION 和日志坐标。
启用基于 GTID 的复制时,不需要指定 master 的日志坐标,因为 slave 将 @@global.gtid_executed 的值发送给master 。因此, master 知道 slave 已经执行了哪些事务,从而仅发送 slave 尚未执行的那些事务。
1.3. 复制的故障转移
1) 使用日志坐标进行故障转移
要查找每个 slave 的新 master 和正确的日志坐标,必须严密检查二进制日志。
– 查找应用于每个 slave 的最近事件。
– 选择最新 slave 作为新的 master 。
– 确定新 master 上的日志坐标来匹配每个其他 slave 上最新应用的事件。
– 在每个 slave 上发出正确的 CHANGE MASTER TO …。
要在 master 变为不可用后进行故障转移,请停止所有 slave 并通过在其余 slave 上发出 CHANGE MASTER TO 语句(包含新 master 的日志坐标)选择某个 slave 作为 master 。如果进行故障转移时 slave 不是最新状态,您可能会具有不一致的复制拓扑:
l 如果新 master 位于特定 slave 后面(即,如果该 slave 已经应用了该新 master 的日志末尾的事件),则该slave 会重复那些事件。
l 如果新 master 在特定 slave 的前面(即,如果该新 master 的二进制日志包含该 slave 尚未应用的事件),该slave 将跳过那些事件。
要避免这种不一致,必须选择最新 slave 作为新 master ,然后在新 master 上查找与每个 slave 上的最近事件匹配的日志坐标。如果某些 slave 远在其他 slave 之后,则对于一个 slave 与下一个 slave 而言,在 CHANGE MASTER TO …语句中提供的日志坐标将有所不同,所以您不能在新 master 上仅发出 SHOW MASTER STATUS 。相反,必须检查二进制日志来查找正确的坐标。
在循环拓扑中,查找每个二进制日志中的事件源变得非常困难。
在多个 master 接受客户机更新的循环拓扑中,查找最新 slave 和确定正确日志坐标会非常困难,因为每个 slave 使用与其他 slave 不同的顺序应用操作。要避免此困难,请使用全局事务标识符 (Global Transaction Identifier, GTID) 。MySQL 实用程序还包括有助于使用 GTID 进行故障转移的工具。
2) 全局事务标识符 (Global Transaction Identifier, GTID)
GTID 唯一地标识复制的网络中的每个事务。
l 每个 GTID 的形式为
0ed18583-47fd-11e2-92f3-0019b944b7f7:338
l GTID 集包含一系列 GTID :
0ed18583-47fd-11e2-92f3-0019b944b7f7:1-338
l 使用以下选项启用 GTID 模式:
– gtid-mode=ON :与每个事务一起记录唯一的 GTID
– enforce-gtid-consistency :禁止无法以事务安全方式记录的事件
– log-slave-updates :将复制的事件记录到 slave 的二进制日志
源 UUID ( universally unique identifier ,通用唯一标识符)是每个事务的源服务器的 UUID 。每个服务器的 UUID 存储在数据目录中的 auto.cnf 文件中。如果该文件不存在, MySQL 会创建该文件并生成新的 UUID ,将其放在该新文件中。使用 server_uuid 变量查询服务器的 UUID :
mysql> SELECT @@server_uuid\G
*************************** 1. row ***************************
@@server_uuid: 0ed18583-47fd-11e2-92f3-0019b944b7f7
1 row in set (0.00 sec)
客户机在 master 上执行事务时, MySQL 将创建新 GTID 并记录事务及其唯一 GTID 。 slave 从 master 读取并应用该事务时,该事务保持其原始 GTID 。即,复制到 slave 的事务的服务器 UUID 是 master 的 UUID ,而不是 slave 的。复制链中的每个后续 slave 都将记录该事务及其原始 GTID 。因此,复制拓扑中的每个 slave 可以确定第一个执行事务的master 。
每个服务器记录事务时,它还在 gtid_executed 变量内的 GTID 集中记录该事务的 ID 。在全局上下文中,此变量包含记录到服务器的二进制日志的所有 GTID 集(表示此服务器和其他上游 master 的所有事务)。
mysql> SELECT @@global.gtid_executed\G
*************************** 1. row ***************************
@@global.gtid_executed: bacc034d-4785-11e2-8fe9-0019b944b7f7:1-34,
c237b5cd-4785-11e2-8fe9-0019b944b7f7:1-9,
c9cec614-4785-11e2-8fea-0019b944b7f7:1-839
1 row in set (0.00 sec)
gtid_purged 变量包含已经从二进制日志中清除的 GTID 集。在服务器上执行 RESET MASTER 时, gtid_purged 和全局 gtid_executed 都将重置为空字符串。
3) 使用 GTID 进行故障转移
l 使用 GTID 时,循环拓扑中的故障转移
在发生故障的 master 的 slave 上,通过发出单个 CHANGE MASTER TO 语句绕过该 master 。每个服务器忽略或应用从拓扑中的其他服务器复制的事务,具体取决于是否看到了该事务的 GTID 。
l 非循环拓扑中的故障转移
临时将新 master 配置为最新 slave 的 slave ,直到该新 master 变为最新。
虽然 GTID 可以防止源自单个服务器上的事件重复,但是它们不会防止源自不同服务器上的冲突操作,如 “复杂拓扑”中所述。在故障转移后将应用程序重新连接到服务器时,您必须小心不要产生此类冲突。
1.4. 复制的过滤规则
过滤器是应用于 master 或 slave 的服务器选项:
l master 写入二进制日志时应用 binlog-* 过滤器。
l slave 读取中继日志时应用 replicate-* 过滤器。
基于以下各项选择要复制的事件:
Ø 数据库:
– replicate-do-db, binlog-do-db
– replicate-ignore-db, binlog-ignore-db
Ø 表:
– replicate-do-table, replicate-wild-do-table
– replicate-ignore-table,replicate-wild-ignore-table
当环境中的不同服务器用于不同目的时,使用过滤规则。例如,专用于显示 Web 内容的服务器不需要从 master 复制重新进货信息或工资记录,而专用于生成关于销售量的管理报表的服务器不需要存储 Web 内容或市场营销副本。
过滤规则具有按顺序应用的复杂优先级规则:
Ø 数据库过滤器先于表过滤器应用。
Ø 表通配符过滤器 *-wild-* 在不使用通配符的那些过滤器之后应用。
Ø *-do-* 过滤器先于各个 *-ignore-* 过滤器应用。
使用多个过滤器时要谨慎。由于应用过滤器的顺序复杂,非常容易出错。因为过滤器控制要复制的数据,所以很难从此类错误中恢复。因此,不要混用不同类型的过滤器。例如,如果使用 replicate-wild-* ,则不要使用任何非 wild replicate-*过滤器。
有关复制规则及其执行顺序的完整论述,请访问:
http://dev.mysql.com/doc/refman/5.6/en/replication-rules.html
1.5. MySQL 实用程序 -- 复制工具
许多实用程序对于复制特别有用:
a) mysqldbcopy :将数据库以及复制配置从源服务器复制到目标服务器; mysqldbcopy 实用程序接受选项 --rpl ,其在目标服务器上运行 CHANGE MASTER TO 语句。它接受以下值:
Ø master :目标服务器变为源的 slave 。
Ø slave :源已经是其他 master 的 slave 。目标服务器从源复制该 master 信息并变为同一 master 的 slave;
b) mysqldbcompare :比较两个数据库来查找区别并创建脚本来同步这两个数据库;
c) mysqlrpladmin :管理复制拓扑;
– 在 master 故障后故障转移到最佳 slave
– 切换以升级指定的 slave
– 启动、重置或停止所有 slave
d) mysqlfailover :持续监视 master ,并执行故障转移到最佳可用 slave ;
mysqlfailover 实用程序通过 ping 操作定期检查 master 状态。期间间隔和 ping 操作都是可配置的。它使用 GTID 确保新的 master 在变为 master 时是最新的,通过以下操作实现此项:从候选列表中选择新 master (如果列表中没有可行的候选项,则从所有 slave 中选择),将其配置为所有其他 slave 的 slave 来收集所有未完成事务,最后使其成为新 master 。mysqlrpladmin 的 failover 命令在选择新 master 时执行相似的临时重新配置。如果 master 失败,您还可以执行运行状况监视而不执行自动重新配置。
e) mysqlrplcheck :检查 master 和 slave 之间进行复制的先决条件,包括:
– 二进制日志记录
– 具有适当权限的复制用户
– server_id 冲突
– 可能导致复制冲突的各种设置
f) mysqlreplicate :在两个服务器之间启动复制,报告不匹配警告消息;
g) mysqlrplshow :显示 master 与 slave 之间的复制拓扑或者递归显示整个拓扑;
mysqlrplshow 实用程序显示如下所示的复制拓扑:
# Replication Topology Graph
localhost:3311 (MASTER)
|
+--- localhost:3312 - (SLAVE + MASTER)
|
+--- localhost:3313 - (SLAVE + MASTER)
|
+--- localhost:3311 <--> (SLAVE)
在前面示例中,端口 3311 处的服务器出现两次:一次作为 master ,一次作为 slave 。 <--> 符号指示拓扑内的循环。
1.6. 异步复制
什么是异步复制? slave 请求二进制日志并应用其内容。 slave 通常滞后于 master 。 master 不关注 slave 何时应用日志。 master 继续运行而不等待 slave 。
MySQL 使用其默认配置进行复制过程中, master 从客户机接受更改事件,提交那些事件并将其写入二进制日志。在单独的线程中, master 将二进制日志流处理到连接的 slave 。因为 master 提交更改而不等待任何 slave 的响应,所以这称为异步复制。
最重要的是,这意味着在 master 向应用程序报告成功时 slave 尚未应用事务。通常,这不是个问题。但是,如果在master 提交事务之后而该事务复制到任何 slave 之前,该 master 出现故障并且数据丢失,则该事务将丢失,即使应用程序已经向用户报告成功也是如此。
如果 master 在提交事务之前等待所有 slave 应用其更改,则复制称为是同步的。虽然 MySQL 复制不是同步的,但MySQL Cluster 在内部使用同步复制来确保整个群集中的数据一致性,并且 MySQL 客户机请求是同步的,因为客户机在向服务器发出查询后等待服务器响应。
1.7. 半同步复制
半同步复制是指 master 在提交每个事务后执行阻止直到至少一个 slave 提交该事务,仅当 master 和至少一个 slave提交事务时客户机才收到“成功”,如果发生超时则切换到异步复制。
要启用半同步复制,请在 master 和至少一个 slave 上安装插件。使用以下插件:
l rpl_semi_sync_master (在 master 上)
l rpl_semi_sync_slave (在 slave 上)
还必须启用以下选项:
l rpl_semi_sync_master_enabled (在 master 上)
l rpl_semi_sync_slave_enabled (在 slave 上)
如果在 master 上启用半同步复制,它的行为是异步的,直到至少一个半同步 slave 连接。
在半同步复制过程中, master 在提交事务后执行阻止,直到至少一个半同步 slave 确认它也已经收到了该事务。这意味着在 master 向应用程序报告成功时至少一个 slave 已经收到了每个事务。如果 master 在提交事务后出现故障且数据丢失并且应用程序已经向用户报告了成功,则该事务还存在于至少一个 slave 上。
半同步复制需要您在性能和数据完整性之间进行权衡。使用半同步复制时事务速度比使用异步复制时慢,因为 master在提交之前等待 slave 响应。
每个事务花费的额外时间至少是它为以下项花费的时间:
Ø TCP/IP 往返以将提交发送到 slave
Ø slave 在其中继日志中记录提交
Ø master 等待 slave 确认该提交
这意味着对于物理上位于同一位置、通过快速网络通信的服务器,半同步复制最有效。如果 master 在超时期间内没有收到半同步 slave 的响应,该 master 仍提交该事务,但恢复为异步模式。可以使用 rpl_semi_sync_master_timeout 变量配置超时,其包含以毫秒为单位的值。默认值是 10000 ,表示十秒。
1.8. 复制日志
1) 查看二进制日志记录
二进制日志包含数据和模式更改及其时间戳,基于语句或基于行的日志记录,可以用于从备份的时间点恢复、从备份的完全恢复以及复制; binlog 在下列情况下轮转: MySQL 重新启动、其达到 max_binlog_size 设置的最大大小、执行FLUSH LOGS 语句; binlog 可以各种方式进行检查,查询元数据使用 SHOW BINARY LOGS 、 SHOW MASTER STATUS ,查询内容使用 mysqlbinlog ;
2) 复制日志
中继日志: MySQL 自动管理中继日志文件集,在其已经重放了所有事件时删除这些文件并在当前文件超过最大中继日志文件大小时创建新文件。中继日志使用与二进制日志相同的格式存储;可以使用 mysqlbinlog 查看那些日志。 slave 维护索引文件来跟踪中继日志文件。
默认情况下,中继日志文件名为
slave 状态日志: slave 存储关于如何连接到 master 的信息以及 master 的二进制日志和 slave 的中继日志的最近复制的日志坐标。有两个此类日志:
l master 信息:此日志包含关于 master 的信息,包括主机名和端口、用于连接的凭证以及 master 二进制日志的最近下载的日志坐标等信息。
l 中继日志信息:此日志包含中继日志的最近执行的坐标以及 slave 的已复制事件落后于 master 的那些事件的秒数。
slave 状态日志存储在文件 master.info 和 relay-log.info 中(默认情况下),如果存储在表中,则为 mysql 数据库中的slave_master_info 和 slave_relay_log_info 表;
3) 故障安全 (Crash-Safe) 复制
l 二进制日志记录是故障安全的
MySQL 仅记录完成事件或事务。使用 sync-binlog 提高安全性。默认情况下,值是 ,表示操作系统根据其内部规则向文件写入。将 sync-binlog 设置为 1 ,强制操作系统在每个事务之后写入文件,或者将其设置为任何较大数值以在该数量的事务之后写入。
l 将 slave 状态日志存储在 TABLE 中是故障安全的
slave 状态日志选项: master-info-repository 和 relay-loginfo-repository ,可能值为 FILE (默认值)和 TABLE 。TABLE 是故障安全的。
默认情况下, slave 状态日志存储在文件中。使用 master-info-file 和 relay-log-info-file 选项设置文件名。默认情况下,文件名是 master.info 和 relay-log.info ,都存储在数据目录中。
如果将 slave 状态日志存储在文件中,在记录事件与在状态日志中记录该事件的日志坐标之间的某点会发生故障。服务器在此类事件后重新启动时,状态文件和二进制日志将不一致,恢复变得困难。
复制使用事务存储引擎(例如 InnoDB )的数据时,通过将 master-info-repository 和 relay-log-info-repository 的值从FILE (默认值)更改为 TABLE ,来将状态日志存储在事务表中以提高性能并确保故障安全复制。该表称为slave_master_info 和 slave_relay_log_info ,都存储在 mysql 数据库中,并且都使用 InnoDB 引擎确保事务完整性和故障安全行为。
有关 slave 状态日志的更多信息,请访问:
http://dev.mysql.com/doc/refman/5.6/en/slave-logs-status.html
1.9. 复制线程
1) 复制线程介绍
slave 连接到 master 时
l master 创建 Binlog 转储线程:从二进制日志读取事件并将其发送到 slaveI/O 线程
l slave 至少创建两个线程
— slaveI/O 线程:从 master 的 Binlog 转储线程读取事件并将其写入 slave 的中继日志
— slaveSQL 线程:在单线程 slave 上应用中继日志事件,在多线程 slave 上的工作线程之间分配中继日志事件
— slave 工作线程:在多线程 slave 上应用中继日志事件
MySQL 在 master 和 slave 上创建线程来执行复制工作。 slave 成功连接到 master 时, master 启动称为 Binlog 转储线程的复制 master 线程,如果 slave 配置为使用自动定位协议 (CHANGE MASTER TO MASTER_AUTO_POSITION),则该线程显示为“ Binlog 转储 GTID ”。在 slave 已连接时,此线程会在二进制日志内的事件到达时将其发送到 slave。 master 为每个连接的 slave 创建一个 Binlog 转储线程。
默认情况下,每个 slave 启动两个线程,分别称为 slaveI/O 线程和 slaveSQL 线程。
l slaveI/O 线程连接到 master ,将更新从 Binlog 转储线程读取到本地中继日志中。
l slaveSQL 线程执行中继日志中的事件。
由于单个 SQL 进程处理中继日志而被称为单线程的默认配置会导致 slave 滞后,其中 slave 落后于 master :如果master 具有多个客户机连接则并行应用更改,但是串行执行其二进制日志中的所有事件。 slave 在单个线程中顺序执行这些事件,在高流量环境中或者当 slave 的硬件不足以处理单个线程中的通信流量时,这会成为瓶颈。
2) 多线程 slave
MySQL 支持多线程 slave 以避免单线程 slave 引起的一些滞后。如果在 slave 上将 slave_parallel_workers 变量设置为大于零的值,它会创建该数量的工作线程。在这种情况下, slaveSQL 线程不直接执行事件。相反,它按数据库将事件分配给工作线程。这使多线程 slave 在要在多个数据库中复制数据的环境中特别有用。
如果工作线程执行并行操作的顺序与其在 master 上的执行顺序不同,此选项可能导致数据库之间不一致,所以您必须确保不同数据库中的数据是独立的。由单个线程复制的一个数据库中的数据将保证是一致的。
如果将 slave_parallel_workers 变量设置为大于复制中所用数据库数量的值,一些工作线程将保持空闲。类似地,如果仅在服务器中复制一个数据库,则在您的环境中使用多线程 slave 不会带来什么好处。
3) slave 线程管理
l 启停 slave 线程:
START SLAVE;
STOP SLAVE;
l 单独控制线程:
START SLAVE IO_THREAD;
STOP SLAVE SQL_THREAD;
l 启动线程直到指定的条件:
START SLAVE UNTIL SQL_AFTER_MTS_GAPS;
START SLAVE IO_THREAD UNTIL SQL_AFTER_GTIDS = 0ed18583-47fd-11e2-92f3-0019b944b7f7:338;
通过 START SLAVE 和 STOP SLAVE 语句启动和停止 slave 的 SQL 和 I/O 线程。如果没有参数,这些语句控制这两个线程。通过指定 IO_THREAD 或 SQL_THREAD 作为参数来单独控制每个线程。例如,可以通过在 slave 上发出以下语句来临时停止 slave 查询 master : STOP SLAVE IO_THREAD;
启动 slave 线程时,可以选择在线程到达 UNTIL 子句中指定的某点时将其停止。可以使用日志坐标、 GTID 集或特殊SQL_AFTER_MTS_GAPS 值来指定此点,用于多线程 slave 。例如,以下语句在 slave 上启动 SQL 线程,直到它执行中继日志中的指定 GTID ,在该点它将停止:
START SLAVE SQL_THREAD UNTIL SQL_AFTER_GTIDS = 0ed18583-47fd-11e2-92f3-0019b944b7f7:338
注: slave 工作线程无法单独启动或停止,因为 SQL 线程控制其工作。启动或停止 SQL 线程来控制工作线程。
有关使用 START SLAVE 的完整详细信息,请访问:
http://dev.mysql.com/doc/refman/5.6/en/start-slave.html
1.10. 监控复制
1) 查询 slave 状态
mysql> SHOW SLAVE STATUS\G
***************** 1. row *********************
Slave_IO_State: Queueing master event to the relay log
...
Master_Log_File: mysql-bin.005
Read_Master_Log_Pos: 79
Relay_Log_File: slave-relay-bin.005
Relay_Log_Pos: 548
Relay_Master_Log_File: mysql-bin.004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
Exec_Master_Log_Pos: 3769
...
Seconds_Behind_Master: 8
Slave_*_Running : Slave_IO_Running 和 Slave_SQL_Running 列标识 slave 的 I/O 线程和 SQL 线程当前正在运行、未运行还是正在运行但尚未连接到 master 。可能值分别为 Yes 、 No 或 Connecting 。
master 日志坐标: Master_Log_File 和 Read_Master_Log_Pos 列标识 master 二进制日志中 I/O 线程已经传输的最近事件的坐标。这些列可与您在 master 上执行 SHOW MASTER STATUS 时显示的坐标进行比较。如果 Master_Log_File和 Read_Master_Log_Pos 的值远远落后于 master 上的那些值,这表示 master 与 slave 之间事件的网络传输存在延迟。
中继日志坐标: Relay_Log_File 和 Relay_Log_Pos 列标识 slave 中继日志中 SQL 线程已经执行的最近事件的坐标。这些坐标对应于 Relay_Master_Log_File 和 Exec_Master_Log_Pos 列标识的 master 二进制日志中的坐标。
如果 Relay_Master_Log_File 和 Exec_Master_Log_Pos 列的输出远远落后于 Master_Log_File 和Read_Master_Log_Pos 列(表示 I/O 线程的坐标),这表示 SQL 线程(而不是 I/O 线程)中存在延迟。即,它表示复制日志事件快于执行这些事件。
在多线程 slave 上, Exec_Master_Log_Pos 包含任何未提交事务之前最后一点的位置。这并不始终与中继日志中的最近日志位置相同,因为多线程 slave 在不同数据库上执行事务的顺序可能与二进制日志中显示的顺序不同。
Seconds_Behind_Master :此列提供中继日志中 SQL 线程执行的最近事件的时间戳(在 master 上)与 slave 的实际时间之间的秒数。当 master 并行处理大量事件而 slave 必须串行处理这些事件时,或者当高通信流量期间 slave 的硬件不足以处理与 master 可以处理的相同量的事件时,通常会发生这种类型的延迟。如果 slave 未连接到 master ,此列为NULL 。注:此列不显示 I/O 线程中的延迟或者 master 的事件网络传输中的延迟。
郑州妇科医院:http://byby.zztjyy.com/zztjyy///
2) 复制 slaveI/O 线程状态
本节介绍的 slaveI/O 线程状态是指 SHOW PROCESSLIST 输出的 State 列和 SHOW SLAVE STATUS 显示的Slave_IO_State 列的值;常见的 I/O 线程状态如下:
l Connecting to master :线程正尝试连接到 master 。
l Waiting for master to send event :线程已经连接到 master 并且正在等待二进制日志事件到达。如果master 处于空闲状态,此状态可能持续很长时间。如果等待持续 slave_read_timeout 秒,则发生超时。此时,线程考虑断开连接并尝试重新连接。
l Queueing master event to the relay log :线程已经读取事件并且正在将其复制到中继日志,从而 SQL 线程可以处理该事件。
l Waiting to reconnect after a failed binlog dump request :如果二进制日志转储请求失败(由于断开连接),线程在其休眠时转入此状态,然后定期尝试重新连接。可以使用 --master-connect-retry 选项指定重试之间的时间间隔。
l Reconnecting after a failed binlog dump request :线程正尝试重新连接到 master 。
l Waiting to reconnect after a failed master event read :读取时出错(由于断开连接)。线程在尝试重新连接之前休眠 master-connect-retry 秒。
l Reconnecting after a failed master event read :线程正尝试重新连接到 master 。重新建立连接后,状态变为 Waiting for master to send event 。
l Waiting for the slave SQL thread to free enough relay log space :该状态显示正在使用非零relay_log_space_limit 值,并且中继日志已经增加得足够大,以至其合并大小超过了此值。 I/O 线程正在等待,直到SQL 线程通过处理中继日志内容以便可以删除一些中继日志文件来释放足够空间。
3) 复制 slaveSQL 线程状态
slaveSQL 线程和工作线程的 State 列中显示的最常见状态是:
l Waiting for the next event in relay log :这是 Reading event from the relay log 之前的初始状态。
l Reading event from the relay log :线程已经从中继日志中读取了事件,从而可以处理该事件。
l Making temp file :线程正在执行 LOAD DATA INFILE 语句,并且正在创建包含数据的临时文件, slave 从该数据中读取行。
l Slave has read all relay log; waiting for the slave I/O thread to update it :线程已经处理了中继日志文件中的所有事件,现在正在等待 I/O 线程将新事件写入中继日志。
l Waiting until MASTER_DELAY seconds after master executed event : SQL 线程已经读取事件,但是正等待 slave 延迟结束。通过 CHANGE MASTER TO 的 MASTER_DELAY 选项设置此延迟。
l Waiting for an event from Coordinator :在多线程 slave 上, 工作线程 正等待协调线程向工作队列分配作业。
1.11. 排除 MySQL 复制故障
如何排除 MySQL 复制故障步骤?
a) 查看错误日志,错误日志可以为您提供足够信息来确定和更正复制中的问题。
b) 在 master 上发出 SHOW MASTER STATUS 语句,如果位置值非零则启用日志记录。
c) 确认 master 和 slave 都具有唯一的非零 server_id 值。 master 和 slave 必须具有不同的 server_id 。
d) 在 slave 上发出 SHOW SLAVE STATUS 命令。如果 slave 运行正常, Slave_IO_Running 和Slave_SQL_Running 显示 Yes 。 Last_IO_Error 和 Last_SQL_Error 显示 IO 和 SQL 线程的最新错误消息。SHOW SLAVE STATUS 语句在与复制过程中遇到的最新错误相关的多个字段中返回信息。
l Last_IO_Error 、 Last_SQL_Error :分别导致 I/O 线程或 SQL 线程停止的最新错误的错误消息。在正常复制过程中,这些字段是空的。如果发生错误并导致消息显示在以上任一字段中,则错误值也显示在错误日志中。
l Last_IO_Errno 、 Last_SQL_Errno :与分别导致 I/O 线程或 SQL 线程停止的最新错误关联的错误编号。在正常复制过程中,这些字段包含编号 。
l Last_IO_Error_Timestamp 、 Last_SQL_Error_Timestamp :分别导致 I/O 线程或 SQL 线程停止的最新错误的时间戳,格式为 YYMMDD HH:MM:SS 。在正常复制过程中,这些字段是空的。
错误日志包含关于复制开始时间的信息以及关于复制过程中发生的所有错误的信息。例如,下面的序列显示成功开始,然后在复制 slave 上已经存在的用户时失败:
2012-12-16 11:13:21 8449 [Note] Slave I/O thread: connected to
master '[email protected]:3313',replication started in log 'FIRST'
at position 4
2012-12-16 11:13:21 8449 [Note] Slave SQL thread initialized,
starting replication in log 'mysql-bin.000002' at position 108,
relay log './slave-relay-bin.000003' position: 408
...
2012-12-16 16:42:53 8449 [ERROR] Slave SQL: Error 'Operation
CREATE USER failed for 'user'@'127.0.0.1'' on query. Default
database: 'world_innodb'. Query: 'CREATE USER ‘user'@'127.0.0.1'
IDENTIFIED BY PASSWORD
'*2447D497B9A6A15F2776055CB2D1E9F86758182F'', Error_code: 1396
2012-12-16 16:42:53 8449 [Warning] Slave: Operation CREATE USER
failed for 'user'@'127.0.0.1' Error_code: 1396
2012-12-16 16:42:53 8449 [ERROR] Error running query, slave SQL
thread aborted. Fix the problem, and restart the slave SQL
thread with "SLAVE START". We stopped at log 'mysql-bin.000002'
position 460
下面的序列显示 I/O 线程从 master 的二进制日志读取时失败:
2012-12-16 16:48:13 8823 [Note] Slave I/O thread: connected to master
'[email protected]:3313',replication started in log 'mysql-bin.000002' at position 1172
2012-12-16 16:48:15 8823 [ERROR] Read invalid event from master: 'Found invalid event
in binary log', master could be corrupt but a more likely cause of this is a bug
2012-12-16 16:48:15 8823 [ERROR] Slave I/O: Relay log write failure: could not queue
event from master, Error_code: 1595
2012-12-16 16:48:15 8823 [Note] Slave I/O thread exiting, read up to log 'mysqlbin.
000003', position 4
e) 使用 mysqlrplcheck 确保服务器满足复制的先决条件;
f) 在 master 和 slave 上发出 SHOW PROCESSLIST 命令,查看 Binlog 转储、 I/O 和 SQL 线程的状态。slave 上的 SHOW PROCESSLIST I/O 线程指示正连接到 master :
Ø 确认用于在 master 上进行复制的用户的权限;
Ø 确认主机名和端口对于 master 是正确的;
Ø 确认尚未在 master 或 slave 上禁用网络(使用 --skip-networking 选项);
Ø 尝试 ping master 来确认 slave 可以访问 master ;
g) 对于突然停止工作的 slave ,检查最近复制的语句。如果操作由于约束问题或其他错误而失败, SQL 线程将停止,错误日志包含导致 SQL 线程停止的事件;然后查看已知复制限制(http://dev.mysql.com/doc/refman/5.6/en/replication-features.html );确认 slave 数据尚未被直接修改(在复制之外)。