MariaDB/Mysql之主从架构的复制原理及主从/双主配置详解(二)



紧接上篇博文《MariaDB/Mysql之主从架构的复制原理及主从/双主配置详解(一)》mysql


3.深刻了解复制

3.一、基于语句的复制(Statement-Based Replication)

MySQL 5.0及以前的版本仅支持基于语句的复制(也叫作逻辑复制,logical replication),这在数据库并不常见。master记录下改变数据的查询,而后,slave从中继日志中读取事件,并执行它,这些SQL语句与master执行的语句同样。
这种方式的优势就是实现简单。此外,基于语句的复制的二进制日志能够很好的进行压缩,并且日志的数据量也较小,占用带宽少——例如,一个更新GB的数据的查询仅须要几十个字节的二进制日志。而mysqlbinlog对于基于语句的日志处理十分方便。
   可是,基于语句的复制并非像它看起来那么简单,由于一些查询语句依赖于master的特定条件,例如,master与slave可能有不一样的时间。因此,MySQL的二进制日志的格式不只仅是查询语句,还包括一些元数据信息,例如,当前的时间戳。即便如此,仍是有一些语句,好比,CURRENT USER函数,不能正确的进行复制。此外,存储过程和触发器也是一个问题。
    另一个问题就是基于语句的复制必须是串行化的。这要求大量特殊的代码,配置,例如InnoDB的next-key锁等。并非全部的存储引擎都支持基于语句的复制。

3.二、基于记录的复制(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.三、复制相关的文件

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

(1)mysql-bin.index

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

(2)mysql-relay-bin.index

该文件的功能与mysql-bin.index相似,可是它是针对中继日志,而不是二进制日志。

(3)master.info

保存从服务器链接至主服务时所须要的信息,每行一个值保存master的相关信息。不要删除它,不然,slave重启后不能链接master。

(4)relay-log.info

保存了复制位置:包括二进制日志和中继日志的文件及位置。

3.四、发送复制事件到其它slave
sql

当设置log_slave_updates时,你可让slave扮演其它slave的master。此时,slave把SQL线程执行的事件写进行本身的二进制日志(binary log),而后,它的slave能够获取这些事件并执行它。以下:数据库

wKioL1NOPNPSXgYeAAGOF1KjhsU124.jpg


3.五、复制过滤(Replication Filters)

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

wKioL1NOPYSwF1NvAAF4FoH_Luk325.jpg


4.复制的经常使用拓扑结构

复制的体系结构有如下一些基本原则:
(1)每一个slave能够有一个或多个master;
(2)每一个slave只能有一个惟一的服务器ID;
(3)每一个master能够有不少slave;
(4)若是设置log_slave_updates,slave能够是其它slave的master,从而扩散master的更新。

在早期的MySQL是不支持多主服务器复制(Multimaster Replication)——即一个slave能够有多个master的场景,可是MariaDB目前已经支持。可是,经过一些简单的组合,咱们却能够创建灵活而强大的复制体系结构。
网络


4.一、单一master和多slave

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

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

以下:架构

wKiom1NOQB6wKpInAACPFzueKiI373.jpg

若是写操做较少,而读操做很时,能够采起这种结构。你能够将读操做分布到其它的slave,从而减少master的压力。可是, 当slave增长到必定数量时,slave对master的负载以及网络带宽都会成为一个严重的问题。
这种结构虽然简单,可是,它却很是灵活,足够知足大多数应用需求。一些建议:
(1)    不一样的slave扮演不一样的做用(例如使用不一样的索引,或者不一样的存储引擎);
(2)    用一个slave做为备用master,只进行复制;
(3)    用一个远程的slave,用于灾难恢复;

你们应该都比较清楚,从一个Master节点能够复制出多个Slave节点,可能有人会想,那一个Slave节点是否能够从多个Master节点上面进行复制呢?这是彻底能够实现的,目前在MariaDB中已经实现multi-master replication 功能;可参考《MariaDB多源(主)复制》异步


4.二、主动模式的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中,就更不用担忧可能会出现循环复制的情形了。
如图:

wKioL1NOP_SAmSANAABJisdmItQ735.jpg

   主动的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结合起来,能够创建强大的高性能的数据库平台。可是,能够经过其它一些方式来模拟这种多主服务器的复制。
ide

示例:双主模式配置:函数

环境:

Master1/Master2 Platfrom IP APP Version
Master1 CentOS6.5_X86-64    172.16.41.1   mariadb-10.0.10
Master2 CentOS6.5_X86-64   172.16.41.2 mariadb-10.0.10

1.配置双主:

#Master1的配置:

(1)修改server-id
主配置文件/etc/my.cnf [mysqld]段中,修改以下行:

server-id  =  1
(2)启用中继日志,二进制日志

主配置文件/etc/my.cnf [mysqld]段中,修改以下行:

log-bin = /mydata/binlogs/master1-bin

relay-log = /mydata/relaylogs/relay-bin


确保中继日志选项开启

MariaDB [(none)]> SHOW GLOBAL  VARIABLES LIKE 'relay_log';
+---------------+-----------------------------+
| Variable_name | Value                       |
+---------------+-----------------------------+
| relay_log     | /mydata/relaylogs/relay-bin |
+---------------+-----------------------------+
1 row in set (0.00 sec)


(3)添加下面两项,以免在MySQL自动为INSERT语句选择不互相冲突的值

auto-increment-offset = 1     //起始值

auto-increment-increment = 2   //步长


确保自动增加选项已开启:

MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE 'auto_inc%';

+--------------------------+-------+

| Variable_name            | Value |

+--------------------------+-------+

| auto_increment_increment | 2     |

| auto_increment_offset    | 1     |

+--------------------------+-------+

(4)建立有复制权限的用户,命令以下:

MariaDB [(none)]> CREATE USER 'luccy'@'172.16.41.2' IDENTIFIED BY 'qazwsx123';
MariaDB [(none)]> REVOKE ALL PRIVILEGES ,GRANT OPTION FROM 'luccy'@'172.16.41.2';
MariaDB [(none)]> GRANT RELOAD,LOCK TABLES, REPLICATION CLIENT ,REPLICATION SLAVE ON *.* TO 'luccy'@'172.16.41.2';

MariaDB [(none)]> FLUSH PRIVILEGES;


#Master2的配置:

(1)修改server-id#

主配置文件/etc/my.cnf [mysqld]段中,修改以下行:

server-id  =  2
(2)启用中继日志,二进制日志

log-bin = /mydata/binlogs/master2-bin  

relay-log = /mydata/relaylogs/relay-bin

确保中继日志选项开启

MariaDB [(none)]> SHOW GLOBAL  VARIABLES LIKE 'relay_log';
+---------------+-----------------------------+
| Variable_name | Value                       |
+---------------+-----------------------------+
| relay_log     | /mydata/relaylogs/relay-bin |
+---------------+-----------------------------+

(3)添加下面两项,以免在MySQL自动为INSERT语句选择不互相冲突的值

auto-increment-offset = 2     //起始值

auto-increment-increment = 2   //步长


确保自动增加选项已开启:

MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE 'auto_inc%';

+--------------------------+-------+

| Variable_name            | Value |

+--------------------------+-------+

| auto_increment_increment | 2    |

| auto_increment_offset    | 2    |

+--------------------------+-------+

(4)建立有复制权限的用户,命令以下:

MariaDB [(none)]> CREATE USER 'jerry'@'172.16.41.1' IDENTIFIED BY 'qazwsx123';
MariaDB [(none)]> REVOKE ALL PRIVILEGES ,GRANT OPTION FROM 'jerry'@'172.16.41.1';
MariaDB [(none)]> GRANT RELOAD,LOCK TABLES, REPLICATION CLIENT ,REPLICATION SLAVE ON *.* TO 'jerry'@'172.16.41.1';

MariaDB [(none)]> FLUSH PRIVILEGES;

   若是此时两台服务器均为新创建,且无其它写入操做,各服务器只需记录当前本身二进制日志文件及事件位置,以之做为另外的服务器复制起始位置便可

#Master1:


MariaDB [(none)]> SHOW MASTER STATUS;

+--------------------+----------+--------------+------------------+

| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |

+--------------------+----------+--------------+------------------+

| master1-bin.000001 |      969 |              |                  |

+--------------------+----------+--------------+------------------+

#Master2:

MariaDB [(none)]> SHOW MASTER STATUS;

+--------------------+----------+--------------+------------------+

| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |

+--------------------+----------+--------------+------------------+

| master2-bin.000001 |      314 |              |                  |

+--------------------+----------+--------------+------------------+

   各服务器接下来指定对另外一台服务器为本身的主服务器

#Master1指向Master2

MariaDB [(none)]> CHANGE MASTER TO MASTER_USER='luccy',MASTER_HOST='172.16.41.2',MASTER_PASSWORD='qazwsx123',MASTER_LOG_FILE='master2-bin.000005',MASTER_LOG_POS=328;


#Master2指向Master1

MariaDB [(none)]> CHANGE MASTER TO MASTER_USER='jerry',MASTER_HOST='172.16.41.1',MASTER_PASSWORD='qazwsx123',MASTER_LOG_FILE='master1-bin.000005',MASTER_LOG_POS=1592;

   启动个服务器复制进程

#Master1

MariaDB [(none)]> START SLAVE;

MariaDB [mysql]> SHOW SLAVE STATUS\G

*************************** 1. row ***************************

              Slave_IO_State: Waiting for master to send event

                 Master_Host: 172.16.41.2

                 Master_User: jerry

                 Master_Port: 3306

               Connect_Retry: 60

             Master_Log_File: master2-bin.000006

         Read_Master_Log_Pos: 328

              Relay_Log_File: relay-bin.000004

               Relay_Log_Pos: 617

       Relay_Master_Log_File: master2-bin.000006

            Slave_IO_Running: Yes

           Slave_SQL_Running: Yes

             Replicate_Do_DB:

               ..........

               ..........

#Master2

MariaDB [(none)]> START SLAVE;


MariaDB [(none)]> SHOW SLAVE STATUS\G

*************************** 1. row ***************************

              Slave_IO_State: Waiting for master to send event

                 Master_Host: 172.16.41.1

                 Master_User: luccy

                 Master_Port: 3306

               Connect_Retry: 60

             Master_Log_File: master1-bin.000005

         Read_Master_Log_Pos: 1592

              Relay_Log_File: relay-bin.000002

               Relay_Log_Pos: 537

       Relay_Master_Log_File: master1-bin.000005

            Slave_IO_Running: Yes

           Slave_SQL_Running: Yes

             Replicate_Do_DB:

               ..........
               ..........


双主测试:

(1)在Master1上建立数据库 testdb:

MariaDB [(none)]> CREATE DATABASE testdb;

MariaDB [(none)]> SHOW DATABASES;

+--------------------+

| Database           |

+--------------------+

| information_schema |

| mysql              |

| performance_schema |

| test               |

| testdb            |

+--------------------+

在Master2上查看结果与在Master1上所查得结果同样!

(2)在Master1上建立数据库 mydb:

MariaDB [(none)]> SHOW DATABASES;

+--------------------+

| Database           |

+--------------------+

| information_schema |

| mydb               |

| mysql              |

| performance_schema |

| test               |

| testdb             |

+--------------------+

Master1上查看结果与在Master2上所查得结果同样!

(3)在Master1的mydb上面新建一张表mytable1,并插入语句

MariaDB [(none)]> use mydb

MariaDB [mydb]> CREATE TABLE mytable1 (ID INT AUTO_INCREMENT UNIQUE KEY, Name CHAR(20));

MariaDB [mydb]> DESC mytable1;

+-------+----------+------+-----+---------+----------------+

| Field | Type     | Null | Key | Default | Extra          |

+-------+----------+------+-----+---------+----------------+

| ID    | int(11)  | NO   | PRI | NULL    | auto_increment |

| Name  | char(20) | YES  |     | NULL    |                |

+-------+----------+------+-----+---------+----------------+

MariaDB [mydb]> INSERT INTO mytable1(Name) VALUES ('larry'),('jim'),('jerry');

Query OK, 3 rows affected (0.01 sec)

Records: 3  Duplicates: 0  Warnings: 0


MariaDB [mydb]> SELECT * FROM mytable1;

+----+-------+

| ID | Name  |

+----+-------+

|  1 | larry|  //自动增加的效果,在Master1上定义的起始值为1,步径为2

|  3| jim  |

|  5 | jerry|

+----+-------+

在Master2上面插入字段(以上内容已经同步到Master2)

MariaDB [mydb]>INSERT INTO mytable1(Name) VALUES ('Zhang San'),('Li Si'),('Wang Wu');

MariaDB [mydb]> SELECT * FROM mytable1;

+----+-----------+

| ID | Name      |

+----+-----------+

|  1 | larry     |

|  3 | jim      |

|  5 | jerry     |

|  6 | Zhang San |

|  8 | Li Si     |

| 10 | Wang Wu   |

+----+-----------+

//看来不是想要的结果,虽说MySQL自动为INSERT选择的值不会再出现互相冲突的状况,可是貌似没有按数字排序,找不到解决这个问题的办法,除非不选择用双主模式!



4.三、主动-被动模式的Master-Master(Master-Master in Active-Passive Mode)

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

wKiom1NRQvyD4Q1dAABIsY-WKGc195.jpg


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架构。

wKiom1NRQv6RNnTtAAEAh7azRwo469.jpg

固然,若是条件容许,我更倾向于建议你们经过拆分红多个Replication集群来解决

上述瓶颈问题。毕竟Slave并无减小写的量,全部Slave实际上仍然仍是应用了全部的数据变动操做,没有减小任何写IO。相反,Slave越多,整个集群的写IO总量也就会越多,咱们没有很是明显的感受,仅仅只是由于分散到了多台机器上面,因此不是很容易表现出来。

此外,增长复制的级联层次,同一个变动传到最底层的Slave所须要通过的MySQL也会更多,一样可能形成延时较长的风险。而若是咱们经过分拆集群的方式来解决的话,可能就会要好不少了,固然,分拆集群也须要更复杂的技术和更复杂的应用系统架构。


4.五、带从服务器的Master-Master结构(Master-Master with Slaves)

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

wKioL1NRQtPwj73_AACDaBTeaWw819.jpg

级联复制在必定程度上面确实解决了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集群可能出现的数据延时也会更为明显,因此考虑使用多层级联复制以前,也须要评估数据延时对应用系统的影响。

相关文章
相关标签/搜索