vlambda博客
学习文章列表

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

正文开始~

温习《高性能 MySQL》的复制篇。

1. 复制概述

MySQL 内建的复制功能是构建大型,高性能应用程序的基础。将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将 MySQL 的某一台主机的数据复制到其它主机(slaves)上,并重新执行一遍来实现的。复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后封锁并等待主服务器通知新的更新。

请注意当你进行复制时,所有对复制中的表的更新必须在主服务器上进行。否则,你必须要小心,以避免用户对主服务器上的表进行的更新与对从服务器上的表所进行的更新之间的冲突。

1.1 MySQL 支持的复制类型:

1.基于语句的复制:在主服务器上执行的 SQL 语句,在从服务器上执行同样的语句。MySQL 默认采用基于语句的复制,效率比较高。一旦发现没法精确复制时,会自动选着基于行的复制。2.基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍。从 MySQL5.0 开始支持3.混合类型的复制: 默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制。

1.2 复制解决的问题

MySQL 复制技术有以下一些特点:

1.数据分布 (Data distribution )2.负载平衡 (load balancing)3.备份 (Backups)4.高可用性和容错行 High availability and failover

1.3 复制如何工作

整体上来说,复制有 3 个步骤:

1.master 将改变记录到二进制日志 (binary log)中(这些记录叫做二进制日志事件,binary log events);2.slave 将 master 的 binary log events 拷贝到它的中继日志 (relay log);3.slave 重做中继日志中的事件,将改变反映它自己的数据。

下图描述了复制的过程:

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

该过程的第一部分就是 master 记录二进制日志。在每个事务更新数据完成之前,master 在二日志记录这些改变。MySQL 将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master 通知存储引擎提交事务。

下一步就是 slave 将 master 的 binary log 拷贝到它自己的中继日志。首先,slave 开始一个工作线程——I/O 线程。I/O 线程在 master 上打开一个普通的连接,然后开始 binlog dump process。Binlog dump process 从 master 的二进制日志中读取事件,如果已经跟上 master,它会睡眠并等待 master 产生新的事件。I/O 线程将这些事件写入中继日志。

SQL slave thread(SQL从线程)处理该过程的最后一步。SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小。

此外,在 master 中也有一个工作线程:和其它 MySQL 的连接一样,slave 在 master 中打开一个连接也会使得 master 开始一个线程。复制过程有一个很重要的限制——复制在 slave 上是串行化的,也就是说 master 上的并行更新操作不能在 slave上并行操作。

2. 主从复制配置

有两台 MySQL 数据库服务器 Master 和 slave,Master 为主服务器,slave 为从服务器,初始状态时,Master 和 slave 中的数据信息相同,当 Master 中的数据发生变化时,slave 也跟着发生相应的变化,使得 master 和 slave 的数据信息同步,达到备份的目的。

要点:

负责在主、从服务器传输各种修改动作的媒介是主服务器的二进制变更日志,这个日志记载着需要传输给从服务器的各种修改动作。因此,主服务器必须激活二进制日志功能。从服务器必须具备足以让它连接主服务器并请求主服务器把二进制变更日志传输给它的权限。

环境:

Master 和 slave 的 MySQL 数据库版本同为 5.0.18

2.1 创建复制帐号

在 Master 的数据库中建立一个备份帐户:每个 slave 使用标准的 MySQL 用户名和密码连接 master。进行复制操作的用户会授予 REPLICATION SLAVE 权限。用户名的密码都会存储在文本文件 master.info 中。

命令如下:

mysql > GRANT REPLICATION SLAVE,RELOAD,SUPER ON *.* TO backup@10.100.0.200 IDENTIFIED BY 1234’;

(如果因为 MySQL 版本新旧密码算法不同,可以设置:set password for 'backup'@'10.100.0.200'=old_password('1234'))

2.2 拷贝数据

(假如是你完全新安装 MySQL 主从服务器,这个一步就不需要。因为新安装的 master 和 slave 有相同的数据)

关停 Master 服务器,将 Master 中的数据拷贝到 B 服务器中,使得 Master 和 slave 中的数据同步,并且确保在全部设置操作结束前,禁止在Master和slave服务器中进行写操作,使得两数据库中的数据一定要相同!

2.3 配置 master

接下来对 master 进行配置,包括打开二进制日志,指定唯一的 servr ID。例如,在配置文件加入如下值:

server-id=1log-bin=mysql-bin

server-id:为主服务器 A 的 ID 值

log-bin:二进制变更日值

重启 master,运行 SHOW MASTER STATUS,输出如下:

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

2.4 配置 slave

Slave 的配置与 master 类似,你同样需要重启 slave 的 MySQL。如下:

log_bin = mysql-binserver_id = 2relay_log = mysql-relay-binlog_slave_updates = 1read_only = 1

server_id:是必须的,而且唯一。

log_bin:slave 没有必要开启二进制日志 bin_log,但是在一些情况下,必须设置,例如,如果 slave 为其它 slave 的 master,必须设置 bin_log。在这里,我们开启了二进制日志,而且显示的命名(默认名称为 hostname,但是,如果 hostname 改变则会出现问题)。

relay_log:配置中继日志,log_slave_updates 表示 slave 将复制事件写进自己的二进制日志(后面会看到它的用处)。

有些人开启了 slave 的二进制日志,却没有设置 log_slave_updates,然后查看 slave 的数据是否改变,这是一种错误的配置。

read_only:尽量使用 read_only,它防止改变数据(除了特殊的线程)。但是,read_only 并是很实用,特别是那些需要在 slave 上创建表的应用。

2.5 启动 slave

接下来就是让 slave 连接 master,并开始重做 master 二进制日志中的事件。你不应该用配置文件进行该操作,而应该使用 CHANGE MASTER TO 语句,该语句可以完全取代对配置文件的修改,而且它可以为 slave 指定不同的 master,而不需要停止服务器。如下:

mysql> CHANGE MASTER TO MASTER_HOST='server1', -> MASTER_USER='repl', -> MASTER_PASSWORD='p4ssword', -> MASTER_LOG_FILE='mysql-bin.000001', -> MASTER_LOG_POS=0;

MASTER_LOG_POS 的值为 0,因为它是日志的开始位置。

你可以用 SHOW SLAVE STATUS 语句查看 slave 的设置是否正确:

mysql> SHOW SLAVE STATUS\G*************************** 1. row *************************** Slave_IO_State: Master_Host: server1 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 4 Relay_Log_File: mysql-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: No Slave_SQL_Running: No ...omitted... Seconds_Behind_Master: NULL

Slave_IO_State, Slave_IO_Running, 和 Slave_SQL_Running 是 No

表明 slave 还没有开始复制过程。日志的位置为 4 而不是 0,这是因为 0 只是日志文件的开始位置,并不是日志位置。实际上,MySQL 知道的第一个事件的位置是 4。

为了开始复制,你可以运行:

mysql> START SLAVE;

运行 SHOW SLAVE STATUS 查看输出结果:

mysql> SHOW SLAVE STATUS\G*************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: server1 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 164 Relay_Log_File: mysql-relay-bin.000001 Relay_Log_Pos: 164 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes ...omitted... Seconds_Behind_Master: 0

在这里主要是看:

Slave_IO_Running=Yes

Slave_SQL_Running=Yes

slave 的 I/O 和 SQL 线程都已经开始运行,而且 Seconds_Behind_Master 不再是 NULL。日志的位置增加了,意味着一些事件被获取并执行了。如果你在 master 上进行修改,你可以在 slave 上看到各种日志文件的位置的变化,同样,你也可以看到数据库中数据的变化。

你可查看 master 和 slave 上线程的状态。在 master 上,你可以看到 slave 的 I/O 线程创建的连接:

在 master 上输入 show processlist\G;

mysql> show processlist \G*************************** 1. row *************************** Id: 1 User: root Host: localhost:2096 db: testCommand: Query Time: 0 State: NULL Info: show processlist*************************** 2. row *************************** Id: 2 User: repl Host: localhost:2144 db: NULLCommand: Binlog Dump Time: 1838 State: Has sent all binlog to slave; waiting for binlog to be updated Info: NULL2 rows in set (0.00 sec)

行 2 为处理 slave 的 I/O 线程的连接。

在 slave 服务器上运行该语句:

mysql> show processlist \G*************************** 1. row *************************** Id: 1 User: system user Host: db: NULLCommand: Connect Time: 2291 State: Waiting for master to send event Info: NULL*************************** 2. row *************************** Id: 2 User: system user Host: db: NULLCommand: Connect Time: 1852 State: Has read all relay log; waiting for the slave I/O thread to update it Info: NULL*************************** 3. row *************************** Id: 5 User: root Host: localhost:2152 db: testCommand: Query Time: 0 State: NULL Info: show processlist3 rows in set (0.00 sec)

行 1 为 I/O 线程状态,行 2 为 SQL 线程状态。

2.6 添加新 slave 服务器

假如 master 已经运行很久了,想对新安装的 slave 进行数据同步,甚至它没有 master 的数据。此时,有几种方法可以使 slave 从另一个服务开始,例如,从 master 拷贝数据,从另一个 slave 克隆,从最近的备份开始一个 slave。Slave 与 master 同步时,需要三样东西:

1.master 的某个时刻的数据快照;2.master 当前的日志文件、以及生成快照时的字节偏移。这两个值可以叫做日志文件坐标 (log file coordinate),因为它们确定了一个二进制日志的位置,你可以用 SHOW MASTER STATUS 命令找到日志文件的坐标;3.master 的二进制日志文件。

可以通过以下几中方法来克隆一个 slave:

1.冷拷贝 (cold copy): 停止 master,将 master 的文件拷贝到 slave;然后重启 master。缺点很明显。2.热拷贝 (warm copy):如果你仅使用 MyISAM 表,你可以使用 mysqlhotcopy 拷贝,即使服务器正在运行。3.使用 mysqldump

使用 mysqldump 来得到一个数据快照可分为以下几步:

1.锁表:如果你还没有锁表,你应该对表加锁,防止其它连接修改数据库,否则,你得到的数据可以是不一致的。如下:

mysql> FLUSH TABLES WITH READ LOCK;

2. 在另一个连接用 mysqldump 创建一个你想进行复制的数据库的转储:

shell> mysqldump --all-databases --lock-all-tables >dbdump.db

3. 对表释放锁。

mysql> UNLOCK TABLES;

3. 深入了解复制

已经讨论了关于复制的一些基本东西,下面深入讨论一下复制。

3.1 基于语句的复制 (Statement-Based Replication)

MySQL 5.0 及之前的版本仅支持基于语句的复制(也叫做逻辑复制,logical replication),这在数据库并不常见。master记录下改变数据的查询,然后,slave 从中继日志中读取事件,并执行它,这些 SQL 语句与 master 执行的语句一样。这种方式的优点就是实现简单。此外,基于语句的复制的二进制日志可以很好的进行压缩,而且日志的数据量也较小,占用带宽少——例如,一个更新 GB 的数据的查询仅需要几十个字节的二进制日志。而 mysqlbinlog 对于基于语句的日志处理十分方便。

但是,基于语句的复制并不是像它看起来那么简单,因为一些查询语句依赖于 master 的特定条件,例如,master 与 slave 可能有不同的时间。所以,MySQL 的二进制日志的格式不仅仅是查询语句,还包括一些元数据信息,例如,当前的时间戳。即使如此,还是有一些语句,比如,CURRENT USER 函数,不能正确的进行复制。此外,存储过程和触发器也是一个问题。

另外一个问题就是基于语句的复制必须是串行化的。这要求大量特殊的代码,配置,例如 InnoDB 的 next-key 锁等。并不是所有的存储引擎都支持基于语句的复制。

3.2 基于记录的复制 (Row-Based Replication)

MySQL 增加基于记录的复制,在二进制日志中记录下实际数据的改变,这与其它一些 DBMS 的实现方式类似。这种方式有优点,也有缺点。优点就是可以对任何语句都能正确工作,一些语句的效率更高。主要的缺点就是二进制日志可能会很大,而且不直观,所以,你不能使用 mysqlbinlog 来查看二进制日志。对于一些语句,基于记录的复制能够更有效的工作,如:

mysql> INSERT INTO summary_table(col1, col2, sum_col3) -> SELECT col1, col2, sum(col3) -> FROM enormous_table -> GROUP BY col1, col2;

假设,只有三种唯一的 col1 和 col2 的组合,但是,该查询会扫描原表的许多行,却仅返回三条记录。此时,基于记录的复制效率更高。

另一方面,下面的语句,基于语句的复制更有效:

mysql> UPDATE enormous_table SET col1 = 0;

此时使用基于记录的复制代价会非常高。由于两种方式不能对所有情况都能很好的处理,所以,MySQL 5.1 支持在基于语句的复制和基于记录的复制之前动态交换。你可以通过设置 session 变量 binlog_format 来进行控制。

3.3 复制相关的文件

除了二进制日志和中继日志文件外,还有其它一些与复制相关的文件。如下:

1.mysql-bin.index

服务器一旦开启二进制日志,会产生一个与二日志文件同名,但是以 .index 结尾的文件。它用于跟踪磁盘上存在哪些二进制日志文件。MySQL 用它来定位二进制日志文件。它的内容如下(我的机器上):

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

2. mysql-relay-bin.index

该文件的功能与 mysql-bin.index 类似,但是它是针对中继日志,而不是二进制日志。内容如下:

.\mysql-02-relay-bin.000017.\mysql-02-relay-bin.000018

3. master.info

保存 master的 相关信息。不要删除它,否则,slave 重启后不能连接 master。内容如下(我的机器上):

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

I/O 线程更新 master.info 文件,内容如下(我的机器上):

.\mysql-02-relay-bin.000019254mysql-01-bin.000010286052813

4. relay-log.info

包含 slave 中当前二进制日志和中继日志的信息。

3.4 发送复制事件到其它 slave

当设置 log_slave_updates 时,你可以让 slave 扮演其它 slave 的 master。此时,slave 把 SQL 线程执行的事件写进行自己的二进制日志 (binary log),然后,它的 slave 可以获取这些事件并执行它。如下:

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

3.5 复制过滤 (Replication Filters)

复制过滤可以让你只复制服务器中的一部分数据,有两种复制过滤:在 master 上过滤二进制日志中的事件;在 slave 上过滤中继日志中的事件。如下:

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

4. 复制的常用拓扑结构

复制的体系结构有以下一些基本原则:

1.每个 slave 只能有一个 master;2.每个 slave 只能有一个唯一的服务器 ID;3.每个 master 可以有很多 slave;4.如果你设置 log_slave_updates,slave 可以是其它 slave 的 master,从而扩散 master 的更新。

MySQL 不支持多主服务器复制 (Multimaster Replication)——即一个 slave 可以有多个 master。但是,通过一些简单的组合,我们却可以建立灵活而强大的复制体系结构。

4.1 单一 master 和多 slave

由一个 master 和一个 slave 组成复制系统是最简单的情况。Slave 之间并不相互通信,只能与 master 进行通信。

在实际应用场景中,MySQL 复制 90% 以上都是一个 Master 复制到一个或者多个 Slave 的架构模式,主要用于读压力比较大的应用的数据库端廉价扩展解决方案。因为只要 Master 和 Slave 的压力不是太大(尤其是 Slave 端压力)的话,异步复制的延时一般都很少很少。尤其是自从 Slave 端的复制方式改成两个线程处理之后,更是减小了 Slave 端的延时问题。而带来的效益是,对于数据实时性要求不是特别 Critical 的应用,只需要通过廉价的 pcserver 来扩展 Slave 的数量,将读压力分散到多台 Slave 的机器上面,即可通过分散单台数据库服务器的读压力来解决数据库端的读性能瓶颈,毕竟在大多数数据库应用系统中的读压力还是要比写压力大很多。这在很大程度上解决了目前很多中小型网站的数据库压力瓶颈问题,甚至有些大型网站也在使用类似方案解决数据库瓶颈。

如下:

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

如果写操作较少,而读操作很时,可以采取这种结构。你可以将读操作分布到其它的 slave,从而减小 master 的压力。但是,当 slave 增加到一定数量时,slave 对 master 的负载以及网络带宽都会成为一个严重的问题。

这种结构虽然简单,但是,它却非常灵活,足够满足大多数应用需求。一些建议:

1.不同的 slave 扮演不同的作用 (例如使用不同的索引,或者不同的存储引擎);2.用一个 slave 作为备用 master,只进行复制;3.用一个远程的 slave,用于灾难恢复;

大家应该都比较清楚,从一个 Master 节点可以复制出多个 Slave 节点,可能有人会想,那一个 Slave 节点是否可以从多个 Master 节点上面进行复制呢?至少在目前来看,MySQL 是做不到的,以后是否会支持就不清楚了。

MySQL 不支持一个 Slave 节点从多个 Master 节点来进行复制的架构,主要是为了避免冲突的问题,防止多个数据源之间的数据出现冲突,而造成最后数据的不一致性。不过听说已经有人开发了相关的 patch,让 MySQL 支持一个 Slave 节点从多个 Master 结点作为数据源来进行复制,这也正是 MySQL 开源的性质所带来的好处。

4.2 主动模式的 Master-Master (Master-Master in Active-Active Mode)

Master-Master 复制的两台服务器,既是 master,又是另一台服务器的 slave。这样,任何一方所做的变更,都会通过复制应用到另外一方的数据库中。

可能有些读者朋友会有一个担心,这样搭建复制环境之后,难道不会造成两台 MySQL 之间的循环复制么?实际上 MySQL 自己早就想到了这一点,所以在 MySQL 的 BinaryLog 中记录了当前 MySQL 的 server-id,而且这个参数也是我们搭建 MySQLReplication 的时候必须明确指定,而且 Master 和 Slave 的 server-id 参数值比需要不一致才能使MySQLReplication 搭建成功。一旦有了 server-id 的值之后,MySQL 就很容易判断某个变更是从哪一个 MySQLServer 最初产生的,所以就很容易避免出现循环复制的情况。而且,如果我们不打开记录 Slave 的 BinaryLog 的选项(--log-slave-update)的时候,MySQL 根本就不会记录复制过程中的变更到 BinaryLog 中,就更不用担心可能会出现循环复制的情形了。

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

主动的 Master-Master 复制有一些特殊的用处。例如,地理上分布的两个部分都需要自己的可写的数据副本。这种结构最大的问题就是更新冲突。假设一个表只有一行(一列)的数据,其值为 1,如果两个服务器分别同时执行如下语句:

在第一个服务器上执行:

mysql> UPDATE tbl SET col=col + 1;

在第二个服务器上执行:

mysql> UPDATE tbl SET col=col * 2;

那么结果是多少呢?一台服务器是 4,另一个服务器是 3,但是,这并不会产生错误。

实际上,MySQL 并不支持其它一些 DBMS 支持的多主服务器复制 (Multimaster Replication),这是 MySQL 的复制功能很大的一个限制(多主服务器的难点在于解决更新冲突),但是,如果你实在有这种需求,你可以采用 MySQL Cluster,以及将Cluster 和 Replication 结合起来,可以建立强大的高性能的数据库平台。但是,可以通过其它一些方式来模拟这种多主服务器的复制。

4.3 主动-被动模式的 Master-Master (Master-Master in Active-Passive Mode)

这是 master-master 结构变化而来的,它避免了 M-M 的缺点,实际上,这是一种具有容错和高可用性的系统。它的不同点在于其中一个服务只能进行只读操作。如图:

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

4.4 级联复制架构 Master –Slaves - Slaves

在有些应用场景中,可能读写压力差别比较大,读压力特别的大,一个 Master 可能需要上 10 台甚至更多的 Slave 才能够支撑注读的压力。这时候,Master 就会比较吃力了,因为仅仅连上来的 SlaveIO 线程就比较多了,这样写的压力稍微大一点的时候,Master 端因为复制就会消耗较多的资源,很容易造成复制的延时。

遇到这种情况如何解决呢?这时候我们就可以利用 MySQL 可以在 Slave 端记录复制所产生变更的 BinaryLog 信息的功能,也就是打开— log-slave-update 选项。然后,通过二级(或者是更多级别)复制来减少 Master 端因为复制所带来的压力。也就是说,我们首先通过少数几台 MySQL 从 Master 来进行复制,这几台机器我们姑且称之为第一级 Slave 集群,然后其他的 Slave 再从第一级 Slave 集群来进行复制。从第一级 Slave 进行复制的 Slave,我称之为第二级 Slave 集群。如果有需要,我们可以继续往下增加更多层次的复制。这样,我们很容易就控制了每一台 MySQL 上面所附属 Slave 的数量。这种架构我称之为 Master-Slaves-Slaves 架构

这种多层级联复制的架构,很容易就解决了 Master 端因为附属 Slave 太多而成为瓶颈的风险。下图展示了多层级联复制的 Replication 架构。

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

当然,如果条件允许,我更倾向于建议大家通过拆分成多个 Replication 集群来解决

上述瓶颈问题。毕竟 Slave 并没有减少写的量,所有 Slave 实际上仍然还是应用了所有的数据变更操作,没有减少任何写 IO。相反,Slave 越多,整个集群的写 IO 总量也就会越多,我们没有非常明显的感觉,仅仅只是因为分散到了多台机器上面,所以不是很容易表现出来。

此外,增加复制的级联层次,同一个变更传到最底层的 Slave 所需要经过的 MySQL 也会更多,同样可能造成延时较长的风险。

而如果我们通过分拆集群的方式来解决的话,可能就会要好很多了,当然,分拆集群也需要更复杂的技术和更复杂的应用系统架构。

4.5 带从服务器的 Master-Master 结构 (Master-Master with Slaves)

这种结构的优点就是提供了冗余。在地理上分布的复制结构,它不存在单一节点故障问题,而且还可以将读密集型的请求放到 slave 上。

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

级联复制在一定程度上面确实解决了 Master 因为所附属的 Slave 过多而成为瓶颈的问题,但是他并不能解决人工维护和出现异常需要切换后可能存在重新搭建 Replication 的问题。这样就很自然的引申出了 DualMaster 与级联复制结合的 Replication 架构,我称之为 Master-Master-Slaves 架构

和 Master-Slaves-Slaves 架构相比,区别仅仅只是将第一级 Slave 集群换成了一台单独的 Master,作为备用 Master,然后再从这个备用的 Master 进行复制到一个 Slave 集群。

这种 DualMaster 与级联复制结合的架构,最大的好处就是既可以避免主 Master 的写入操作不会受到 Slave 集群的复制所带来的影响,同时主 Master 需要切换的时候也基本上不会出现重搭 Replication 的情况。但是,这个架构也有一个弊端,那就是备用的 Master 有可能成为瓶颈,因为如果后面的 Slave 集群比较大的话,备用 Master 可能会因为过多的 SlaveIO 线程请求而成为瓶颈。当然,该备用 Master 不提供任何的读服务的时候,瓶颈出现的可能性并不是特别高,如果出现瓶颈,也可以在备用 Master 后面再次进行级联复制,架设多层 Slave 集群。当然,级联复制的级别越多,Slave 集群可能出现的数据延时也会更为明显,所以考虑使用多层级联复制之前,也需要评估数据延时对应用系统的影响。

5. 复制的常见问题

错误一:change master 导致的:

Last_IO_Error: error connecting to master 'repl1@IP:3306' - retry-time: 60 retries

错误二:在没有解锁的情况下停止 slave 进程:

mysql> stop slave;ERROR 1192 (HY000): Can't execute the given command because you have active locked tables or an active transaction

错误三:在没有停止 slave 进程的情况下 change master

mysql> change master to master_host=‘IP', master_user='USER', master_password='PASSWD', master_log_file='mysql-bin.000001',master_log_pos=106;ERROR 1198 (HY000): This operation cannot be performed with a running slave; run STOP SLAVE first

错误四:A B 的 server-id 相同:

Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work (or the --replicate-same-server-id option must be used onslave but this does not always make sense; please check the manual before using it). 

查看 server-id

mysql> show variables like 'server_id';

手动修改 server-id

mysql> set global server_id=2; # 此处的数值和 my.cnf 里设置的一样就行 mysql> slave start;

错误五:change master 之后,查看 slave 的状态,发现 slave_IO_running 仍为 NO

需要注意的是,上述几个错误做完操作之后要重启 mysql 进程,slave_IO_running 变为 Yes

错误六:MySQL 主从同步异常 Client requested master to start replication from position > file size

字面理解:从库的读取 binlog 的位置大于主库当前 binglog 的值

这一般是主库重启导致的问题,主库从参数 sync_binlog 默认为 1000,即主库的数据是先缓存到 1000 条后统一 fsync 到磁盘的 binlog 文件中。

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

当主库重启的时候,从库直接读取主库接着之前的位点重新拉 binlog,但是主库由于没有 fsync 最后的 binlog,所以会返回 1236 的错误。

正常建议配置 sync_binlog=1 也就是每个事务都立即写入到 binlog 文件中。

1.在从库检查 slave 状态:

偏移量为 4063315

【第 33 期】高性能 MySQL:主从架构的复制原理及配置详解

2. 在主库检查 mysql-bin.001574 的偏移量位置

mysqlbinlog mysql-bin.001574 > ./mysql-bin.001574.baktail -10 ./mysql-bin.001574.bak

mysql-bin.001574 文件最后几行 发现最后偏移量是 4059237,从库偏移量的 4063315 远大主库的偏移量 4059237,也就是参数 sync_binlog=1000 导致的。

3. 重新设置 salve

mysql> stop slave;mysql> change master to master_log_file='mysql-bin.001574' ,master_log_pos=4059237;mysql> start slave;

错误七:数据同步异常情况

第一种:在 master 上删除一条记录,而 slave 上找不到。

Last_Error: Could not execute Delete_rows event on table market_edu.tl_player_task; Can't find record in 'tl_player_task', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.002094, end_log_pos 286434186

解决方法:由于 master 要删除一条记录,而 slave 上找不到故报错,这种情况主上都将其删除了,那么从机可以直接跳过。

可用命令:stop slave; set global sql_slave_skip_counter=1; start slave;

第二种:主键重复。在 slave 已经有该记录,又在 master 上插入了同一条记录。

Last_SQL_Error: Could not execute Write_rows event on table hcy.t1; Duplicate entry '2' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000006, end_log_pos 924

解决方法:在 slave 删除重复的主键

第三种:在 master 上更新一条记录,而 slave 上找不到,丢失了数据。

Last_SQL_Error: Could not execute Update_rows event on table hcy.t1;Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000010, end_log_pos 263

解决方法:把丢失的数据在 slave 上填补,然后跳过报错即可。

insert into t1 values (2,'BTV');stop slave ;set global sql_slave_skip_counter=1;start slave;

(完)


上期文章:

相关文章:

相关图书