MySQL主从(Master-Slave)复制是一种数据复制机制,用于将一个MySQL数据库服务器(主服务器)的数据复制到其他一个或多个MySQL数据库服务器(从服务器)。这种复制机制可以提供数据冗余、增加读取性能、实现高可用性、灾难恢复和数据分析等功能。
通过主从复制,可以将主服务器上的数据复制到从服务器上,实现数据的冗余和备份。当主服务器发生硬件故障、数据损坏或人为错误时,可以通过从服务器恢复数据,确保数据的安全性和可用性。
主服务器负责处理写入操作,而从服务器可以用于处理读取操作,从而分摊读取负载。通过在从服务器上执行读取操作,可以提高整个系统的读取性能和吞吐量,减轻主服务器的压力。
通过设置主从复制,可以实现主服务器的冗余,从而提供高可用性。当主服务器发生故障或维护时,可以快速将从服务器提升为新的主服务器,保持系统的连续性和可用性,减少服务中断时间。
在主从复制架构下,可以使用从服务器恢复数据,从而实现快速的灾难恢复。当主服务器不可用时,可以切换到从服务器继续提供服务,实现故障转移
通过从服务器进行数据分析、查询和报表生成等操作,可以减少对主服务器的影响,保持主服务器的高性能。从服务器可以用于处理复杂的查询和数据分析任务,从而提供更好的用户体验。
在这种形式中,有一个主服务器和一个从服务器。主服务器负责处理写入操作和记录日志,而从服务器通过复制主服务器的日志并执行相同的操作来复制数据。
这种形式包含一个主服务器和多个从服务器。主服务器处理写入操作并记录日志,而多个从服务器通过复制主服务器的日志来复制数据。多从服务器可以分摊读取负载,提高读取性能。
主主复制是一种双向复制形式,其中两个或多个服务器都可以作为主服务器和从服务器运行。每个服务器都可以接收写入操作,并将写入操作复制到其他服务器。这样可以提高可用性和冗余性,并允许在不同的地理位置进行数据写入。
多主一从形式的主从复制在MySQL中也称为主主复制,这种方式通过设置多个主服务器,可以将读取操作分摊到各个主服务器上进行处理。这种形式可以提供读取负载均衡、高可用性、数据冗余和灾难恢复等功能,使得MySQL系统更加可靠、高效和可扩展。
MySQL联级复制提供了灵活的数据分发和同步机制,可以实现高可用性、数据冗余、灾难恢复,以及支持数据分析和报告等功能。它是构建活跃/活跃架构、构建分布式系统和提升系统性能和可靠性的重要工具。
另外,多主一从形式从MySQL5.7版本才开始支持
MySQL主从复制原理:
也就是说:
主从复制配置步骤:
环境:
数据库角色 | IP | 系统版本 | 应用 | 有无数据 | 主机名 |
---|---|---|---|---|---|
主数据库 | 192.168.234.22 | centos8/redhat8 | MariaDB10.3 | 有数据 | master |
从数据库 | 192.168.234.33 | centos8/redhat8 | MariaDB10.3 | 无数据 | kiwi111 |
注:MariaDB操作与MySQL一致
[root@master ~]# yum install -y mariadb*
[root@master ~]# systemctl start mariadb
[root@kiwi111 ~]# yum install -y mariadb*
[root@kiwi111 ~]# systemctl start mariadb
查看主数据库
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| kiwi123 |
| mysql |
| performance_schema |
| student |
+--------------------+
5 rows in set (0.000 sec)
MariaDB [(none)]>
查看从数据库
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.001 sec)
MariaDB [(none)]>
全备主数据库
全备主数据库是为了能够让从数据库同步主数据库的数据
## 在备主库时需要另开一个终端,给数据库加上读锁,避免在备份期间有其他人在写入导致数据不一致
MariaDB [(none)]> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]>
开始全备主数据库
[root@master ~]# mysqldump -uroot -p1 --all-databases > /opt/all-databases-2023-9-7.sql
[root@master ~]# ls /opt/
all-databases-2023-9-7.sql
[root@master ~]#
将备份文件传输给从数据库
[root@master ~]# cd /opt/
[root@master opt]# scp all-databases-2023-9-7.sql 192.168.234.33:/opt/
[email protected]'s password:
all-databases-2023-9-7.sql 100% 467KB 21.7MB/s 00:00
[root@master opt]#
## 从库
[root@kiwi111 ~]# cd /opt/
[root@kiwi111 opt]# ls
all-databases-2023-9-7.sql
[root@kiwi111 opt]#
在从数据库上恢复备份并查看是否数据同步完成,确保和主数据库一致
[root@kiwi111 opt]# mysql -uroot -pkiwi111 < /opt/all-databases-2023-9-7.sql
[root@kiwi111 opt]# mysql -uroot -pkiwi111 -e 'show databases;'
+--------------------+
| Database |
+--------------------+
| information_schema |
| kiwi123 |
| mysql |
| performance_schema |
| student |
+--------------------+
[root@kiwi111 opt]#
解锁主数据库
## 退出MySQL即可
MariaDB [(none)]> quit
Bye
[root@master ~]#
关闭防火墙与selinux
[root@master]# systemctl stop firewalld
[root@master]# setenforce 0
[root@master]#
[root@kiwi111]# systemctl stop firewalld
[root@kiwi111]# setenforce 0
[root@kiwi111]#
MariaDB [(none)]> CREATE USER 'kiwi'@'192.168.234.33' IDENTIFIED BY '1';
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'kiwi'@'192.168.234.33' IDENTIFIED BY '1';
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.003 sec)
MariaDB [(none)]>
## 授权可与创建用户同时进行
[root@master ~]# vim /etc/my.cnf
[root@master ~]# cat /etc/my.cnf
## 加上下面几行
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-bin=mysql-bin ##启用binlog日志
server-id=10 ##数据库服务器唯一标识符,主库的server-id值必须比从库的小
symbolic-links=0
log-error=/var/log/mariadb/mariadb.log ## 这行MySQL的路径可能不一样
pid-file=/var/run/mariadb/mariadb.pid ## 这行MySQL的路径可能不一样
## 重启服务
[root@master ~]# systemctl restart mariadb
查看主数据库状态
[root@master ~]# mysql -uroot -p1 -e 'SHOW master status;'
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 328 | | |
+------------------+----------+--------------+------------------+
[root@master ~]#
## Position 这里的数字每个人都有可能不一样
[root@kiwi111 ~]# vim /etc/my.cnf
[root@kiwi111 ~]# cat /etc/my.cnf
## 添加下面几行
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
server-id=20 ## //设置从库的唯一标识符,从库的server-id值必须大于主库的该值
relay-log=mysql-relay-bin ## 启用中继日志relay-log
symbolic-links=0
log-error=/var/log/mariadb/mariadb.log ## 这行MySQL的路径可能不一样
pid-file=/var/run/mariadb/mariadb.pid ## 这行MySQL的路径可能不一样
[root@kiwi111 ~]#
## 重启服务
[root@kiwi111 ~]# systemctl restart mariadb
[root@kiwi111 ~]#
## 同步完成之后主数据库与从数据库的密码也会同步
## 此时再写原本的密码提示密码错误
[root@kiwi111 ~]# mysql -uroot -pkiwi111
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
[root@kiwi111 ~]# mysql -uroot -p1
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 19
Server version: 10.3.28-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
配置并启动从数据库主从复制
[root@kiwi111 ~]# mysql -uroot -p1
## 配置并启动主从复制
MariaDB [(none)]> CHANGE MASTER TO
-> MASTER_HOST='192.168.234.22',
-> MASTER_USER='kiwi',
-> MASTER_PASSWORD='1',
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=328;
Query OK, 0 rows affected (0.005 sec)
MariaDB [(none)]>
## 启动主从复制
MariaDB [(none)]> start slave;
Query OK, 0 rows affected, 1 warning (0.000 sec)
查看从服务器状态
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.234.22
Master_User: kiwi
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 2336
Relay_Log_File: mysql-relay-bin.000003
Relay_Log_Pos: 2563
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes ## 此处必须为yes
Slave_SQL_Running: Yes ## 此处必须为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: 2336
Relay_Log_Space: 2872
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
··························略
MariaDB [(none)]>
在主服务器的kiwi123库创建表并插入数据
MariaDB [(none)]> USE kiwi123;
Database changed
MariaDB [kiwi123]> CREATE TABLE hobby (id int PRIMARY KEY AUTO_INCREMENT,name varchar(100))
-> ;
Query OK, 0 rows affected (0.017 sec)
MariaDB [kiwi123]> DESC hobby;
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | YES | | NULL | |
+-------+--------------+------+-----+---------+----------------+
2 rows in set (0.002 sec)
MariaDB [kiwi123]> INSERT hobby(name) VALUES ('exercise'),('read book'),('sing'),('watch movie'),('travel'),('dance');
Query OK, 6 rows affected (0.001 sec)
Records: 6 Duplicates: 0 Warnings: 0
MariaDB [kiwi123]> SELECT * FROM hobby;
+----+-------------+
| id | name |
+----+-------------+
| 1 | exercise |
| 2 | read book |
| 3 | sing |
| 4 | watch movie |
| 5 | travel |
| 6 | dance |
+----+-------------+
6 rows in set (0.000 sec)
查看从数据库是否同步
[root@kiwi111 ~]# mysql -uroot -p1
MariaDB [(none)]> USE kiwi123;
Database changed
MariaDB [kiwi123]> SELECT * FROM hobby;
+----+-------------+
| id | name |
+----+-------------+
| 1 | exercise |
| 2 | read book |
| 3 | sing |
| 4 | watch movie |
| 5 | travel |
| 6 | dance |
+----+-------------+
6 rows in set (0.000 sec)
MariaDB [kiwi123]>
## 可以看见已同步
GTID即全局事务ID (global transaction identifier),是MySQL中用于复制和故障恢复的一种机制,其保证为每一个在主上提交的事务在复制集群中可以生成一个唯一的ID。GTID最初由google实现,GTID在MySQL5.6引入。它可以在集群中唯一标识一个事务,在MySQL主从复制时,从节点可以使用GTID来确定复制位点,用于取代使用binlog文件偏移量的传统方式,在发生主备切换时从节点可以自动在新主上找到正确的复制位置,大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位点发生误操作的风险,另外,基于GTID的复制可以跳过已经执行过的事务,减少了数据发生不一致的风险,提供了一种可靠且方便的机制来管理和控制MySQL复制和故障恢复过程中的事务。它简化了复制拓扑变更的任务,并提供了更精确和可靠的断点恢复功能。
GTID实际上是由UUID+TID (即transactionId)组成的。其中UUID(即server_uuid) 产生于auto.conf文件(cat /data/mysql/data/auto.cnf),是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。GTID在一组复制中,全局唯一。 下面是一个GTID的具体形式 :
如图, Server1(Master)崩溃,根据从上show slave status获得Master_log_File/Read_Master_Log_Pos的值,Server2(Slave)已经跟上了主,Server3(Slave)没有跟上主。这时要是把Server2提升为主,Server3变成Server2的从。这时在Server3上执行change的时候需要做一些计算。
这个问题在5.6的GTID出现后,就显得非常的简单。由于同一事务的GTID在所有节点上的值一致,那么根据Server3当前停止点的GTID就能定位到Server2上的GTID。甚至由于MASTER_AUTO_POSITION功能的出现,我们都不需要知道GTID的具体值,直接使用CHANGE MASTER TO MASTER_HOST=‘xxx’, MASTER_AUTO_POSITION命令就可以直接完成failover的工作。
GTID和Binlog的关系
98895b40ab4b.png#pic_center)
GTID 重要参数的持久化
参数 | comment |
---|---|
gtid_executed | 执行过的所有GTID |
gtid_purged | 丢弃掉的GTID |
gtid_mode | GTID模式 |
gtid_next | session级别的变量,下一个gtid |
gtid_owned | 正在运行的GTID |
enforce_gtid_consistency | 保证GTID安全的参数 |
开启GTID的必备条件
gtid_mode=on (必选)
enforce-gtid-consistency=on (必选)
log_bin=mysql-bin (可选) #高可用切换,最好开启该功能
log-slave-updates=on (可选) #高可用切换,最好打开该功能
GTID是MySQL 5.6的新特性,可简化MySQL的主从切换以及Failover。GTID用于在binlog中唯一标识一个事务。当事务提交时,MySQL Server在写binlog的时候,会先写一个特殊的Binlog Event,类型为GTID_Event,指定下一个事务的GTID,然后再写事务的Binlog。主从同步时GTID_Event和事务的Binlog都会传递到从库,从库在执行的时候也是用同样的GTID写binlog,这样主从同步以后,就可通过GTID确定从库同步到的位置了。也就是说,无论是级联情况,还是一主多从情况,都可以通过GTID自动找点儿,而无需像之前那样通过File_name和File_position找点儿了。
原理:
当启用GTID时,MySQL实例在执行每个事务时都会生成一个全局唯一的GTID。GTID由服务器的唯一标识符(Server UUID)和一个递增的事务ID组成。在每个MySQL实例中,GTID都是自动生成的,确保在整个集群中的每个事务都有唯一的标识符。
MySQL实例会在本地事务日志(二进制日志)中记录GTID。每个事务提交时,它的GTID会写入二进制日志。这样,GTID可以作为复制的基础,用于将事务从主节点复制到从节点。
当MySQL实例作为主节点时,它会将其生成的GTID传播给从节点。具体而言,主节点将GTID写入二进制日志,并将日志传输给从节点。从节点通过解析主节点的二进制日志,读取并应用主节点上的GTID。这样,从节点就知道哪些事务已在主节点上执行。
从节点连接到主节点并请求复制时,主节点会将从节点当前已应用的事务GTID状态汇报给从节点。从节点使用此信息确定从何时开始请求缺失的事务。主节点在发送日志事件时会包含GTID信息,从节点会根据这些信息选择并复制缺失的事务。
基于GTID的复制确保所有节点上的事务以相同的顺序执行,从而使得复制链路上的每个节点保持一致。主节点和从节点之间的通信基于GTID进行,以确保事务按照正确的顺序复制到各个节点。
当发生故障或重新连接从节点时,可以使用GTID来确定从哪个点开始进行复制。从节点可以告知主节点它的当前GTID,然后主节点会将复制进程恢复到该GTID并继续复制。
总之,GTID的工作流程为:
环境:
数据库角色 | IP | 系统版本 | 应用 | 有无数据 | 主机名 |
---|---|---|---|---|---|
主数据库 | 192.168.234.22 | centos8/redhat8 | MariaDB10.3 | 有数据 | master |
从数据库 | 192.168.234.33 | centos8/redhat8 | MariaDB10.3 | 无数据 | kiwi111 |
注:MariaDB操作与MySQL有区别
注:以下配置只适用mariadb最新版(后面有MySQL的配置)
主数据库配置:
[root@master ~]# cat /etc/my.cnf
## 添加以下配置
[mysqld]
log-bin=mysql_bin
server-id=10
gtid_strict_mode=on
log-slave-updates=on
[root@master ~]#
## 重启服务
[root@master ~]# systemctl restart mariadb
从数据库配置:
[root@kiwi111 ~]# vim /etc/my.cnf
[root@kiwi111 ~]# cat /etc/my.cnf
## 添加以下配置
[mysqld]
server-id=20
relay-log=myrelay
gtid_mode=on
log-slave-updates=on
read_only=on
master-info-repository=TABLE
relay-log-info-repository=TABLE
## 重启服务
[root@kiwi111 ~]# systemctl restart mariadb
[root@kiwi111 ~]#
注:以下为MySQL5.6和MySQL5.7版本配置
主数据库配置
[root@master ~]# cat /etc/my.cnf
## 添加以下配置
[mysqld]
log-bin=mysql_bin
server-id=10
gtid_mode=on
enforce-gtid-consistency=true
log-slave-updates=on
从数据库配置
[root@kiwi111 ~]# vim /etc/my.cnf
## 添加以下配置
[mysqld]
server-id=20
relay-log=myrelay
gtid_mode=on
enforce-gtid-consistency=true
log-slave-updates=on
read_only=on
master-info-repository=TABLE
relay-log-info-repository=TABLE
注:以下为MariaDB版本数据同步
主数据库授权用户
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'kiwi'@'192.168.234.33' IDENTIFIED BY '1';
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]>
从数据库设置要同步的主库信息
MariaDB [(none)]> change master to \
master_host='192.168.234.22', \
master_port=3306, \
master_user='kiwi', \
master_password='1', \
master_use_gtid=slave_pos;
Query OK, 0 rows affected (0.009 sec)
开始同步
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.004 sec)
## 查看状态
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.234.22
Master_User: kiwi
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql_bin.000001
Read_Master_Log_Pos: 1204
Relay_Log_File: myrelay.000002
Relay_Log_Pos: 1350
Relay_Master_Log_File: mysql_bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
## 显示两个yes即为成功
注:以下为MySQL5.6和MySQL5.7版本数据同步
主数据库授权用户
GRANT REPLICATION SLAVE ON *.* TO 'kiwi'@'192.168.234.33' IDENTIFIED BY '1';
同步信息并开启同步
change master to \
master_host='主库IP', \
master_port=3306, \
master_user='kiwi', \
master_password='1', \
master_auto_position=1;
## 开启同步
start slave;
show slave status\G;