Mysql的主从复制、主主复制、半同步复制及复制过滤

Mysql 的复制架构能够提供一个负载均衡、高可用、备份、数据分布的服务器集群,而在完成这样一个集群之前,我们需要保证数据库服务器能够正常复制同步数据,而完成这样的同步的方式主要有主从复制和主主复制。

一、Mysql的主从复制

1、环境准备

两台Linux虚拟主机。
Linux版本:7.4
ip:192.168.0.82(master)、192.168.0.89(slave)
数据库版本: mariadb-server.x86_64 1:5.5.56-2.el7
注意,在启动mariadb-server服务前,先确保/etc/my.cnf配置文件中配置开启了log-bin选项。此选项必须开启,因为主从复制的数据同步,实际上就是二进制日志在备机上的重现。

配置master服务器的数据库配置文件:

[root@master ~]# vim /etc/my.cnf
log-bin=master.log    #启动master服务器的log-bin功能
innodb-file-per-table=ON
sync_binlog = 1  #默认,sync_binlog=0,表示MySQL不控制binlog的刷新,由文件系统自己控制它的缓存的刷新。这时候的性能是最好的,但是风险也是最大的。因为一旦系统Crash,在binlog_cache中的所有binlog信息都会被丢失。
server_id=1  #mysql的同步的数据中是包含server-id的,用于标识该语句最初是从哪个server写入的,所以server-id一定要有的

配置slave服务器的数据库配置文件:

[root@slave ~]# vim /etc/my.cnf
innodb-file-per-table=ON
relay-log=relay.log  #用于保存master服务器的binlog日志
read-only=ON  #设置从库为只读模式,但仅对非SUPER权限的用户有效
server_id=2

最后启动数据库服务即可。

2、构建主从复制

数据库服务的安装此处略过,可自行查找相关的安装方式。若是在现有的数据库服务器上配置主从,需确保主从数据一致后再配置主从复制。因为从服务器主要是通过获取master服务器的binlog日志来在从服务器上重新执行,以此同步数据的,若从服务器本身并没有相关的数据库,binlog日志的复现执行可能会失败。

首先在master服务器上创建用于同步的账号:

MariaDB [(none)]> grant REPLICATION SLAVE ON *.* TO 'slave'@'192.168.0.89' identified by '123456';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

接着在master服务器上查看对应的二进制日志的名称及日志pos位置:

MariaDB [(none)]> show master status;
+---------------+----------+--------------+------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| master.000003 |     8154 |              |                  |
+---------------+---------

然后在slave服务器上执行change master 语句:

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.0.82',MASTER_USER='slave',MASTER_PASSWORD='123456',MASTER_LOG_FILE='master.000003',MASTER_LOG_POS=8154;
MariaDB [hellodb]> start slave;    #最后启动slave

通过show slave status可以查看相应的slave状态,查看相应的slave信息及报错情况:

MariaDB [hellodb]> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.0.82
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master.000004
          Read_Master_Log_Pos: 733
               Relay_Log_File: relay.000002
                Relay_Log_Pos: 1014
        Relay_Master_Log_File: master.000004
             Slave_IO_Running: Yes    #此处为slave的IO线程,为yes说明线程已经连接上主服务器,正等待二进制日志事件到达。
            Slave_SQL_Running: Yes  #此处为slave的SQL线程,为yes线程已经从中继日志读取一个事件,可以对事件进行处理。
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 733
              Relay_Log_Space: 1298
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0        #用于判断slave服务器的数据是否落后于master
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
1 row in set (0.00 sec)

ERROR: No query specified

至此主从复制便完成了。

二、Mysql的主主复制

1、环境准备

两台Linux虚拟主机。
Linux版本:7.4
ip:192.168.0.82(master1)、192.168.0.89(master2)
数据库版本: mariadb-server.x86_64 1:5.5.56-2.el7
需要注意的是,主主复制需要在两个服务器节点上开启binlog和relay-log功能,且server_id必须使用不同的值;若数据库中存在自动增长id的表,为了使得id不冲突,需要自定义其自动增长的方式,如master-1自增长为奇数,master-2的自增长为偶数。

master1的配置文件:

log-bin=master1.log
relay-log=master1-relay.log
innodb-file-per-table=ON
server_id=1
auto_increment_offset=1   #自增长的起始值。一般填第n台主MySQL
auto_increment_increment=2  #自增长的步长值auto_imcrement。一般有n台主MySQL就填n

master2的配置文件:

log-bin=master2.log
innodb-file-per-table=ON
relay-log=master2-relay.log
server_id=2
auto_increment_increment=2
auto_increment_offset=2

2、构建主主复制

在构建主主复制前,先确保服务器之间的数据相同。
首先在两个服务器节点上创建提供给对方做同步的复制账号:

#master1
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'master1-slave'@'192.168.0.89' identified by '123456';
Query OK, 0 rows affected (0.01 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

#master2
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'master2-slave'@'192.168.0.82' identified by '123456';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.01 sec)

接着分别在master1和master2上查看相应的binlog信息:

#master1
MariaDB [(none)]> show master status;
+----------------+----------+--------------+------------------+
| File           | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+----------------+----------+--------------+------------------+
| master1.000001 |      492 |              |                  |
+----------------+----------+--------------+------------------+
1 row in set (0.00 sec)

#master2
MariaDB [(none)]> show master status;
+----------------+----------+--------------+------------------+
| File           | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+----------------+----------+--------------+------------------+
| master2.000001 |      492 |              |                  |
+----------------+----------+--------------+------------------+
1 row in set (0.00 sec)

然后分别在master1和master2上使用change master指定对方为master,然后启动slave即可:

#master1
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.0.89',MASTER_USER='master2-slave',MASTER_PASSWORD='123456',MASTER_LOG_FILE='master2.000001',MASTER_LOG_POS=492;
Query OK, 0 rows affected (0.08 sec)

MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.01 sec)

#master2
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.0.82',MASTER_USER='master1-slave',MASTER_PASSWORD='123456',MASTER_LOG_FILE='master1.000001',MASTER_LOG_POS=492;
Query OK, 0 rows affected (0.03 sec)
MariaDB [(none)]> start slave;

3、测试主主复制

此时分别查看master1和master2的slave状态:

#master1
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.0.89
                  Master_User: master2-slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master2.000001
          Read_Master_Log_Pos: 492
               Relay_Log_File: master1-relay.000002
                Relay_Log_Pos: 527
        Relay_Master_Log_File: master2.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 492
              Relay_Log_Space: 819
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2
1 row in set (0.00 sec)

ERROR: No query specified


#master2
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.0.82
                  Master_User: master1-slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master1.000001
          Read_Master_Log_Pos: 492
               Relay_Log_File: master2-relay.000002
                Relay_Log_Pos: 527
        Relay_Master_Log_File: master1.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 492
              Relay_Log_Space: 819
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
1 row in set (0.00 sec)

ERROR: No query specified

若Slave_IO_Running和Slave_SQL_Running显示为yes,说明主主复制已经启动成功。

在master1上测试创建mydb数据:

MariaDB [(none)]> create database mydb;
Query OK, 1 row affected (0.00 sec)

此时在master2上应该能复制同步创建mydb,在master2上创建mydb库的account表:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| mydb               |
| mysql              |
| performance_schema |
| test               |
+--------------------+
6 rows in set (0.00 sec)
MariaDB [(none)]> use mydb;
MariaDB [mydb]>  create table account (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,name VARCHAR(30));
Query OK, 0 rows affected (0.01 sec)

此时分别在master1和master2上往account表中插入数据:

#master1
MariaDB [(none)]> use mydb;
MariaDB [mydb]> insert into account(name) values ('charlie'),('jack'),('alice');
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0


#master2
MariaDB [mydb]> insert into account(name) values ('Ops'),('IT'),('Manager');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

插入完成后在master1和master2上都应该能查看到下述数据:


MariaDB [mydb]> select * from account;
+----+---------+
| id | name    |
+----+---------+
|  1 | charlie |
|  3 | jack    |
|  5 | alice   |
|  6 | Ops     |
|  8 | IT      |
| 10 | Manager |
+----+---------+
6 rows in set (0.00 sec)

此时说明Mysql的主主复制同步已成功。

三、Mysql的半同步复制

从MySQL5.5开始,MySQL以插件的形式支持半同步复制。如何理解半同步呢?首先我们来看看异步,全同步的概念。

异步复制:MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。
全同步复制:指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
半同步复制:介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。
Mysql半同步复制必须在Mysql 5.5及以上版本使用,并且安装相关的支持插件。
接着我们在此前的主从复制的配置环境下来构建半同步复制。

1、构建半同步复制

首先检查判断Master和slave服务器是否支持动态增加插件:

MariaDB [(none)]> select @@have_dynamic_loading;
+------------------------+
| @@have_dynamic_loading |
+------------------------+
| YES                    |
+------------------------+
1 row in set (0.00 sec)

接着分别检查其对应的插件目录下是否存在插件semisync_master.so和semisync_slave.so:

MariaDB [(none)]> show variables like 'plugin_dir';
+---------------+--------------------------+
| Variable_name | Value                    |
+---------------+--------------------------+
| plugin_dir    | /usr/lib64/mysql/plugin/ |
+---------------+--------------------------+
1 row in set (0.01 sec)

MariaDB [(none)]> quit
Bye
[root@master ~]# ll /usr/lib64/mysql/plugin/ | grep semi
-rwxr-xr-x. 1 root root   41336 8月   5 2017 semisync_master.so
-rwxr-xr-x. 1 root root   15984 8月   5 2017 semisync_slave.so

接着在master服务器上安装插件semisync_master.so,在slave服务器上安装semisync_slave.so插件:

#master
MariaDB [(none)]> install plugin rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.01 sec)

#slave
MariaDB [(none)]> install plugin rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)

安装完后,可以在mysql库的plugin表中查看到相应的插件:

#master
MariaDB [(none)]> select * from mysql.plugin;
+----------------------+--------------------+
| name                 | dl                 |
+----------------------+--------------------+
| rpl_semi_sync_master | semisync_master.so |
+----------------------+--------------------+
1 row in set (0.00 sec)

#slave
MariaDB [(none)]> select * from mysql.plugin;
+---------------------+-------------------+
| name                | dl                |
+---------------------+-------------------+
| rpl_semi_sync_slave | semisync_slave.so |
+---------------------+-------------------+
1 row in set (0.00 sec)

接着分别配置master和slave的数据库配置文件,启用半同步功能:

#master
[root@master ~]# vim /etc/my.cnf
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=30000

#slave
[root@slave ~]# vim /etc/my.cnf
rpl_semi_sync_slave_enabled=1

最后重启数据库服务即可。

启动完成后,可以通过下述两个命令来在master主机上查看半同步复制的状态:

MariaDB [mydb]> show status like '%semi_sync%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |    #半同步的slave节点有多少个
| Rpl_semi_sync_master_net_avg_wait_time     | 1127  |    #半同步的平均等待时长
| Rpl_semi_sync_master_net_wait_time         | 1127  |
| Rpl_semi_sync_master_net_waits             | 1     |
| Rpl_semi_sync_master_no_times              | 0     |
| Rpl_semi_sync_master_no_tx                 | 0     |
| Rpl_semi_sync_master_status                | ON    |      #半同步复制的是否启用
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     |
| Rpl_semi_sync_master_tx_waits              | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 1     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)

MariaDB [(none)]> show variables like '%Rpl%';
+------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_recovery_rank                  | 0     |
| rpl_semi_sync_master_enabled       | ON    |
| rpl_semi_sync_master_timeout       | 30000 |
| rpl_semi_sync_master_trace_level   | 32    |
| rpl_semi_sync_master_wait_no_slave | ON    |
+------------------------------------+-------+
5 rows in set (0.00 sec)

四、Mysql的复制过滤

上述所提到的主从复制、主主复制、异步复制、半同步复制等等,几乎都是复制同步全部的数据库,但是有些情况下可能只需要复制同步一两个指定的数据库。而这时为了复制同步一两个指定的数据库而去同步整个数据库的话,有可能会造成主服务器的负载过大。因此此时我们可以利用Mysql的复制过滤器来实现复制过滤,仅复制指定的数据库,或者不复制指定的数据库,其实现方法有以下两种。

1、修改Master的过滤变量

可以在Master服务器上修改下述两个全局变量:

binlog_do_db=           #相当于白名单,只对指定的db做负复制同步
binlog_ignore_db=       #黑名单,不复制同步指定的db

这两个全局变量一般不同时指定,因此同时指定的话容易造成干扰冲突。修改完成后,主服务器仅向二进制日志中记录指定的数据库相关的写操作。但是修改Master的方法会使得其他数据库无法使用基于时间节点的恢复的功能,这是一大弊端。

2、修改从服务器的过滤变量

第二种方法,是修改从服务器的过滤变量,由从服务器的SQL线程来过滤出指定的数据库或表的相关事件,并应用于本地。

其相关变量有:

Replicate_Do_DB=
Replicate_Ignore_DB=
Replicate_Do_Table=
Replicate_Ignore_Table=
Replicate_Wild_Do_Table=        #通配符
Replicate_Wild_Ignore_Table=

3、复制过滤示例

配置从服务器只复制同步hellodb:

MariaDB [(none)]> stop slave;      #在修改复制过滤变量前,需先停止slave
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> set @@global.replicate_do_db=hellodb;    #设置只复制同步hellodb
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> start slave;
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.0.82
                  Master_User: master1-slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master1.000005
          Read_Master_Log_Pos: 470
               Relay_Log_File: slave.000006
                Relay_Log_Pos: 527
        Relay_Master_Log_File: master1.000005
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: hellodb      #查看slave的status能看到指定的复制同步的db
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 470
              Relay_Log_Space: 1318
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
1 row in set (0.00 sec)

此时在master做出的修改变更,只有与hellodb相关的事件会复制同步到slave上,其他库的更改变更不会进行同步。

你可能感兴趣的:(Mysql的主从复制、主主复制、半同步复制及复制过滤)