MySQL Replication服务

Published on 2016 - 06 - 08

引言

MySQL Replication是MySQL非常有特色的一个功能,它能够将一个MySQL Server的Instance中的数据完整复制到另外一个MySQL Server的Instance中。虽然复制过程并不是实时而是异步进行的,但是由于其高效的性能设计,延时非常之少。MySQL的Replication功能在实际应用场景中被广泛用于保证系统数据的安全性和系统可扩展设计中。本文将专门针对如何利用MySQL的Replication功能来提高系统扩展性进行详细的介绍。

Replication对可扩展性设计的意义

在互联网应用系统中,扩展最为方便的可能要数基本的Web应用服务了。因为Web应用服务大部分情况下都是无状态的,也很少须要保存太多数据,当然Session这类信息例外。所以,对于基本的Web应用服务器很容易通过简单地添加并复制应用程序来做到Scale Out。

而数据库由于其特殊的性质,就不那么容易做到方便的Scale Out。当然,各个数据库厂商一直在努力希望自己的数据库软件能够像常规的应用服务器一样方便的Scale Out,他们也确实做出了一些功能,能够基本实现像Web应用服务器一样的Scalability,如很多数据库所支持的逻辑复制功能。

MySQL数据库也为此做出了非常大的努力,其Replication功能主要就是基于这一目的所产生的。通过MySQL的Replication功能,我们可以非常方便地将一个数据库中的数据复制到很多台MySQL主机上,组成一个MySQL集群,然后通过该集群来对外提供服务。这样,每台MySQL主机所要承担的负载就会大大降低,整个集群的处理能力也很容易得到提升。

为什么通过MySQL的Replication可以做到Scale Out呢?主要是因为通过MySQL的Replication,可以将一台主机中MySQL的数据完整且同时复制到其他多个MySQL数据库中,正常情况下这种复制的延时并不长。等各台服务器上都有同样的数据之后,应用访问就不再是只能到一台数据库主机上读取数据了,而是访问整个MySQL集群中任何一台主机的数据库都可以得到相同的数据。此外还有一个非常重要的因素就是MySQL的复制非常容易实施和维护。这一点对于实施一个简单的分布式数据库集群是非常重要的,毕竟一个系统实施之后的工作主要就是维护了,一个维护复杂的系统肯定不是受欢迎的系统。

Replication机制的实现原理

要想用好一个系统,理解其实现原理是非常重要的事情,只有这样,才能够扬长避短,合理利用,搭建出最适合自己应用环境的系统,并在系统实施之后更好地维护它。

下面分析一下MySQL Replication的实现原理。

Replication线程

MySQL的Replication是一个异步的复制过程,从一个MySQL Instance(我们称之为Master)复制到另一个MySQL Instance(称之为Slave)。在Master与Slave之间的整个复制过程主要由三个线程来完成,其中两个线程(SQL线程和IO线程)在Slave端,另外一个线程(IO线程)在Master端。

要实现MySQL的Replication,首先必须打开Master端的Binary Log(mysqlbin.xxxxxx)功能。因为整个复制过程实际上就是Slave从Master端获取二进制日志,然后在自己身上完全按照产生的顺序依次执行日志中所记录的各种操作。可以在启动MySQL Server的过程中使用“—log-bin”参数选项,或者在my.cnf配置文件中的mysqld参数组([mysqld]标识后的参数部分)增加“log-bin”参数项,打开MySQL的Binary Log。

MySQL复制的基本过程如下:

  1. Slave的IO线程连接上Master,并请求日志文件的指定位置(或者从最开始的日志)之后的日志内容;
  2. Master接收到来自Slave的IO线程请求后,负责复制的IO线程根据请求信息读取指定日志位置之后的日志信息,返回给Slave端的IO线程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息在Master端的Binary Log文件的名称及位置;
  3. Slave的IO线程接收到信息后,将日志内容依次写入Slave端的Relay Log文件(mysql-relay-bin.xxxxxx)的最末端,并将读取到的Master端的bin-log的文件名和位置记录到master-info文件中,以便在下一次读取时能清楚地告诉Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”。
  4. Slave的SQL线程检测到Relay Log中新内容后,会马上解析该Log文件中的内容,还原成在Master端真实执行时的可执行Query语句,并执行这些Query。实际上就是在Master端和Slave端执行了同样的Query,所以两端的数据是完全一样的。

实际上,在老版本中,MySQL的复制实现在Slave端并不是由SQL线程和IO线程共同协作完成的,而是由一个单独的线程完成。但是MySQL的工程师们很快发现,这样做存在很大的风险和性能问题,主要如下。

首先,如果通过单一的线程来实现,就是复制Master端的Binary Log日志,以及解析这些日志,然后再在自身执行的过程成为一个串行的过程,性能自然会受到较大的限制,这种架构下的Replication的延迟就比较长了。

其次,Slave端的复制线程从Master端获取Binary Log之后,须要接着解析这些内容,并还原成Master端所执行的原始Query,然后在自身执行。在此过程中,Master端很可能又已经产生了很大的变化并生成了大量的Binary Log信息。如果这一阶段Master端的存储系统出现了无法修复的故障,那么在此期间所产生的所有变更都将永远丢失,无法再找回来。这种潜在风险在Slave端压力比较大的时候尤其突出,因为如果Slave压力比较大,解析及应用日志所花费的时间自然更长一些,可能丢失的数据也就更多。

所以,在后期的改造中,新版本的MySQL为了尽量减小这个风险,提高复制的性能,将Slave端的复制改为由两个线程来完成,即前面所提到的SQL线程和IO线程。最早提出这个改进方案的是Yahoo!的一位工程师“Jeremy Zawodny”。通过这样的改造,既在很大程度上解决了性能问题,缩短异步的延时时间,同时也减少了潜在的数据丢失量。

当然,即使是换成现在这样两个线程来协作处理,仍存在Slave数据延时及数据丢失的可能性,毕竟这个复制是异步的。只要数据的更改不是在一个事务中,这些问题都是存在的。

如果要完全避免这些问题,就只能用MySQL的Cluster来解决了。不过MySQL的Cluster直到笔者写这部分内容的时候,还是一个内存数据库的解决方案,即需要将所有数据包括索引全部都加载到内存中,对内存的要求非常大,对于一般的大众化应用来说可实施性并不是太大。当然,在之前与MySQL的CTO David交流的时候得知,MySQL正在不断改进其Cluster的实现,其中非常大的一个改动就是允许数据不用全部加载到内存中,而仅仅是索引全部加载到内存中,相信在完成该项改造之后的MySQL Cluster将会更受人欢迎,可实施性也更大。

复制实现级别

MySQL的复制可以是基于一条语句(Statement Level)或一条记录(Row level)的,你可以在MySQL的配置参数中设定复制级别,不同复制级别的设置会影响到Master端的Binary Log记录成不同的形式。

Row Level

Binary Log会记录成每一行数据被修改的形式,然后在Slave端再对相同的数据进行修改。

优点:在Row Level模式下,Binary Log可以不记录执行的Query语句的上下文相关信息,只须要记录哪一条记录被修改了,修改成什么样了。所以Row Level的日志内容会非常清楚地记录下每一行数据修改的细节,非常容易理解。而且不会出现某些特定情况下的存储过程,或Function,以及Trigger的调用和触发无法被正确复制的问题。

缺点:Row Level下,当所有的执行语句记录到Binary Log中时,都将被记录成每条记录被修改的才式,这样可能会产生大量的日志内容,比如有这样一条update语句:UPDATE group_message SET group_id = 1 WHERE group_id = 2,执行后,日志中记录的不是该语句所对应的事件(MySQL以事件的形式记录Binary Log日志),而是该语句所更新的每一条记录的变化情况,这样一条Query就被记录成更新每一条记录的很多个事件了。自然,Binary Log日志量很大。尤其是执行ALTER TABLE之类的语句时,产生的日志量更是惊人的。因为MySQL对于ALTER TABLE之类的DDL变更语句的处理方式是重建整个表的所有数据,即表中的每一条记录都要变动,那么该表的所有记录都会被记录到日志中。

Statement Level

每一条会修改数据的Query都会记录到Master的Binary Log中。Slave在复制的时候,SQL线程会解析成和原来Master端执行过的相同的Query,并再次执行。

优点:Statement Level的优点首先就是解决了Row Level下的缺点,不须要记录每一行数据的变化,减少Binary Log日志量,节约了IO成本,提高了性能。因为它只须要记录在Master上所执行的语句的细节,以及执行语句时上下文的信息。

缺点:由于它记录的是执行语句,为了让这些语句在Slave端也能正确执行,那么它还必须记录每条语句在执行时的一些相关信息,即上下文信息,以保证所有语句在Slave端被执行的时候能够得到和在Master端执行时相同的结果。另外,由于MySQL现在发展比较快,很多新功能不断加入,使得MySQL复制遇到了不小的挑战,复制时涉及的内容越复杂,就越容易出现Bug。在Statement Level下,目前已经发现的就有不少情况会造成MySQL的复制出现问题,主要是在修改数据时使用了某些特定的函数或功能后出现,比如:sleep()函数在有些版本中就不能正确复制,在存储过程中使用了last_insert_id()函数,可能会使Slave和Master得到不一致的ID,等等。由于Row Level是基于每一行来记录的变化,所以不会出现类似问题。

Mixed Level

在Mixed模式下,MySQL会根据执行的每一条具体的Query语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。除了MySQL认为通过Statement方式可能造成复制过程中Master与Slave之间产生不一致数据(如特殊Procedure和Function的使用,UUID()函数的使用等特殊情况)时,它会选择ROW的模式来记录变更之外,都会使用Statement模式来记录。当然,这里须要排除的特殊情况并不仅仅是上面所描述的几种,具体请参考MySQL官方的详细手册。

从MySQL官方文档可以看出,之前的MySQL一直都只有基于Statement的复制模式,直到5.1.5版本才开始支持Row Level的复制。从5.0开始,MySQL的复制已经解决了大量老版本中出现的无法正确复制的问题。但是由于存储过程的出现,给MySQL的复制又带来了更大的新挑战。另外,看到官方文档说,从5.1.8版本开始,MySQL提供了Statement Level和Row Level之外的第三种复制模式:Mixed Level。新版本中的Statment Level还是和以前一样,仅仅记录执行的语句。而对Row Level模式做了优化,并不是所有的修改都会以Row Level来记录,像遇到表结构变更的时候就会以Statement模式来记录,如果Query语句确实就是UPDATE或DELETE等修改数据的语句,那么还是会记录所有变化行的变更。

Replication常用架构

MySQL Replicaion是比较简单的架构,就是一台MySQL服务器(Slave)从另一台MySQL服务器(Master)进行日志的复制,然后再解析日志并应用到自身。一个复制环境仅仅须要两台运行有MySQL Server的主机即可,更为简单的时候甚至可以在同一台物理服务器主机上启动两个MySQL Instance,一个作为Master而另一个作为Slave来完成复制环境的搭建。但是在实际应用环境中,可以根据实际的业务需求利用MySQL Replication的功能定制搭建出其他多种更利于Scale Out的复制架构。如Dual Master架构,级联复制架构等。下面针对比较典型的三种复制架构进行相应的分析介绍。

常规复制架构(Master-Slaves)

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

这个架构可以通过Master-Slave复制架构图(图1)比较清晰地展示。

一个Master复制多个Slave的架构实施非常简单,多个Slave和单个Slave的实施并没有实质性的区别。在Master端并不Care有多少个Slave连接了自己,只要有Slave的IO线程通过了连接认证,向它请求指定位置之后的Binary Log信息,它就会按照该IO线程的要求,读取自己的Binary Log信息,返回给Slave的IO线程。

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

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

对于Replication的配置细节,在MySQL的官方文档上已经说得非常清楚了,甚至介绍了多种实现Slave的配置方式,在下一节中也会通过一个具体的示例来演示搭建一个Replication环境的详细过程及注意事项。

Dual Master复制架构(Master-Master)

有些时候,简单地从一个MySQL复制到另一个MySQL的基本Replication架构,可能还会须要在一些特定的场景下进行Master的切换。如在Master端须要进行一些特别的维护操作时,可能须要停止MySQL的服务。这时候,为了尽可能减少应用系统写服务的停机时间,最佳做法就是将Slave节点切换成Master来提供写入的服务。

但是这样一来,原来Master节点的数据就会和实际的数据不一致了。当原Master启动可以正常提供服务的时候,由于数据不一致,不得不通过反转原Master-Slave关系,重新搭建Replication环境,并以原Master作为Slave来对外提供读服务。重新搭建Replication环境会给我们带来很多额外的工作量,如果没有合适的备份,可能还会让Replication的搭建过程非常麻烦。

为了解决这个问题,可以通过搭建Dual Master环境来处理。何谓Dual Master环境?实际上就是两个MySQL Server互相将对方作为自己的Master,自己作为对方的Slave来进行复制。这样,任何一方所做的变更,都会通过复制应用到另外一方的数据库中。

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

Dual-Master架构图(图2)将更清晰的展示Dual Master复制架构组成:

通过Dual Master复制架构,能够避免正常的常规维护操作需要的停机所带来的重新搭建Replication环境的操作,因为任何一端都记录了自己当前复制到对方的什么位置了,在系统搭建之后,它就会自动从之前的位置开始重新复制,不需要人为地干预,大大节省了维护成本。

不仅如此,Dual Master复制架构和一些第三方的HA管理软件结合,还可以在当前使用的Master出现异常无法提供服务之后,非常迅速地自动切换另外一端来提供相应的服务,减少异常情况下带来的停机时间,也不需要人工干预。

当然,搭建一个Dual Master环境,并不是为了让两端都提供写的服务。在正常情况下,我们只会将其中一端开启写服务,另外一端仅仅提供读服务,或者完全不提供任何服务,只是作为一个备用的机器存在。为什么一般都只开启其中的一端来提供写服务呢?主要还是为了避免数据的冲突,防止造成数据的不一致性。因为即使在两边执行的修改有先后顺序,但由于Replication是异步的实现机制,同样会导致晚做的修改也可能会被早做的修改所覆盖,就像如下情形,见表1:

这种情形下,不仅在B库的数据不是用户所期望的结果,A和B两边的数据也出现了不一致。

当然,也可以通过特殊的约定,让某些表的写操作全部在一端,而另外一些表的写操作全部在另外一端,保证两端不会操作相同的表,这样就能避免上面问题的发生了。

级联复制架构(Master-Slaves-Slaves...)

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

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

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

当然,如果条件允许,更倾向于建议大家通过拆分成多个Replication集群来解决上述瓶颈问题。毕竟Slave并没有减少写的量,它实际上仍然应用了所有的数据变更操作,没有减少任何写IO。相反,Slave越多,整个集群的写IO总量也就会越多,我们没有非常明显的感觉,只是因为分散到了多台机器上面,所以不是很容易表现出来。

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

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

Dual Master与级联复制结合架构(Master-Master-Slaves)

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

和Master-Slaves-Slaves架构相比,区别只是将第一级Slave集群换成了一台单独的Master,作为备用Master,然后再从这个Master复制到一个Slave集群。下面的组合复制架构图(图4)更清晰地展示了这个架构的组成:

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

Replication搭建实现

MySQL Replication环境的搭建实现比较简单,总的来说有四步:第一步是做好Master端的准备工作。第二步是取得Master端数据的“快照”备份。第三步则是在Slave端恢复Master的备份“快照”。第四步就是在Slave端设置Master相关配置,然后启动复制。在本节中,并不是列举一个搭建Replication环境的详细过程,因为这在MySQL官方操作手册中已经有较为详细的描述了,主要是针对搭建环境中4个主要的操作步骤中可以使用的各种实现方法进行介绍,并针对这四步操作及须要注意的地方进行简单的分析。

Master端准备工作

在搭建Replication环境之前,首先要保证Master端MySQL记录Binary Log的选项打开,因为MySQL Replication就是通过Binary Log来实现的。让Master端MySQL记录Binary Log可以在启动MySQL Server的时候使用—log-bin选项,或者在MySQL的配置文件my.cnf中配置log-bin[=path for binary log]参数选项。

在开启了记录Binary Log功能之后,还须要准备一个用于复制的MySQL用户。可以通过给一个现有账户授予复制相关的权限,也可以创建一个全新的专用于复制的账户。不过,还是建议用一个专用于复制的账户。实现MySQL Replication仅仅需要“REPLICATION SLAVE”权限即可。可以通过如示例代码1的方式来创建这个用户:

这里首先通过CREATE USER命令创建了一个仅仅具有最基本权限的用户repl,再通过GRANT命令授予该用户REPLICATION SLAVE的权限。当然,也可以只执行上面的第二条命令,创建出我们所需的用户,这已经在第4章(“MySQL安全管理”)中介绍过了。

获取Master端的备份“快照”

这里所说的Master端备份“快照”,并不是特指通过类似LVM等软件所做的Snapshot,而是所有数据均基于某一特定时刻,数据完整性和一致性都可以得到保证的备份集。同时还须要取得该备份集时刻所对应的Master端Binary Log的准确Log Position,因为在后面配置Slave的时候会用到。

一般来说,可以通过如下几种办法获得一个具有一致性和完整性的备份集,以及所对应的Log Position。

  • 通过数据库全库冷备份。

对于可以停机的数据库,可以通过关闭Master端MySQL,再拷贝所有数据文件和日志文件到须要搭建Slave的主机中的合适位置,这样所得到的备份集是最完整的。在做完备份之后,再启动Master端的MySQL。

当然,这样还只是得到了一个满足要求的备份集,还需要这个备份集所对应的日志位置才可以。对于这样的备份集,有多种方法可以获取到对应的日志位置。如在Master刚刚启动,还没有应用程序连接上Master之前,通过执行SHOW Master STATUS命令从Master端获取到可以使用的Log Position。如果无法在Master启动之后控制应用程序的连接,那么可能在还没有来得及执行SHOW Master STATUS命令之前就已经有数据写进来了,此时可以通过mysqlbinlog客户端程序分析Master最新的Binary Log来获取其第一个有效的Log Position。当然,如果你非常清楚自己所使用的MySQL版本每一个新的Binary Log第一个有效的日志位置,自然就无须进行任何操作了。

  • 通过LVM或ZFS等具有Snapshot功能的软件进行“热备份”。

如果Master是一个须要满足365×24×7服务的数据库,那么就无法通过冷备份来获取所需要的备份集。这时候,如果MySQL在支持Snapshot功能的文件系统上面(如ZFS)运行,或者文件系统虽然不支持Snapshot,但是文件系统在LVM上面运行,那么可以通过相关的命令对MySQL的数据文件和日志文件所在的目录做一个Snapshot,这样就可以得到一个和全库冷备差不多的备份集。

当然,为了保证备份集数据能够完整且一致,须要在进行Snapshot过程中通过相关命令(FLUSH TABLES WITH READ LOCK)来锁住所有表的写操作,也包括支持事务的存储引擎中commit动作,这样才能真正保证该Snapshot的所有数据都完整一致。在做完Snapshot之后,就可以UNLOCK TABLES了。可能有些人会担心,如果锁住了所有的写操作,那应用不是就无法提供写服务了么?确实,这是无法避免的,不过,一般来说Snapshot操作所需要的时间大都比较短,所以不会影响太长时间。

那Log Position怎么办呢?是的,通过Snapshot所做的备份,同样需要一个该备份所对应的Log Position,才能满足搭建Replication环境的要求。不过,这种方式下,我们可以比进行冷备份更容易获取到对应的Log Position。因为从锁定了所有表的写入操作开始到解锁之前,数据库不能进行任何写入操作,这个时间段之内任何时候通过执行SHOW MASTER STATUS命令都可以得到准确的Log Position。

由于这种方式在实施过程中并不须要完全停掉Master,只须要停止写入操作,所以也可以称之为“热备份”。

  • 通过mysqldump客户端程序导出逻辑数据序。

如果数据库不能停机进行冷备份,而且MySQL也没有运行在可以进行Snapshot的文件系统或管理软件之上,那么就要通过mysqldump工具将Master端需要复制的数据库(或者表)的数据dump出来。为了让备份集具有一致性和完整性,我们必须确保dump数据的这个过程处于同一个事务中,或者锁住所有需要复制的表的写操作。如果所使用的是支持事务的存储引擎(如InnoDB),可以在执行mysqldump程序的时候通过添加—single-transaction选项,但是如果存储引擎并不支持事务,或者须要dump的表只有部分支持事务时,就只能先通过FLUSH TABLES WITH READ LOCK命令来暂停所有写入服务,然后再dump数据了。当然,如果只需要dump一个表的数据,就不需要这么麻烦了,因为mysqldump程序在dump数据时实际上每个表是通过一条Query来得到数据的,所以单个表的时候总是可以保证所取数据的一致性的。

上面的操作还只是获得了合适的备份集,还没有获得该备份集所对应的Log Position,所以还不能完全满足搭建Slave的要求。幸好mysqldump程序的开发者早就考虑到这个问题了——给mysqldump程序增加了另外一个参数选项来帮助获取到对应的Log Position,这个参数选项就是—master-data。在添加这个参数选项之后,mysqldump会在dump文件中产生一条CHANGE MASTER TO命令,命令中记录了dump时刻所对应的详细的Log Position信息。如下。

测试dump example数据库下的group_message表(如代码2):

然后通过grep命令来查找一下看看(如代码3):

连CHANGE MASTER TO的命令都已经准备好了,还真够体贴的,呵呵。

如果我们要一次性dump多个支持事务的表,可能很多人会选择通过添加—single-transaction选项来保证数据的一致性和完整性。这选择确实不错。但是,如果须要dump的数据量比较大时,可能会产生一个很大的事务,而且会持续较长的时间。

  • 通过现有某一个Slave端进行“热备份”。

如果现在已经有Slave从须要搭建Replication环境的Master上进行复制的话,那这个备份集就非常容易取得了。我们可以暂时性地停掉现有Slave(如果有多台则仅仅需要停止其中的一台),同时执行一次FLUSH TABLES命令来刷新所有表和索引的数据。这时候在该Slave上面就不会再有任何的写入操作了,既可以通过拷贝所有的数据文件和日志文件来做一个全备份,也可以通过Snapshot(如果支持)来进行备份。当然,如果支持Snapshot功能,还是建议大家通过Snapshot来做,因为这样可以使Slave停止复制的时间大大缩短,减少该Slave的数据延时。

通过现有Slave来获取备份集的方式,不仅得到数据库备份的方式很简单,连所需要Log Position,甚至是新Slave后期的配置等相关动作都可以省略掉,只需要新的Slave完全基于这个备份集来启动,就可以从Master进行正常复制了。

整个过程中只是在短暂时间内停止了某台现有Slave的复制线程,对系统的正常服务影响很小,所以这种方式也基本可以称之为“热备份”。

Slave端恢复备份“快照”

上面第二步已经获取了需要的备份集,这一步要将上一步所得到的备份集恢复到Slave端的MySQL中。

针对上面4种方法所获取的备份集的不同,在Slave端的恢复操作也有区别,下面就做一个简单的说明。

  • 恢复全库冷备份集。

由于这个备份集是完整的数据库物理备份,我们只须要将这个备份集通过FTP或SCP之类的网络传输软件复制到Slave所在的主机,根据Slave上my.cnf配置文件的设置,将文件存放在相应的目录,覆盖现有的所有数据和日志等相关文件,再启动Slave端的MySQL,就完成了整个恢复过程。

  • 恢复对Master进行Snapshot得到的备份集。

对于通过对Master进行Snapshot所得到的备份集,实际上和全库冷备份的恢复方法基本一样,唯一的差别只是首先须要将该Snapshot通过相应的文件系统mount到某个目录下,然后才能进行后续的文件拷贝操作。之后的操作与恢复全库冷备份集基本一致,就不再赘述。

  • 恢复mysqldump得到的备份集。

通过mysqldump客户端程序所得到的备份集,和前面两种备份集的恢复方式有较大的差别。因为前面两种备份集的都属于物理备份,而通过mysqldump客户端程序所做的备份属于逻辑备份。恢复mysqldump备份集的方式是通过MYSQL客户端程序来执行备份文件中的所有Query语句。

使用MYSQL客户端程序在Slave端恢复之前,建议复制出通过—master-data所得到的CHANGE MASTER TO命令部分,然后在备份文件中注销掉该部分,再进行恢复。因为该命令并不是一个完整的CHANGE MASTER TO命令,如果在配置文件(my.cnf)中没有配置MASTER_HOST、MASTER_USER、MASTER_PASSWORD这三个参数,该语句无法有效完成。

通过mysql客户端程序来恢复备份的方式如示例代码4所示:

这样即可将之前通过mysqldump客户端程序所做的逻辑备份集恢复到数据库中了。

  • 恢复通过现有Slave所得到的热备份。

通过现有Slave所得到的备份集和上面第一种或第二种备份集也差不多。如果是通过直接拷贝数据和日志文件所得到的备份集,那么就是和全库冷备一样的备份方式,如果是通过Snapshot得到的备份集,就和第二种备份恢复方式完全一致。

配置并启动Slave

在完成了前面三个步骤之后,Replication环境的搭建就只需要最后的一个步骤了,那就是通过CHANGE MASTER TO命令来配置,然后再启动Slave。

CHANGE MASTER TO命令总共需要设置5项内容,分别为:

  • MASTER_HOST:Master的主机名(或者IP地址);
  • MASTER_USER:Slave连接Master的用户名,实际上就是之前所创建的repl用户;
  • MASTER_PASSWORD:Slave连接Master的用户的密码;
  • MASTER_LOG_FILE:开始复制的日志文件名称;
  • MASTER_LOG_POS:开始复制的日志文件的位置,也就是在之前介绍备份集过程中一致提到的Log Position。

示例代码5是一个完整的CHANGE MASTER TO命令示例:

执行完CHANGE MASTER TO命令之后,就可以通过如示例代码6中的命令启动SLAVE了:

至此,Replication环境就搭建完成了。读者朋友可以自己进行相应的测试来尝试搭建,如果须要了解MySQL Replication搭建过程中更为详细的步骤,可以查阅MySQL官方手册。

参考文档