七、MySQL主从复制详解

7.1概念

MySQL的主从复制功能是构建基于MySQL数据库的高可用、高性能的应用程序基础,既能用于分担主数据库的读负载,也为高可用HA等工作提供了更多的支持。主从复制是指数据可以从一个MySQL数据库服务器主节点复制到另外一个或多个MySQL数据库服务器从节点。主从复制可以用于数据实时备份、读写分离、高可用HA等企业场景中。

​ 在上面的模型中,MySQL-A是主服务器,即master;MySQL-B是从服务器,即slave。日志系统A其实是 MySQL日志类型中的二进制日志binlog,专门用来保存修改数据库表的所有动作。日志系统B并不是二进制 日志,而是中继日志,即relay-log,因为它是从MySQL-A的二进制日志复制过来的,并不是自己的数据库 变化产生的。这就是所谓的MySQL的主从复制。报表等读负载可以在从服务器的数据库上查询,同时当主 服务器出现问题时,可以切换到从服务器。

7.2场景用途

1)从服务器作为主服务器的实时数据备份

​ 主从服务器架构的设置可以大大加强MySQL数据库架构的健壮性。例如,做数据的热备,当主数据库 服务器故障出问题后可切换到从服务器继续提供服务,此时从服务器的从数据库的数据和宕机时的主数据 库的数据几乎是一致的,而且可以在从服务器进行备份,避免备份期间影响主服务器服务。

2)主从服务器实时读写分离,从服务器实现负载均衡

​ 主从服务器架构可通过程序(PHP、Java等)或代理数据库中间件实现对用户(客户端)的请求读写分离,如图7-2所示,即让从服务器仅仅处理用户的select查询请求,降低用户查询响应时间及读写同时在主服务器上带来的访问压力。更新的数据(例如update、insert、delete语句)仍然交给主服务器处理,以确保主服务器和从服务器保持实时同步。

3)把多个从服务器根据业务重要性进行拆分访问

​ 可以把几个不同的从服务器根据公司的业务进行拆分。例如,有为外部用户提供查询服务的从服务器,有内部DBA用来数据备份的从服务器,还有为公司内部人员提供访问的后台、脚本、日志分析及供开发人员查询使用的从服务器。这样的拆分除了减轻主服务器的压力外,还可以使数据库对外部用户浏览、 内部用户业务处理及DBA人员的备份等互不影响。

7.3 主从复制的原理及其过程描述

​ MySQL之间主从复制的基础是二进制日志文件(binary log file)。一个MySQL数据库启用二进制日志后,作为master,数据库中的所有操作都会以“事件”的方式记录在二进制日志中。其他数据库作为slave通过一个I/O线程与master保持通信,并监控master二进制日志文件的变化,如果发现master二进制日志文件发生变化,就会把变化复制到自己的中继日志中,然后由一个SQL线程把相关的“事件”执行到自己的数据库中,以实现从数据库和主数据库的一致性,也就是实现了主从复制。

​ 在主从复制的过程中,首先必须打开master主节点的binary log(binlog)功能,否则无法实现。因为整个复制过程实际上就是slave从节点从master主节点获取日志然后在自己身上完全顺序地执行日志中所记录的各种操作。

​ MySQL主从复制涉及3个线程,一个运行在主节点(log dump thread),其余两个(I/O thread、SQL thread)运行在从节点,如图7-3所示。

​ 主节点会创建一个binlog dump线程,用于发送binlog的内容。当从节点上执行start slave命令开启主从复制之后,从节点会创建一个I/O线程,用来连接主节点,并请求从指定binlog日志文件的指定位置之后的日志内容。主节点接收到来自从节点的I/O请求后,通过负责复制的binlog dump的I/O进程,根据从节点的I/O线程请求的信息分批读取binlog日志文件所指定位置之后的日志信息,返回给从节点。返回信息中除了日志所包含的信息之外,还包括本次返回信息的binlog文件名以及binlog的位置。

​ 从节点的I/O进程接收到内容后,将接收到的日志内容更新到本机的relay-log中,并将读取到的bin-log文件名和位置保存到master-info文件中,以便在下一次读取的时候能够清楚地告诉master“我需要从某个binlog的哪个位置开始往后的日志内容,请发给我”。从节点上的SQL线程会实时检测到relay log中新增加了内容,将relay log的内容解析成具体的SQL语句操作,并在从节点上按解析SQL语句的位置顺序执行和应用这些SQL语句,最终保证主从数据的一致性。

7.4主从复制的重点参数解析

​ 在MySQL数据库配置文件my.cnf中,启用主从复制过程中需要考虑的重要参数说明如下:

  • server-id:MySQL主从服务器上不能一样,这是同一组主从结构的唯一标识。

  • log-bin:开启二进制日志(搭建主从复制必须开启)。

  • binlog_format:二进制日志的格式,有statement模式(基于SQL语句的复制)、row模式(基于行 的复制)、还有mixed模式(混合复制),这里必须使用row模式。statement基于SQL语句的复制就 是记录SQL语句在binlog中,缺点是在某些情况下会导致主从节点中的数据不一致(比如sleep()、 now()等)。row基于行的复制是MySQL master将SQL语句分解为基于row更改的语句并记录在binlog 中,也就是只记录哪条数据被修改了、修改成什么样,优点是不会出现某些特定情况下被正确复制 的问题。mixed是以上两种模式的混合。

  • read_only:设置从库只读模式,可以限定普通用户进行数据修改的操作,但不会限定具有super权限的用户的数据修改操作,可以通过set global read_only=1设置从库只读状态。MySQL 5.7增加了一个super_read_only参数,一旦开启该参数,连超级管理员都没有权限进行写入操作。在MySQL slave库中设定了read_only=1以后,通过show slave status\G命令查看salve状态,发现salve仍然会读取master上的日志,并且在slave库中应用日志,不会影响slave同步复制的功能。

  • relay_log_recovery=1:当slave从库宕机后,若relay log损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的relay log,并重新从master上获取日志,这样就保证了relay log的完整性。默认情况下,该功能是关闭的,将relay_log_recovery的值设置为1时,可在slave从库上开启该功能。建议开启。

  • relay-log-info-repository=TABLE和master-info-repository=TABLE:在MySQL运行过程中宕机的话,从库启动后必须能够恢复到已经执行事务的位置,该信息传统上是存在文件中的,有可能存在不一致或者损坏的风险。从MySQL 5.7开始,可以用表来存储这些信息,并把这些表设置为InnoDB引擎,通过使用事务型存储引擎来恢复这个信息。

  • gtid_mode:是否开启gtid模式。若使用gtid模式,则设置gtid_mode=on。

  • enforce-gtid-consistency:enforce_gtid_consistency默认为off,可选[off|on],表示限定事务安全的SQL才允许被记录。例如,create table…select语句以及create temporary table语句不被允许执行。(create table … select会被拆分为两个事务,比如create table和insert事务,会导致相同的GTID分配给两个事务,从库会忽略。)

  • log_slave_updates:通常情况下,从服务器从主服务器接收到的更新不记入它的二进制日志。该选项的作用是将从master上获取数据变更的信息记录到slave的二进制日志文件中。对于级联复制 A→B→C,也就是说,A为从服务器B的主服务器,B为从服务器C的主服务器。为了能工作,B必须既为主服务器又为从服务器。除了A和B启用二进制日志外,B服务器必须启用log-slave-updates选项。另外,MySQL 5.6的GTID复制模式也必须开启log_slave_updates参数,否则启动就会报错,因为需要在bin-log找到同步复制的信息。在MySQL 5.7里,官方做了调整,用一张gtid_executed系统表记录同步复制的信息,可以不用开启log_slave_updates参数,减少了从库的压力。

7.5主从复制的部署架构

​ MySQL数据库支持单向、双向、链式级联、环状等不同业务场景的复制。在复制过程中,一台服务器充当主服务器(master),接收来自用户的内容更新,而一个或多个其他的服务器充当从服务器 (slave),接收来自主服务器binlog文件的日志内容,解析出SQL重新应用到从服务器,使得主从服务器 数据达到一致。

1)一主一从或一主多从

​ 如图7-4所示,常见的master-slaves架构(大概90%的主从复制会使用这种架构)就是一台master复制数据到一台或多台slave,将master上的读压力分散到多台slave上,因为在很多系统中读压力往往会大于写压力。

2)多级主从(级联同步)

​ 如图7-5所示,如果设置了链式级联复制,那么从服务器(slave)本身除了充当从服务器外,也会同 时充当其下面从服务器的主服务器。链式级复制类似A→B→C的复制形式,需要注意的是要复制的节点过多,会导致复制延迟。

3)双主

​ 如图7-6所示,可以搭建一个双主(master)环境,在这个双master环境里,两个MySQL Server互相将对方视为自己的master,自己作为slave。这样无论哪一方数据发生了更改都能同步到另一方,如果其中一个master停机维护,重启后也不会有任何数据问题。当然如果双master都同时提供写服务的话,也会有一定的数据冲突问题,虽然是双主,但是业务上同一时刻只允许对一个主进行写入。

4)多主一从(也称多源复制,MySQL 5.7之后开始支持)

​ 如图7-7所示,多主一从使得从机从各主机同步接收业务信息(transactions),这样可以让一部服务器为多个主机服务器备份、合并数据表、联合数据。应用场景如数据汇总,可将多个主数据库同步汇总到一个从数据库中,方便数据统计分析,从库只用于查询。

7.6异步复制

​ MySQL默认采用异步复制方式。所谓异步模式,指的是MySQL主服务器上I/O thread线程将二进制日志 写入binlog文件之后就返回客户端结果,不会考虑二进制日志是否完整传输到从服务器以及是否完整存放 到从服务器上的relay-log日志中。在这种模式下,主服务器宕机时,主服务器上已经提交的事务可能并没有传到从服务器上,如果强行将从服务器提升为主服务器,可能导致新主服务器上的数据不完整。

​ 下面看一下MySQL异步复制搭建过程,这里是基于binlog和position方式来搭建主从复制的。

1)搭建主从复制必要条件

  • 主库开启binlog功能(建议从库也开启binlog,并且开启log_slave_updates参数,方便后期扩 展架构)。

  • 主库的server-id和从库的server-id保证不能重复,MySQL同步的数据中是包含server-id的, 而server-id用于标识该语句最初是从哪个server写入,因此server-id一定要有,而且不能相同。如果server-id相同,那么同步就可能陷入死循环,会有问题。

  • 在MySQL中做主主同步时,多个主需要构成一个环状,但是同步的时候又要保证一条数据不会陷入死循环,要靠server-id来实现。

  • 为了保证后期不会出现数据不一致的情况,binlog格式要为row模式。

  • 从库设置relay-log-info-repository=TABLE、 master-info-repository=TABLE 和 relay_log_recovery=1。其中,前两个选项的作用是确保在slave上和复制相关的元数据以表的形式存放到数据库中,表采用InnoDB引擎,受到InnoDB事务安全的保护;后一个选项的作用是开启relay-log自动修复机制,发生crash时,会自动判断哪些relay-log需要重新从master上抓取回来再次应用,以此避免部分数据丢失的可能性。

  • 主库要建立主从复制账户账号(授予replication slave权限)。

2)主从复制具体搭建过程

​ 假设搭建一主一从的部署架构,master(主服务器)node0的IP地址是10.10.75.100,slave(从服务器)node1的IP地址是10.10.75.101。

  1. 修改数据库配参数文件,如图7-8所示,为主库开启binlog功能;为了便于后期架构扩展,也为从库开启binlog功能。

  1. 在主服务器node0(10.10.75.100)上建立复制账户并授权,如图7-9所示。