高性能MySQL(第三版)第十章:复制

10.1 复制概述

  • 复制解决的基本问题是让一台服务器的数据与其他服务器保持同步。
  • MySQL支持两种复制方式:基于行的复制和基于语句的复制。
  • 这两种方式都是通过主库上记录的二进制日志,在备库重放日志的方式来实现异步的数据复制。
  • 都是通过主库上记录二进制日志,虽然有开销,但是不会很大。
  • 同一时间点备库上的数据可能与主库存在不一致性,并无法保证主备之间的延迟。
  • 通过复制可以将读操作指向备库来获得更好地读扩展。
  • 目前备库只能串行化执行。

10.1.1 复制解决的问题

  • 数据分布 基于行的复制比基于语句的复制模式的带宽压力更大。
  • 负载均衡 将读操作分布到多个服务器上,实现对读密集型应用的优化。
  • 备份 复制是对备份的补充,但不是备份。
  • 高可用性和故障切换 能够帮助程序避免MySQL单点失败
  • MySQL升级 使用一个更高版本的MySQL作为备库,保证在升级全部实例之前,查询能够在备库按照预期执行。

10.1.2 复制如何工作

  • 主库把数据更改记录到二进制日志中。

  • 备库将主库上的日志复制到自己的中继日志中。

  • 备库读取中继日志中的事件,将其重放到备库数据之上。
    MySQL复制如何工作
    MySQL会按事务提交的顺序而非每条语句的执行顺序来记录二进制文件。

  • 这种复制架构实现了获取事件和重放事件的解耦,允许这两个过程异步进行。也就是说I/O线程能够独立于SQL线程之外工作。

  • 主库上并发运行的查询在备库只能串行执行,因为只有一个SQL线程来重放中继日志中的事件。

10.2 配置复制

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

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

具体操作查看书包内容。

初始化备库或者从其他服务器克隆数据到备库。

  • 从主库复制数据
  • 从另外一台备库克隆数据
  • 使用最近的一次备份来启动备库

添加新slave服务器

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

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

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

  • 冷拷贝(cold copy)
    停止master,将master的文件拷贝到slave;然后重启master。缺点很明显。
  • 热拷贝(warm copy)
    如果你仅使用MyISAM表,你可以使用mysqlhotcopy拷贝,即使服务器正在运行。
  • 使用mysqldump
  • 使用快照或者备份
  • 使用 Percona Xtrabackup
  • 使用另外的备库

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

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

  2. 在另一个连接用mysqldump创建一个你想进行复制的数据库的转储:shell> mysqldump --all-databases --lock-all-tables >dbdump.db

  3. 对表释放锁。mysql> UNLOCK TABLES;

10.3 复制原理

10.3.1 基于语句的复制

主库会记录那些造成数据更改的查询,当备库读取并重放这些事件时,实际上只是把主库上执行过的SQL再执行一遍。
优点:

  • 实现简单,因为二进制日志里面事件比较紧凑,所以不会占用太多的带宽。
  • 主备的模式不同时,逻辑复制可以在多种情况下复制,允许灵活操作。

缺点:

  • 无法正确的复制
  • 除了查询语句还需要注意一些元数据,如当前的时间戳等。
  • 存储过程和触发器在此种方式中也会存在问题
  • 更新必须是串行的

10.3.2 基于行的复制

从MySQL 5.1开始支持, 将实际数据记录在二进制日志中。
优点

  • 可以正确的复制每一行,一些语句可以被更加有效的复制。
  • 几乎没有不能处理的场景
  • 可以减少锁的使用
  • 占用更少的CPU

缺点

  • 一些二进制日志文件可能会比较大,不直观,所以不能使用mysql binlog来查看二进制日志。
  • 试图做一些备库修改表这样的事情时可能导致复制失败。
  • 由于语句没有记录在日志里,所以不知道执行了那些SQL。

10.3.3 复制相关的文件

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

  1. mysql-bin.index
    服务器一旦开启二进制日志,会产生一个与二日志文件同名,但是以.index结尾的文件。它用于跟踪磁盘上存在哪些二进制日志文件。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。

  4. relay-log.info
    包含slave中当前二进制日志和中继日志的信息。

10.3.4 发送复制事件到其它slave

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

10.3.5 复制过滤(Replication Filters)

复制过滤可以让你只复制服务器中的一部分数据,有两种复制过滤:

  • 在master上过滤二进制日志中的事件;
  • 在slave上过滤中继日志中的事件。

如下:
在这里插入图片描述

10.4 复制的常用拓扑结构

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

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

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

10.4.1 单一master和多slave

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

在实际应用场景中,MySQL复制90%以上都是一个Master复制到一个或者多个Slave的架构模式,主要用于读压力比较大的应用的数据库端廉价扩展解决方案。因为只要Master和Slave的压力不是太大(尤其是Slave端压力)的话,异步复制的延时一般都很少很少。尤其是自从Slave端的复制方式改成两个线程处理之后,更是减小了Slave端的延时问题。而带来的效益是,对于数据实时性要求不是特别Critical的应用,只需要通过廉价的pcserver来扩展Slave的数量,将读压力分散到多台Slave的机器上面,即可通过分散单台数据库服务器的读压力来解决数据库端的读性能瓶颈,毕竟在大多数数据库应用系统中的读压力还是要比写压力大很多。这在很大程度上解决了目前很多中小型网站的数据库压力瓶颈问题,甚至有些大型网站也在使用类似方案解决数据库瓶颈。
在这里插入图片描述
如果写操作较少,而读操作很时,可以采取这种结构。你可以将读操作分布到其它的slave,从而减小master的压力。但是,当slave增加到一定数量时,slave对master的负载以及网络带宽都会成为一个严重的问题。
这种结构虽然简单,但是,它却非常灵活,足够满足大多数应用需求。一些建议:

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

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

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

10.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中,就更不用担心可能会出现循环复制的情形了。
在这里插入图片描述
主动的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结合起来,可以建立强大的高性能的数据库平台。但是,可以通过其它一些方式来模拟这种多主服务器的复制。

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

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

10.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架构。
在这里插入图片描述
当然,如果条件允许,我更倾向于建议大家通过拆分成多个Replication集群来解决

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

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

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

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

这种结构的优点就是提供了冗余。在地理上分布的复制结构,它不存在单一节点故障问题,而且还可以将读密集型的请求放到slave上。
在这里插入图片描述
级联复制在一定程度上面确实解决了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集群可能出现的数据延时也会更为明显,所以考虑使用多层级联复制之前,也需要评估数据延时对应用系统的影响。

10.4.6 定制的复制方案

选择复制
为了利用访问局部性原理,并将需要读的工作驻留在内存中,可以复制少量数据到备库中。在主库上写,在备库上读。主库包含了所有的数据,这样在写的时候无需访问多个服务器。

最简单的方法是在主库上将数据划分到不同的数据库里,然后将每个数据库复制到不同的备库中。也可以通过一个分发主库进行分发。

分离功能
许多应用都混合了先线性事务处理(OLTP)和在线数据分析(OLAP)的查询。OLTP查询比较短且是事务型的,OLAP查询通常很大,也很慢,并且不要求是最新的数据。

这两种查询需要的配置,甚至是存储引擎或者硬件都不相同。黑服务器带来的负担完全不同。

常见的方法是将OLTP服务器的数据复制到OLAP工作负载准备的备库上。配置不同的硬件、存储引擎等。

数据归档

  • 一种方式是将SQL_LOG_BIN设置为0,然后再进行数据清理。
  • 在清理数据之前对主库上特定的数据库使用use语句。

将备库用作全文检索
将备库设置为MyISAM引擎,然后创建全文索引。主库还是可以继续支持事务。

只读备库
将备库设置为只读,防止在备库进行无意识修改导致复制中断。通过设置read_only选项来实现。它会禁止大部分写操作,除了复制线程和拥有超级权限的用户以及零时表操作。

创建日志服务
目的是更加容易重放并且/或者过滤二进制日志文件,它对崩溃后重启复制很有帮助。

10.5 复制和容量规划

主备库的模式下,并不是增加备库就能线性增加读写功能。并且在开启复制功能时,要考虑监控延时,可用性。

10.6 MySQL复制的高级特性

半同步复制
可以帮助确保备库拥有主库数据的拷贝,减少潜在的数据丢失危机。有助于备库提供更好地冗余度和持久性。 半同步复制在提交过程中增加一个延迟:当提交事务时,在客户端接收到查询结束反馈前必须保证二进制日志已经传输 到至少一台备库上。

  • 在主库上已经完成事务提交,只有通知客户端被延迟了。
  • 备库在接收到事务后发送反馈而非(备库)完成事务后发送。
  • 如果备库一直没有回应已收到事件,会超时并转化为正常的异步复制模式。

复制心跳
保持备库一直与主库相联系,避免悄无声息地断开连接。

10.7 总结

  • KISS原则(Keep It Simple Stupid),用简单的就好。
  • 监控。
  • 理解复制的异步本质,且设计你的应用避免或容忍从备库读取脏数据。
  • 在一个复制拓扑中不要写入多于一个服务器,把备库配置为只读,并降低权限以阻止对数据的改变。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值