优点:适合数据量小的网站,如企业网站。
缺点:单个数据库无法满足日益增长的读写请求;
高可用性:站点高可用,冗余站点;服务高可用,冗余服务;数据高可用,冗余数据。
负载均衡:切换某服务访问某节点,分摊单个节点的数据库压力
可伸缩性:新增数据库节点便利,方便扩容。
MySQL集群中各实例的数据同步,均基于mysql的复制机制。
第一步:主库开启bin-log日志: ** 主库需要设置开启记录二进制日志,提交数据更新的事务之前将更新的事件记录都二进制日志中,后才进行事务提交。
第二步:备库建立IO线程连接: ** 备库创建IO线程与主库创建连接,主库上启动一个binlog-dump线程。该线程会读取主库二进制事件,该线程不会对事件进行轮询。如果从库数据与主库已经保持一致后,该线程进入休眠状态,一旦主库有新事件会以信号量唤醒binlog-dump线程。备库IO线程会将事件写入到中继日志(relay-log)中。
第三步:SQL线程重放数据:**SQL线程执行最后一步,从中继日志中获取事件并在备库中执行,从而实现数据库的更新。
M-S:一主一从
M-S-S:一主多从
M-M:双主
M-M-S-S:双主多从
master1——192.168.28.141——mysql8.0.34——数据库已有数据
[root@master1 ~]# mysql -uroot -p'Admin.123'
mysql> create database class;
Query OK, 1 row affected (0.00 sec)
mysql> create table class.stu (id int,name varchar(50));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into class.stu values(1,'a');
Query OK, 1 row affected (0.05 sec)
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | a |
+------+------+
1 row in set (0.00 sec)
slave1——192.168.28.143——mysql8.0.34——数据库没有数据
开启二进制日志,指定master的server-id标识为1
[root@master1 ~]# echo -e "log_bin \nserver-id=1" >> /etc/my.cnf
[root@master1 ~]# systemctl restart mysqld
创建复制用户并授权
[root@master1 ~]# mysql -uroot -p'Admin.123'
mysql> create user 'rep'@'192.168.28.%' identified by 'Admin.123';
Query OK, 0 rows affected (0.05 sec)
mysql> grant replication slave on *.* to 'rep'@'192.168.28.%';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> show grants for 'rep'@'192.168.28.%';
+--------------------------------------------------------+
| Grants for [email protected].% |
+--------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `rep`@`192.168.28.%` |
+--------------------------------------------------------+
1 row in set (0.01 sec)
备份
[root@master1 ~]# mysqldump -uroot -p'Admin.123' -A --single-transaction --source-data=2 --flush-logs > `date +'%F-%T'-all.sql`
[root@master1 ~]# ls
2023-09-10-21:20:02-all.sql anaconda-ks.cfg
[root@master1 ~]# cat 2023-09-10-21\:20\:02-all.sql
...
-- CHANGE MASTER TO MASTER_LOG_FILE='master1-bin.000003', MASTER_LOG_POS=157;
将备份文件传输至slave1上
[root@master1 ~]# scp ./2023-09-10-21\:20\:02-all.sql root@slave1:/root
[root@slave1 ~]# ls
2023-09-10-21:20:02-all.sql anaconda-ks.cfg
#测试能否以复制用户登录master1的数据库
[root@slave1 ~]# mysql -h master1 -urep -p'Admin.123'
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
...
#设置slave1的server-id
[root@slave1 ~]# echo "server-id=2" >> /etc/my.cnf
[root@slave1 ~]# systemctl restart mysqld
恢复数据
[root@slave1 ~]# mysql -uroot -p'Admin.123'
mysql> set sql_log_bin=0; #关闭二进制日志,避免产生因恢复操作出现的日志
mysql> source /root/2023-09-10-21:20:02-all.sql #导入数据
mysql> change master to master_host='master1',master_user='rep',master_password='Admin.123',master_log_file='/var/lib/mysql/master1-bin.000003',master_log_pos=157;
mysql> start slave; #开启同步
#查看从数据库的状态
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: master1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master1-bin.000003
Read_Master_Log_Pos: 157
Relay_Log_File: slave1-relay-bin.000002
Relay_Log_Pos: 328
Relay_Master_Log_File: master1-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
此时数据已保持一致
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | a |
+------+------+
1 row in set (0.01 sec)
在master1中新增数据
mysql> insert into class.stu values(2,'b');
Query OK, 1 row affected (0.00 sec)
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | a |
| 2 | b |
+------+------+
2 rows in set (0.00 sec)
查看slave1是否同步,已同步
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | a |
| 2 | b |
+------+------+
2 rows in set (0.00 sec)
双主避免单点故障。
gtid_mode=ON 是一种MySQL的特性,它为每个事务分配一个唯一的全局事务ID。这个选项用于启用GTID。在大多数情况下,你应该开启这个选项,因为它可以提供更好的复制和故障恢复功能。
enforce_gtid_consistency=1 这个选项确保了在MySQL服务器上所有线程和复制都严格遵守GTID的一致性。如果设置为1,那么MySQL将不允许在同一个会话中执行两次相同的事务。这对于确保数据的一致性非常有用。
数据库配置文件添加如下
log_bin
server-id=1 #每台服务器server-id 不一样
gtid_mode=ON
enforce_gtid_consistency=1
[root@master1 ~]# mysql -uroot -p'Admin.123'
mysql> create database class;
Query OK, 1 row affected (0.00 sec)
mysql> create table class.stu (id int,name varchar(50));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into class.stu values(1,'wei');
Query OK, 1 row affected (0.09 sec)
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | wei |
+------+------+
1 row in set (0.00 sec)
[root@master1 ~]# vim /etc/my.cnf
...
log_bin
server-id=1
gtid_mode=ON
enforce_gtid_consistency=1
[root@master1 ~]# systemctl restart mysqld
[root@master1 ~]# mysql -uroot -p'Admin.123'
mysql> create user 'rep'@'192.168.28.%' identified by 'Admin.123';
Query OK, 0 rows affected (0.05 sec)
mysql> grant replication slave on *.* to 'rep'@'192.168.28.%';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> show grants for 'rep'@'192.168.28.%';
+--------------------------------------------------------+
| Grants for [email protected].% |
+--------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `rep`@`192.168.28.%` |
+--------------------------------------------------------+
1 row in set (0.01 sec)
[root@master1 ~]# mysqldump -uroot -p'Admin.123' -A --single-transaction --source-data=2 --flush-logs > `date +'%F-%T'-all.sql`
[root@master1 ~]# scp ./2023-09-11-02\:10\:19-all.sql [email protected]:/root/
[root@master2 ~]# vim /etc/my.cnf
...
log_bin
server-id=1
gtid_mode=ON
enforce_gtid_consistency=1
[root@master2 ~]# systemctl restart mysqld
[root@master2 ~]# ls
2023-09-11-02:10:19-all.sql anaconda-ks.cfg
[root@master2 ~]# mysql -uroot -p'Admin.123'
mysql> set sql_log_bin=0;
mysql> source /root/2023-09-11-02:10:19-all.sql
mysql> change master to master_host='master1',master_user='rep',master_password='Admin.123',get_master_public_key=1,master_auto_position=1;
mysql> start slave;
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: master1
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master1-bin.000005
Read_Master_Log_Pos: 197
Relay_Log_File: master2-relay-bin.000002
Relay_Log_Pos: 377
Relay_Master_Log_File: master1-bin.000005
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | wei |
+------+------+
1 row in set (0.00 sec)
get_master_public_key=1 在MySQL的主从复制中,主服务器会生成一个公钥(即get_master_public_key),并将其发送给从服务器。从服务器使用该公钥与主服务器建立加密连接,以确保数据传输的安全性。不加此选项会有如下报错
2023-09-10T16:27:42.806971Z 10 [ERROR] [MY-010584] [Repl] Replica I/O for channel '': Error connecting to source 'rep@master1:3306'. This was attempt 2/86400, with a delay of 60 seconds between attempts. Message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection. Error_code: MY-002061
[root@master2 ~]# mysql -uroot -p'Admin.123'
mysql> create user 'per'@'192.168.28.%' identified by 'Admin.123';
Query OK, 0 rows affected (0.00 sec)
mysql> grant replication slave on *.* to 'per'@'192.168.28.%';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> show grants for 'per'@'192.168.28.%';
+--------------------------------------------------------+
| Grants for [email protected].% |
+--------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `per`@`192.168.28.%` |
+--------------------------------------------------------+
1 row in set (0.00 sec)
[root@master1 ~]# mysql -uroot -p'Admin.123'
mysql> change master to master_host='master2',master_user='per',master_password='Admin.123',get_master_public_key=1,master_auto_position=1;
Query OK, 0 rows affected, 8 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: master2
Master_User: per
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master2-bin.000002
Read_Master_Log_Pos: 663
Relay_Log_File: master1-relay-bin.000002
Relay_Log_Pos: 747
Relay_Master_Log_File: master2-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
[root@master1 ~]# mysql -uroot -p'Admin.123'
mysql> insert into class.stu values(2,'shu');
Query OK, 1 row affected (0.00 sec)
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | wei |
| 2 | shu |
+------+------+
2 rows in set (0.00 sec)
[root@master2 ~]# mysql -uroot -p'Admin.123'
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | wei |
| 2 | shu |
+------+------+
2 rows in set (0.01 sec)
[root@master2 ~]# mysql -uroot -p'Admin.123'
mysql> insert into class.stu values(3,'wu');
Query OK, 1 row affected (0.00 sec)
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | wei |
| 2 | shu |
| 3 | wu |
+------+------+
3 rows in set (0.00 sec)
[root@master1 ~]# mysql -uroot -p'Admin.123'
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | wei |
| 2 | shu |
| 3 | wu |
+------+------+
3 rows in set (0.00 sec)
master1备份数据,用以两个slave同步数据
[root@master1 ~]# mysqldump -uroot -p'Admin.123' -A --single-transaction --source-data=2 --flush-logs > `date +'%F-%T'-all.sql`
[root@master1 ~]# ls
2023-09-11-03:11:40-all.sql anaconda-ks.cfg
[root@master1 ~]# scp ./2023-09-11-02\:10\:19-all.sql [email protected]:/root/
[email protected]'s password:
2023-09-11-02:10:19-all.sql 100% 1255KB 57.5MB/s 00:00
[root@master1 ~]# scp ./2023-09-11-02\:10\:19-all.sql [email protected]:/root/
[email protected]'s password:
2023-09-11-02:10:19-all.sql
[root@slave1 ~]# ls
2023-09-11-02:10:19-all.sql anaconda-ks.cfg
[root@slave1 ~]# mysql -uroot -p'Admin.123' < 2023-09-11-02\:10\:19-all.sql
[root@slave1 ~]# vim /etc/my.cnf
...
log_bin
server-id=3
gtid_mode=ON
enforce_gtid_consistency=1
master-info-repository=TABLE
relay-log-info-repository=TABLE
[root@slave1 ~]# systemctl restart mysqld
[root@slave1 ~]# mysql -uroot -p'Admin.123'
mysql> change master to master_host='192.168.28.141',master_user='rep',master_password='Admin.123',get_master_public_key=1,master_auto_position=1 for channel '192.168.28.141';
Query OK, 0 rows affected, 8 warnings (0.00 sec)
mysql> change master to master_host='192.168.28.143',master_user='per',master_password='Admin.123',get_master_public_key=1,master_auto_position=1 for channel '192.168.28.143';
Query OK, 0 rows affected, 8 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.28.141
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master1-bin.000006
Read_Master_Log_Pos: 237
Relay_Log_File: slave1-relay-bin-192@002e168@[email protected]
Relay_Log_Pos: 457
Relay_Master_Log_File: master1-bin.000006
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
*************************** 2. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.28.143
Master_User: per
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master2-bin.000002
Read_Master_Log_Pos: 1235
Relay_Log_File: slave1-relay-bin-192@002e168@[email protected]
Relay_Log_Pos: 1455
Relay_Master_Log_File: master2-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | wei |
| 2 | shu |
| 3 | wu |
+------+------+
3 rows in set (0.00 sec)
[root@slave2 ~]# ls
2023-09-11-02:10:19-all.sql anaconda-ks.cfg
[root@slave2 ~]# mysql -uroot -p'Admin.123' < 2023-09-11-02\:10\:19-all.sql
[root@slave2 ~]# vim /etc/my.cnf
...
log_bin
server-id=4
gtid_mode=ON
enforce_gtid_consistency=1
master-info-repository=TABLE
relay-log-info-repository=TABLE
[root@slave2 ~]# systemctl restart mysqld
[root@slave2 ~]# mysql -uroot -p'Admin.123'
mysql> change master to master_host='192.168.28.141',master_user='rep',master_password='Admin.123',get_master_public_key=1,master_auto_position=1 for channel '192.168.28.141';
Query OK, 0 rows affected, 8 warnings (0.00 sec)
mysql> change master to master_host='192.168.28.143',master_user='per',master_password='Admin.123',get_master_public_key=1,master_auto_position=1 for channel '192.168.28.143';
Query OK, 0 rows affected, 8 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.28.141
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master1-bin.000006
Read_Master_Log_Pos: 237
Relay_Log_File: slave2-relay-bin-192@002e168@[email protected]
Relay_Log_Pos: 457
Relay_Master_Log_File: master1-bin.000006
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
*************************** 2. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.28.143
Master_User: per
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master2-bin.000002
Read_Master_Log_Pos: 1235
Relay_Log_File: slave2-relay-bin-192@002e168@[email protected]
Relay_Log_Pos: 1455
Relay_Master_Log_File: master2-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
mysql> select * from class.stu;
+------+------+
| id | name |
+------+------+
| 1 | wei |
| 2 | shu |
| 3 | wu |
+------+------+
3 rows in set (0.00 sec)
master-info-repository 是MySQL主从复制配置中的选项,用于指定主服务器信息存储的方式。它可以在配置文件或表中存储主服务器的信息。
relay-log-info-repository 是MySQL主从复制中的一个参数,用于指定relay log信息存储的方式。
经测试,当修改master1或master2数据时,其余三台设均能实现数据同步。