一、为什么要进行主从复制

主从复制、读写分离一般是一起使用的。目的很简单,就是为了提高数据库的并发性能。你想,假设是单机,读写都在一台MySQL上面完成,性能肯定不高。如果有三台MySQL,一台mater只负责写操作,两台salve只负责读操作,性能不就能大大提高了吗?

所以主从复制、读写分离就是为了数据库能支持更大的并发。

随着业务量的扩展、如果是单机部署的MySQL,会导致I/O频率过高。采用主从复制、读写分离可以提高数据库的可用性。

主从复制的作用:

做数据的热备,作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。
架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的评率,提高单个机器的I/O性能。
读写分离,使数据库能支持更大的并发。在报表中尤其重要。由于部分报表sql语句非常的慢,导致锁表,影响前台服务。如果前台使用master,报表使用slave,那么报表sql将不会造成前台锁,保证了前台速度。

 1--在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力;(主库写,从库读,降压)
 2--在从主服务器进行备份,避免备份期间影响主服务器服务;(确保数据安全)
 3--当主服务器出现问题时,可以切换到从服务器。(提升性能)

二、主从复制的原理

Mysql的主从复制中主要有三个线程:master(binlog dump thread)、slave(I/O thread 、SQL thread),Master一条线程和Slave中的两条线程。

master(binlog dump thread)主要负责Master库中有数据更新的时候,会按照binlog格式,将更新的事件类型写入到主库的binlog文件中。并且,Master会创建log dump线程通知Slave主库中存在数据更新,这就是为什么主库的binlog日志一定要开启的原因。

I/O thread线程在Slave中创建,该线程用于请求Master,Master会返回binlog的名称以及当前数据更新的位置、binlog文件位置的副本。然后,将binlog保存在 中继日志(relay log) 中,中继日志也是记录数据更新的信息。

SQL线程也是在Slave中创建的,当Slave检测到中继日志有更新,就会将更新的内容同步到Slave数据库中,这样就保证了主从的数据的同步。

mysql主备和灾备 mysql主备作用_主从复制


三、主从复制的类型

主从复制的过程有不同的策略方式进行数据的同步,主要包含以下几种:

  1. 「同步策略」:Master会等待所有的Slave都回应后才会提交,这个主从的同步的性能会严重的影响。
  2. 「半同步策略」:Master至少会等待一个Slave回应后提交。
  3. 「异步策略」:Master不用等待Slave回应就可以提交。
  4. 「延迟策略」:Slave要落后于Master指定的时间。

四、异步主从复制

4.1 一主一从主从复制

在上文操作的基础上,首先我们需要再在一个新的虚拟机上安装设置mysql,将server1上编译好的包拷贝到server2上:

mysql主备和灾备 mysql主备作用_mysql_02

将刚刚更改的两个配置文件复制到server2上去:

mysql主备和灾备 mysql主备作用_主从复制_03

刚才server1的操作再在server2上再做一遍:

mysql主备和灾备 mysql主备作用_架构_04

mysql主备和灾备 mysql主备作用_数据库_05

 此时server2上的mysql初始化完成,可以正常使用:

mysql主备和灾备 mysql主备作用_mysql主备和灾备_06

此过程可完全按照mysql官网文档来:MySQL :: MySQL 5.7 Reference Manual :: 16 Replication

 在server1上:

编辑 /etc/my.cnf :

mysql主备和灾备 mysql主备作用_mysql主备和灾备_07

重启mysqld使之生效:

mysql主备和灾备 mysql主备作用_主从复制_08

 

mysql主备和灾备 mysql主备作用_数据库_09

此时已经在数据目录里生成了二进制日志文件:

 

mysql主备和灾备 mysql主备作用_数据库_10

此时的二进制日志文件编号为595,因为你所做的操作都会以追加的方式被记录在二进制日志文件内,而编号就是记录操作指令,595就是最后的一个编号。编号可以控制slave端复制的时候从哪开始复制。

mysql主备和灾备 mysql主备作用_数据库_11

 在server2上:

在slave备机上可以不设置binlog,可以不用启用binlog。

 

mysql主备和灾备 mysql主备作用_数据库_12

通过 /etc/init.d/mysqld restart 重启服务。进入数据库设置:

mysql> CHANGE MASTER TO
    ->     MASTER_HOST='source_host_name',
    ->     MASTER_USER='replication_user_name',
    ->     MASTER_PASSWORD='replication_password',
    ->     MASTER_LOG_FILE='recorded_log_file_name',
    ->     MASTER_LOG_POS=recorded_log_position;

mysql主备和灾备 mysql主备作用_架构_13

mysql主备和灾备 mysql主备作用_主从复制_14

  

回到server1上创建数据库:

mysql主备和灾备 mysql主备作用_数据库_15

 创建完成后,在server2的数据库上查看server2上也有了刚刚创建的westos库。

注:如果server1上已经建立了数据库、表或者写入了数据。那么server2上也需要先存在这些东西,这是因为二进制文件里记录的是执行的动作,从机来复制这些动作。从机里没有被操作的东西,那就无法执行动作。如果server1的mysql是全新的话,则可以直接继续设置server2。

mysql主备和灾备 mysql主备作用_架构_16

 此数据库是从server1 master上自动复制过去的,但是这种复制是单向的,一般主从复制slave端mysql都要设置成只读模式,不能在slave上写入数据,因为这样的话数据就不同步了。

各个server上的索引文件可以记录各个server上的中继日志:

mysql主备和灾备 mysql主备作用_mysql_17

 

mysql主备和灾备 mysql主备作用_mysql主备和灾备_18

4.2 一主多从主从复制(线性主从)

上面我们介绍的是一主一从架构,也有一主多从架构,一主多从架构适合于读多写少的情景,即读的请求要远远大于写的请求。我们再扩一个节点做一主多从架构。与刚刚在server2上开启mysql服务类似。下面我们搭建的是 A-->B-->C 的线性一主多从架构:

mysql主备和灾备 mysql主备作用_数据库_19

mysql主备和灾备 mysql主备作用_数据库_20

在server3上,在my.cnf中更改server-id:

 

mysql主备和灾备 mysql主备作用_数据库_21

mysql主备和灾备 mysql主备作用_数据库_22

 此时server3上的mysql初始化完毕。由于我们server3上的数据要从server2上拿,所以在server2上要开启二进制日志文件,并且加上log-slave-updates选项:

mysql主备和灾备 mysql主备作用_mysql_23

设置完成后在server2上也创建了mysql-bin 文件。在server1上再插入数据,查看server2上的mysql-bin 发现在server1上的操作已经被记录了下来。

mysql主备和灾备 mysql主备作用_架构_24

 由于之前server1、2上的数据库已经存储了部分数据,所以我们先把其中的数据库备份出来,导入到server3中:

mysql主备和灾备 mysql主备作用_数据库_25

注:用mysqldump导入时会有一个坑,在导入同名数据库时,会先删除再导入:

 

mysql主备和灾备 mysql主备作用_架构_26

 先建立一个同名的库,再将数据导入进去。

 

mysql主备和灾备 mysql主备作用_mysql_27

 

mysql主备和灾备 mysql主备作用_架构_28

 原来的库导入完成!在server2上创建repl用户并寄予权限:

mysql主备和灾备 mysql主备作用_架构_29

刷新一下授权表:

 

mysql主备和灾备 mysql主备作用_架构_30

在server2上查看master status :

mysql主备和灾备 mysql主备作用_mysql_31

 在server3上设置从server2复制数据库信息:

mysql主备和灾备 mysql主备作用_mysql主备和灾备_32

 IO和SQL线程均为YES,说明设置没问题。

测试:在server1的数据库上添加信息:

mysql主备和灾备 mysql主备作用_mysql主备和灾备_33

我们可以直接查看server3的数据库是否复制成功,若是复制成功那么server2一定复制成功:

mysql主备和灾备 mysql主备作用_主从复制_34

 线性的一主多从mysql设置成功!这样设置的好处是可以减小server1端的压力。

mysql默认情况下是以异步的方式将binlog的更新发送到slave端,虽然速度很快,但是此种方式并不关心slave端是否接受到binlog信息,当网络复杂不稳定时就会出问题。

4.3 基于GTID的异步主从复制(非线性)

GTID (Golobal Transaction ID) 是对于一个已提交事务的唯一编号,并且是一个全局(主从复制)唯一的编号。

GTID 复制和传统复制的区别:在启动主从复制时,不需要指定 binlog 文件名和 postion 号,直接 auto 即可。MySQL 会自动读取最后一个 relay,获取到上次已经复制的 GTID 号,从此号码开始向后复制即可。在 MHA 高可用环境下,在主库无法 SSH 时,从库进行数据补偿更加便捷。


在GTID主从复制中,每个mysql数据库上都有一个唯一uuid,每个事务生成一个id,gtid由上面两者组合: uuid+事务id。

mysql主备和灾备 mysql主备作用_mysql主备和灾备_35

使用GTID方式进行主从复制,当master挂掉时,会自动切换到里自己最近的一台slave上。

在server2上关闭slave,将其配置成GTID模式,在server1上打开GTID模式:

server1:

mysql主备和灾备 mysql主备作用_数据库_36

mysql主备和灾备 mysql主备作用_mysql_37

 server2:

mysql主备和灾备 mysql主备作用_mysql_38

 

mysql主备和灾备 mysql主备作用_主从复制_39

(注:该slave服务是开机自启的,设置时restart完了记得再关闭一次):

mysql主备和灾备 mysql主备作用_mysql主备和灾备_40

可以使用 show slave status\G;  查看slave状态。在server3上同样的配置再来一遍:

mysql主备和灾备 mysql主备作用_mysql_41

mysql主备和灾备 mysql主备作用_mysql_42

测试: 在server1上添加数据:

mysql主备和灾备 mysql主备作用_数据库_43

 server2和server3上的数据已经同步。(注:此时我们server2、3的数据都是直接由server1复制来的,不是线性复制了)

mysql主备和灾备 mysql主备作用_mysql_44

当集群的master挂掉后,自动寻找最近的一个slave进行接管,slave变成master后,另外的slave在同步数据时并不需要知道此时复制的binlog号到哪了,因在在采用GTID模式时,就会自动去寻找下一个号是多少。

五、半同步主从复制

此时使用的异步主从复制还有些问题:在整体架构中,IO线程不太稳定,因为默认情况下master采用异步方式发送数据,那么slave端如果没有接受到的话会导致主从数据不一致,此时主从复制就没有存在的意义了。


半同步复制必须要求是GTID的模式。

官方半同步文档说明:MySQL :: MySQL 5.7 Reference Manual :: 16.3.9.1 Semisynchronous Replication Administrative Interface

首先,在所有的server上都要安装相应的plugin插件。

在server1 master端:

mysql主备和灾备 mysql主备作用_数据库_45

 在server2、3  slave端下载插件并开启半同步模式:

mysql主备和灾备 mysql主备作用_架构_46

 可以看到我们虽然启动了半同步,但是半同步的状态还是OFF的,即还没有生效。将IO线程重启一下就生效了:

mysql主备和灾备 mysql主备作用_主从复制_47

可以在mysql数据库中使用 show plugins; 查看已经安装的插件。在server1 master端设置开启半同步模式:

mysql主备和灾备 mysql主备作用_mysql_48

 在master端查看半同步状态,发现已经有两个clients:

mysql主备和灾备 mysql主备作用_数据库_49

上面在mysql上设置的都是临时的热生效的方式,要开机自动生效还是要写到文件里 /etc/my.cnf:

server1 master上:

mysql主备和灾备 mysql主备作用_mysql_50

 server2、3 slave上:

mysql主备和灾备 mysql主备作用_架构_51

                 

mysql主备和灾备 mysql主备作用_架构_52

 测试:

在master上添加数据:

mysql主备和灾备 mysql主备作用_架构_53

 

mysql主备和灾备 mysql主备作用_架构_54

半同步模式一般是要求数据无损。在半同步模式下,当master没有接收到slave端同步信息后发来的ack确认信号,master就认为slave端没有同步信息,这种情况下就能保证不会出现由于网络原因导致的数据不一致。

 测试不同步:

先把两个slave端的IO线程停掉:

mysql主备和灾备 mysql主备作用_mysql_55

 由于默认设置等待时间为10s,master10秒还没接收到slave发来的信息,就证明同步有问题,当10秒过后整个系统就会退回到异步模式。

 

mysql主备和灾备 mysql主备作用_主从复制_56

当后端的两个slave恢复正常时,它会自动开启半同步模式,并且整个过程中不会有数据丢失。

mysql主备和灾备 mysql主备作用_主从复制_57

 

mysql主备和灾备 mysql主备作用_数据库_58


mysql主备和灾备 mysql主备作用_主从复制_59

                        After-commit半同步                               

mysql主备和灾备 mysql主备作用_mysql主备和灾备_60

After-sync半同步

异步模式和半同步模式的区别在于,异步模式不管slave端是否完成同步,只要Binlog更改就做引擎提交;而半同步模式只有在接收到slave发送过来的ACK确认信号之后,才作引擎提交。注:做完引擎提交后其他所有的用户都能看到你提交的内容。