MySQL主主复制
1、MySQL主主复制概述
MySQL主从复制虽然能够提高数据库总体性能、实时备份、利用mysql-proxy实现读写分离,但当主服务器宕机时业务还是中断,所以就需要主主复制,两台主服务器实现负载。
1.1 MySQL主主复制原理
主从复制原理是当从库IO线程接受到主库传递来的二进制日志(Binlog)并将之保存为从库的中继日志(relay log),然后从库SQL线程将中继日志(relay log)的事件重做到从库上,实现主从数据同步。如果SQL线程发现重复的事件并且server_id与当前从库的server_id相同,则会丢弃该事件,因此两台MySQL服务器互为主从,不会导致相同的事件被重复执行。
主主复制架构图:
在MySQL集群中通过双主或多主架构,可以解决一主多从架构的单点故障,减少主从切换的故障处理时间,增加MySQL群集的高可用性。
1.2 MySQL主主复制优点
- 主主模式能将读写请求分摊到两个主节点,有效提升服务器使用率。
- 主节点发生故障后,能快速进行主从切换。
- 当故障节点恢复后,故障节点能通过复制进行数据恢复(应用其他节点数据)和数据同步(将未同步数据发生给其他节点)。
1.3 MySQL主主复制缺点
- 当主节点上MySQL实例发生故障后,可能会存在部分数据(Binlog)未同步到另外的主节点,导致数据丢失(直到故障节点恢复)。
- 主主模式下,很容易因数据访问控制不当导致数据冲突。
- 为提高系统高可用性,双主架构会被扩展成双主多从结构,同样存在主节点发生故障后多个从库选主和恢复复制的问题。
1.4 MySQL主主复制存在的问题
在主主模式下,两个主库都提供读写服务,如果应用通过两个主库操作相同数据,则会发生冲突导致数据覆盖(使用语句模式复制)或复制异常(使用行模式复制),因此需要对读写服务进行控制:
- 基于自主主键控制,通过设置自增属性auto_increment_offset和auto_increment_increment来控制每个主节点生产不同的自增值,并根据不同自增值访问不同主节点。
- 基于库级别或表级别控制,如应用APP1访问节点node1上的DB1库,而应用APP2访问节点node2上的DB2库,两个主节点间不会操作相同表的数据,因此不会存在事务冲突。
2、MySQL主主复制配置
主主复制需要两台虚拟机,分别为master1(主服务器1:192.168.52.128)和master2(主服务器2:192.168.52.129)。
//主服务器1和主服务器2安装并初始化mariadb
[root@master1 ~]# dnf -y install mariadb mariadb-server
[root@master1 ~]# systemctl enable mariadb
[root@master1 ~]# systemctl start mariadb
[root@master1 ~]# mysql_secure_installation
[root@master2 ~]# dnf -y install mariadb mariadb-server
[root@master2 ~]# systemctl enable mariadb
[root@master2 ~]# systemctl start mariadb
[root@master2 ~]# mysql_secure_installation
//主服务器1和主服务器2关闭防火墙和selinux
[root@master1 ~]# systemctl stop firewalld.service
[root@master1 ~]# systemctl disable firewalld.service
Removed /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@master1 ~]# sed -i s/SELINUX=enforing/SELINUX=disabled/g /etc/selinux/config
[root@master1 ~]# setenforce 0
[root@master2 ~]# systemctl stop firewalld.service
[root@master2 ~]# systemctl disable firewalld.service
Removed /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@master2 ~]# sed -i s/SELINUX=enforing/SELINUX=disabled/g /etc/selinux/config
[root@master2 ~]# setenforce 0
//在主服务器1上配置主从复制,开启二进制日志
[root@master1 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
log_bin=mysql-bin //开启二进制日志
server_id=1 //服务id号,不可重复,为0则拒绝从服务器连接
skip_name_resolve=on //优化连接速度
auto_increment_offset=1 //自动增长起始值。一般填第n台主MySQL。此时为第一台主MySQL
auto_increment_increment=2 //自动增长步进值,一般有n台主MySQL就填n
binlog-ignore=mysql //忽略mysql库,一般不写
replicate-do-db=test //要同步的数据库,默认所有库,一般也不写
log-slave-updates=1 //将写的操作全部写入二进制日志,多主多从时开启
:wq!
[root@master1 ~]# systemctl restart mariadb.service
//在主服务器2上配置主从复制,开启二进制日志
[root@master2 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
log_bin=mysql-bin //开启二进制日志
server_id=2 //服务id号,不可重复,为0则拒绝从服务器连接
skip_name_resolve=on //优化连接速度
auto_increment_offset=2 //自动增长起始值。一般填第n台主MySQL。此时为第二台主MySQL
auto_increment_increment=2 //自动增长步进值,一般有n台主MySQL就填n
:wq!
[root@master2 ~]# systemctl restart mariadb.service
//在主服务器1上授权一个数据库用户用于复制,创建完成后在主服务器2上测试登录
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'zcfz1'@'%' IDENTIFIED BY 'hzz123!';
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.001 sec)
//在主服务器2上授权一个数据库用户用于复制,创建完成后在主服务器1上测试登录
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'zcfz2'@'%' IDENTIFIED BY 'hzz123!';
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.001 sec)
//登录到主服务器2的数据库,在数据库中配置主服务器1的信息
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.52.128',MASTER_PORT=3306,MASTER_USER='zcfz1',MASTER_PASSWORD='hzz123!';
Query OK, 0 rows affected (0.002 sec)
MariaDB [(none)]> START SLAVE;
Query OK, 0 rows affected (0.001 sec)
//登录到主服务器1的数据库,在数据库中配置主服务器2的信息
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='192.168.52.129',MASTER_PORT=3306,MASTER_USER='zcfz2',MASTER_PASSWORD='hzz123!';
Query OK, 0 rows affected (0.002 sec)
MariaDB [(none)]> START SLAVE;
Query OK, 0 rows affected (0.001 sec)
//查看主服务器1和主服务器2是否互为主从
//master1
MariaDB [(none)]> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.52.129
Master_User: zcfz2
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 638
Relay_Log_File: mariadb-relay-bin.000003
Relay_Log_Pos: 937
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.....省略.....
//master2
MariaDB [(none)]> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.52.128
Master_User: zcfz1
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 638
Relay_Log_File: mariadb-relay-bin.000003
Relay_Log_Pos: 937
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.....省略.....
//在主服务器数据库中添加数据,查看是否复制到主服务器2
//主服务器1创建数据库
MariaDB [(none)]> CREATE DATABASE hzz;
Query OK, 1 row affected (0.001 sec)
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| hzz |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.000 sec)
//主服务器2成功复制主服务器1新建的数据库
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| hzz |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)
//在master2数据库中添加数据,查看是否复制到master1
//主服务器2创建数据库
MariaDB [(none)]> CREATE DATABASE zzh;
Query OK, 1 row affected (0.001 sec)
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| hzz |
| information_schema |
| mysql |
| performance_schema |
| zzh |
+--------------------+
5 rows in set (0.000 sec)
//主服务器1成功复制主服务器2新建的数据库
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| hzz |
| information_schema |
| mysql |
| performance_schema |
| zzh |
+--------------------+
4 rows in set (0.000 sec)