MySQL主从复制,主主复制,半同步复制

时间:2022-09-15 11:40:12

实验环境:

系统:CentOS Linux release 7.4.1708 (Core) 

mariadb:mariadb-server-5.5.56-2.el7.x86_64

node1:172.18.0.7

node2:172.18.0.17

节点主机时间要同步,清空防火墙策略,关闭SELinux

一:实验:实现MySQL主从复制

1.首先配置主节点:

安装数据库

[root@node1 ~]# yum install mairadb-server  

编辑配置文件

[root@node1 ~]# vim /etc/my.cnf

设置server id
server-id=1

启用二进制日志
log-bin=/data/mysql/logs/mysql-bin

跳过名称解析
skip_name_resolve=ON

新建日志存放目录

[root@node1 ~]# mkdir -p  /data/mysql/logs

修改日志属主属组为mysql

[root@node1 ~]#  chown -R mysql.mysql /data/mysql/logs

启动Mariadb数据库

[root@node1 ~]# systemctl start mariadb

查看监听端口

[root@node1 ~]# ss -ntl

LISTEN      050*:3306*:*users:(("mysqld",pid=28046,fd=15))

2.配置从节点:

[root@node2 ~]# yum install mariadb-server
[root@node2 ~]#vim /etc/my.cnf
server-id=2   #确保从节点与主节点server id不同
启用中继日志
relay-log=/data/mysql/logs/relay-bin
skip_name_resolve=ON
read_only=ON  #为了防止从节点写入数据导致和主节点数据不一致设置为只读
[root@node2 ~]# mkdir -p /data/mysql/logs/relay-bin
[root@node2 ~]# chown -R mysql.mysql /data/mysql/logs/
[root@node2 ~]# systemctl start mariadb
[root@node2 ~]# mysql

 

3.测试:

node1主服务器:

[root@node1 ~]# mysql

MariaDB [(none)]> SHOW BINARY LOGS;

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

| Log_name         | File_size |

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

| mysql-bin.000001 |       689 |

| mysql-bin.000002 |       746 |

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

2 rows in set (0.00 sec)

 

MariaDB [(none)]> SHOW MASTER STATUS;

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

| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |

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

| mysql-bin.000002 |      746 |              |                  |

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

1 row in set (0.00 sec)

 

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

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

| Variable_name | Value |

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

| server_id     | 1|

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

1 row in set (0.00 sec)

  

查看node2从服务器

[root@node2 ~]# mysql

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

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

| Variable_name | Value |

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

| server_id     | 2|

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

  

4.主节点对用户授权:

在主服务器上对用户授权

[root@node1 ~]# mysql

MariaDB [(none)]> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO  zangfans@'172.18.0.%' IDENTIFIED BY 'andme1024';

把内存的数据同步到磁盘上

MariaDB [(none)]> FLUSH PRIVILEGES; 

查看授权信息

MariaDB [(none)]> USE mysql;

MariaDB [mysql]> select user,host from user;

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

| user     | host          |

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

| root     | 127.0.0.1     |

| zangfans | 172.18.0.%    |

| root     | ::1           |

|          | localhost     |

| root     | localhost     |

|          | node1         |

| root     | node1         |

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

  

5.从服务器切换至主master

注:使用命令之前可以查看帮助信息

MariaDB [(none)]> HELP CHANGE MASTER TO

切换master

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='172.18.0.7',MASTER_PORT=3306,MASTER_USER='zangfans',MASTER_PASSWORD='andme1024',MASTER_LOG_FILE='mysql-bin.0000001',MASTER_LOG_POS=746;

注:如果端口是默认端口3306可以不指定

 

查看而二进制日志信息

MariaDB [mysql]> show binlog events;

----------------------

踩到的坑

错误解决:

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='172.18.0.7',MASTER_PORT=3306,MASTER_USER='zangfans',MASTER_PASSWORD='centos',MASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=461;

ERROR 1198 (HY000): This operation cannot be performed with a running slave; run STOP SLAVE first

如果change master错误需要

MariaDB [(none)]> STOP SLAVE;

MariaDB [(none)]> RESET SLAVE;

-------------------

启动从服务器也可以指定的线程

MariaDB [(none)]> STRAT SLAVE;

 

查看运行状态

错误语法:

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

MySQL主从复制,主主复制,半同步复制

正确语法:

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

 

测试:

在主服务器创建数据库

MariaDB [mysql]> CREATE DATABASE mydb;

Query OK, 1 row affected (0.00 sec)

在从服务器上可以看到服务器

MariaDB [(none)]> SHOW DATABASES;

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

| Database           |

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

| information_schema |

| mydb               |

| mysql              |

| performance_schema |

| test               |

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

5 rows in set (0.00 sec)

      MySQL主从复制搭建起来是非常简单的但是在今后进行维护起来是非常让人头疼的事情,这是因为Mysl主从复制线程是异步的,异步导致从节点落后于主节点,会导致数据不一致。

落后的原因有多种:

     对于主节点在事务隔离级别不是非常高的级别下,如read comititted repeatable read 多个事务是可以同时提交、同时执行,事务执行过程当中是并行的,写语句能够被串行写入到日志文件中的是分为多个步骤依次进行的但从节点在复制时依次只能获取一个事件,此事件依次保存在中继日志中, 带来的结果就是从节点必然是落后于主节点。

    由于不同步也可能导致从节点执行事务的顺序是不一致的,带来主从数据不一致,此结果在Mysql上是一种非常常见的现象,只要在mysql中使用主从复制基本都会面对的问题。

    通过手动去查找不一致的数据集,然后对错误数据进行修改是非常麻烦的事情,有可能在出现的错误人工排查不出来的可能性。percona提过了比对主从节点数据不一致的工具,不一致会启动不阻塞主节点业务场景当中,通常会重新启动在进行二者数据同步的过程。这种代价会影响服务器的性能但是对于重新复制来讲代价要小很多。

 

二:实验:实现MySQL主主复制

解决主节点单点

由于在实验环境可以对生成数据文件删除,真实生产环境建议还是移动到一个空间,不到万不得已不要删除

[root@node1 logs]# rm -rf /var/lib/mysql/* /data/mysql/logs/*

[root@node2 ~]# rm /var/lib/mysql/* /data/mysql/logs/* -rf

  

node1节点:

[root@node1 ~]# mkdir -p /data/mysql/logs/

[root@node1 ~]# chown -R  mysql.mysql /data/mysql/logs

[root@node1 ~]# vim /etc/my.cnf

server-id=1

log_bin=/data/mysql/logs/mysql-bin

relay_log=/data/mysql/logs/relay-log

skip_name_resolve=ON

 

node2节点:

[root@node2 ~]# mkdir -p /data/mysql/logs/

[root@node2 ~]# chown -R  mysql.mysql /data/mysql/logs

[root@node2 ~]# vim /etc/my.cnf

server-id=2

log_bin=/data/mysql/logs/mysql-bin

relay-log=/data/mysql/logs/relay-log

skip_name_resolve=ON  

 注:主主都得开启二进制日志和中继日志

启动主从节点mariadb服务

[root@node1 ~]# systemctl start mariadb
[root@node2 ~]# systemctl start mariadb

此时可以查看到生成的日志信息

[root@node2 ~]# ls /data/mysql/logs

mysql-bin.000001  mysql-bin.000002  mysql-bin.000003  mysql-bin.index

授权命令grant也是写操作,如果在另一台主机上开启了mariadb那么就会造成从节点也会复制一份,也进行执行,如此往来就会造成死循环,所以必须进行对创建账号之后进行复制。但是仅仅只是账号的复制对于双方来说影响不大也可以不停止服务。

 

1.授权

node1,node2对账号进行授权

MariaDB [(none)]> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO zangfans@'172.18.0.%' IDENTIFIED BY 'andme1024';

注:授权账号密码不要过于简单,我在使用centos密码对change mster始终出现了失败

 

2.同步数据

node1,node2节点数据从内存同步到磁盘中

MariaDB [(none)]> FLUSH PRIVILEGES;

node1,node2各自都要查看二进制未见处于哪个文件并获得它的位置

MariaDB [(none)]> SHOW MASTER STATUS;

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

| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |

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

| mysql-bin.000003 |      492 |              |                  |

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

1 row in set (0.00 sec)

 

3.切换主master

node1,node2各自进行change master

node1节点

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='172.18.0.17',MASTER_USER='zangfans',MASTER_PASSWORD='andme1024',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=492;

注:master的ip是主节点的ip

node2节点

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='172.18.0.7',MASTER_USER='zangfans',MASTER_PASSWORD='andme1024',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=492; 

 

4.查看状态

node1节点状态:

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

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

               Slave_IO_State:

                  Master_Host: 172.18.0.17

                  Master_User: zangfans

                  Master_Port: 3306

 Master_Log_File: mysql-bin.000003

 Read_Master_Log_Pos: 492

  Relay_Log_File: relay-log.000001

  Relay_Log_Pos: 4

  

此时IO线程和SQL线程是没有启动

Slave_IO_Running: No

Slave_SQL_Running: No

 

node2节点状态:

MariaDB [(none)]> show slave status\G

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

               Slave_IO_State:

                  Master_Host: 172.18.0.7

                  Master_User: zangfans

                  Master_Port: 3306

IO_THREAD:从节点向主节点复制事件

SEL_THREAD:在本地重放中继日志事件

 

5.启动IO线程

node1,node2启动IO线程

MariaDB [(none)]> START SLAVE IO_THREAD;

MariaDB [(none)]> show salve status\G

Slave_IO_Running: Yes

在启动SQL线程之前查看一下Mysql错误日志信息

错误日志不光记录了服务器运行过程中的错误信息,服务停止过程中的信息诊断信息,还有可能记录复制线程启动信息。

 

6.查看错误日志,查看是否启动信息

[root@node2 ~]# cd /var/log/mariadb/

[root@node2 mariadb]# tail mariadb.log

180605 15:22:14 [Warning] 'user' entry '@node2' ignored in --skip-name-resolve mode.

180605 15:22:14 [Warning] 'proxies_priv' entry '@ root@node2' ignored in --skip-name-resolve mode.

180605 15:22:14 [Note] Event Scheduler: Loaded 0 events

180605 15:22:14 [Note] /usr/libexec/mysqld: ready for connections.

Version: '5.5.56-MariaDB'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MariaDB Server

180605 15:23:45 [Warning] 'user' entry 'root@node2' ignored in --skip-name-resolve mode.

180605 15:23:45 [Warning] 'user' entry '@node2' ignored in --skip-name-resolve mode.

180605 15:23:45 [Warning] 'proxies_priv' entry '@ root@node2' ignored in --skip-name-resolve mode.

180605 15:25:29 [Note] 'CHANGE MASTER TO executed'. Previous state master_host='', master_port='3306', master_log_file='', master_log_pos='4'. New state master_host='172.18.0.7', master_port='3306', master_log_file='mysql-bin.000003', master_log_pos='491'.

180605 15:26:30 [Note] Slave I/O thread: connected to master 'alex@172.18.0.7:3306',replication started in log 'mysql-bin.000003' at position 491

 

7.启动SQL线程

node1,node2同时启动SQL线程

MariaDB [(none)]> START SLAVE SQL_THREAD;

MariaDB [(none)]> show slave status\G

             Slave_IO_Running: Yes

            Slave_SQL_Running: Yes

 

[root@node2 mariadb]# tail mariadb.log

180605 15:26:30 [Note] Slave I/O thread: connected to master 'alex@172.18.0.7:3306',replication started in log 'mysql-bin.000003' at position 491

180605 15:30:44 [Note] Slave SQL thread initialized, starting replication in log 'mysql-bin.000003' at position 491, relay log '/data/mysql/logs/relay-log.000001' position: 4

  

验证:

MySQL主从复制,主主复制,半同步复制

 

从主节点创建一个表,其实主节点起始位置和从节点起始位置都将发生改变

MySQL主从复制,主主复制,半同步复制

 

MySQL:优化配置

       存在自动增长id的表,为了使得id不相冲突,需要定义其自动增长方式;

node1节点:

[root@node1 ~]# vim /etc/my.cnf

auto_increment_offset=1

auto_increment_increment=2

 

node2节点:

[root@node2 ~]# vim /etc/my.cnf

auto_increment_offset=2  #

auto_increment_increment=2

下次启动知道复制的位置cat /var/lib/mysql/master.info,此文件的记录也会存放在内存缓存区当中

 

三:实验:实现MySQL半同步复制

环境配置主从架构

使用2个节点一个做主节点,一个做同步复制

node1节点:

[root@node1 ~]# vim /etc/my.cnf

server-id=1

log_bin=/data/mysql/logs/mysql-bin

skip_name_resolve=ON

新建日志存放目录

[root@node1 ~]# mkdir -p  /data/mysql/logs

修改日志所属所组为mysql

[root@node1 ~]#  chown -R mysql.mysql /data/mysql/logs

启动Mariadb数据库

[root@node1 ~]# systemctl start mariadb

  

node2节点:

[root@node2 ~]# vim /etc/my.cnf

server-id=2

relay_log=/data/mysql/logs/relay-log

skip_name_resolve=ON

read_only=ON  #只读
[root@node2 ~]# mkdir -p /data/mysql/logs/relay-bin

[root@node2 ~]# chown -R mysql.mysql /data/mysql/logs/

[root@node2 ~]# systemctl start mariadb

node1节点授权

MariaDB [mydb]>  GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO alex@'172.18.0.%' IDENTIFIED BY 'andme1024';

MariaDB [mydb]> FLUSH PRIVILEGES;

Query OK, 0 rows affected (0.00 sec)

  

查看Master状态

MariaDB [(none)]> show master status;

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

| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |

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

| mysql-bin.000003 |      245 |              |                  |

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

node2节点changer master

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='172.18.0.7',MASTER_PORT=3306,MASTER_USER='alex',MASTER_PASSWORD='andme1024',MASTER_LOG_FILE='mysql-bin.0000003',MASTER_LOG_POS=245;

测试:主节点创建数据库和表,在从节点查看

MySQL主从复制,主主复制,半同步复制

此时复制方式是异步,改成半同步复制,可以在后面更改IO线程

主从节点默认是没有安装插件

semisync_master.so  #主节点插件

semisync_slave.so

查看已安装的插件

MariaDB [db1]> SHOW PLUGINS;

查看插件放于的位置

/usr/lib64/mysql/plugin/

 

1.启用插件

主节点启用master插件

MariaDB [db1]> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

从节点启用slave插件

MariaDB [db1]> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

 

2.设置半同步启用

ON:启用

OFF:关闭

同时也可以使用0代替ON,1代替OFF 

主节点:

MariaDB [db1]> SET GLOBAL rpl_semi_sync_master_enabled=ON;

从节点:

MariaDB [db1]> SET GLOBAL rpl_semi_sync_slave_enabled=ON;

 

3.查看状态的方式

MariaDB [db1]> SHOW GLOBAL STATUS LIKE 'rpl%';

MariaDB [db1]> SHOW GLOBAL VARIABLES LIKE 'rpl%';

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

| Variable_name                      | Value |

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

| rpl_semi_sync_master_enabled       | OFF|1为开启,表示在master上已经开启了半同步复制模式;

| rpl_semi_sync_master_timeout       | 10000 |表示如果主库在某次事务中的等待时间超过10000毫秒,则降级为异步复制模式,不在等待slave从库。如果主库再次探测到slave从恢复了,则会自动切换回半同步复制模式;

| rpl_semi_sync_master_trace_level   | 32|指用于开启半同步复制模式时的调试级别,默认为32。

| rpl_semi_sync_master_wait_no_slave | ON    |表示是否允许master每个事务提交后都要等待slave的接收确认信号。默认为ON,即每一个事务都会等待。如果为OFF,则slave追赶上之后,也不会开启半同步复制模式,需要手工开启;

 

4.关闭异步线程,开启同步线程

MariaDB [db1]> SHOW GLOBAL VARIABLES LIKE 'rpl%';

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

| Variable_name                   | Value |

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

| rpl_recovery_rank               | 0     |

| rpl_semi_sync_slave_enabled     | ON    |

| rpl_semi_sync_slave_trace_level | 32    |

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

  

此时发现IO线程和SQL线程都启用了,是以异步方式连接过来

 Slave_IO_Running: Yes

 Slave_SQL_Running: Yes

 

关闭异步线程

MariaDB [db1]> STOP SLAVE IO_THREAD;

MariaDB [db1]> STOP SLAVE SQL_THREAD;

开启同步IO线程

MariaDB [db1]> START SLAVE IO_THREAD;

测试:

MariaDB [db1]> SHOW GLOBAL STATUS LIKE 'rpl%';                                

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

| Variable_name                              | Value       |

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

| Rpl_semi_sync_master_clients| 1           |

此时在node1主节点上可以看到有了连接客户端

 

在node1节点创建一个表

MariaDB [db1]> INSERT INTO tb1 VALUES (3,'peter'); 

查看状态信息

MariaDB [db1]> SHOW GLOBAL STATUS LIKE 'rpl%';   

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

| Variable_name                              | Value       |

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

| Rpl_semi_sync_master_clients| 1           |

| Rpl_semi_sync_master_net_avg_wait_time     | 682         |  #等待平均时长

| Rpl_semi_sync_master_net_wait_time         | 682  #等待时长

注:找一个离主机最近的,最好为同一个机架上的机器,将来提升一个新的主节点时此节点将是优选

缺陷:主节点带宽被降低了