MySQL 的复制功能是构建大型,高性能应用程序的基础。将 MySQL 的数据分布到多个系统,这种分布机制是通过将MySQL 的某一台主机(master)的数据复制到其它主机(slaves)上,并重新执行一遍来实现的。复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。
复制的体系结构需要遵循以下基本原则:
(1)每个 slave 只能有一个 master;
(2)每个 slave 有一个唯一的服务器ID(server-id);
(3)每个 master 可以有一个或很多 slave;
(4)通过设置 log_slave_updates,一个 slave 可以成为其它 slave 的 master。
MySQL常用的主从复制架构如下:
一主一从复制架构是由一个 master 和一个 slave 组成复制系统。一主多从复制架构是由一个 master 和多个 slave 组成,Slave之间并不相互通信,只能与master进行通信。在实际应用场景中,MySQL 复制90%以上都是一个 Master 复制到一个或者多个 Slave 的架构模式,主要用于读压力比较大的应用。一主多从复制架构如下图所示:
这种结构适合于写操作较少,而读操作很多。可以将读操作分布到其它的 slave,从而减小 master 的压力。但是,当slave 增加到一定数量时,slave 对 master 的负载以及网络带宽会成为瓶颈。
这种结构的优点是:简单、灵活,能够满足大多数应用的需求。
主主复制架构的两台服务器,既是 master,同时又是另一台服务器的 slave。 这样,任何一方所做的变更,都会通过复制应用到另外一方的数据库中。主主复制架构如下图所示:
主主复制架构最大的问题就是更新冲突。假设一个表只有一行一列的数据,其值为1,如果两个服务器分别同时执行如下语句:
在第一个服务器上执行:
mysql> UPDATE tbl SET col=col + 1;
在第二个服务器上执行:
mysql> UPDATE tbl SET col=col * 2;
那么结果是多少呢?一台服务器是4,另一个服务器是3,但是,这并不会产生错误。
在某些应用场景中,可能读写压力差别比较大,读压力特别的大,一个 Master 可能需要上10台甚至更多的 Slave 才能支撑读的压力。这时候,Master 就会比较吃力了,因为仅仅连上来的 Slave IO 线程就比较多,这样写的压力稍微大一点的时候,Master 端因为复制就会消耗较多的资源,很容易造成复制的延时。
遇到这种情况,我们能够利用 MySQL 可以在 Slave 端记录复制所产生变更的 Binary Log 信息的功能,也就是打开 log-slave-update 选项。然后,通过二级复制来减少 Master 端因为复制所带来的压力。级联复制架构如下图所示:
MySQL版本:MySQL5.7
Linux版本:CentOS7.0
主数据库(master)地址:192.168.1.11
从数据库(slave,该数据库又作为13的 master)地址:192.168.1.12
从数据库(slave)地址:192.168.1.13
参见上一篇文章:MySQL主从复制(2)——一主多从架构的搭建(https://blog.csdn.net/weixin_44377973/article/details/107136733)。
(1)在配置文件中添加如下内容
[mysqld]
log-bin=mysql-bin
logbin_format=mixed
#### 把relay log中的记录写入binlog日志
log_slave_updates=1
(2)创建复制用户
mysql> grant replication slave on *.* to 'repl'@'192.168.1.%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.02 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> select host,user,authentication_string from mysql.user;
+-------------+---------------+-------------------------------------------+
| host | user | authentication_string |
+-------------+---------------+-------------------------------------------+
| localhost | root | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| localhost | mysql.session | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| localhost | mysql.sys | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| % | wgx | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| 192.168.1.% | repl | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+-------------+---------------+-------------------------------------------+
5 rows in set (0.02 sec)
(3)导出数据库中的数据并记录日志文件及位置
step1、导出数据库之前,给数据库加锁,阻止对数据库进行任何的写操作。
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.01 sec)
mysql> use hist;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> drop table t1;
ERROR 1223 (HY000): Can't execute the query because you have a conflicting read lock
step2、导出主库中的所有数据库数据
[root@Mysql11 ~]# mysqldump -uroot -p123456 --all-databases --master-data=2 --events > /tmp/all_bak.sql
step3、把备份的主库数据复制到从库
[root@Mysql11 ~]# scp /tmp/all_bak.sql 192.168.1.13:/tmp/
[email protected]'s password:
all_bak.sql 100% 834KB 833.7KB/s 00:00
[root@Mysql11 ~]#
step4、解锁,查看二进制日志信息
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005 | 866214 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
(1)在配置文件中添加如下内容
[mysqld]
server-id=3
relay-log = mysql-relay-log
(2)配置完成后重启mysql服务,查看relay log文件信息:
[root@localhost ~]# ll /var/lib/mysql/mysql-relay*
-rw-r-----. 1 mysql mysql 207 7月 5 21:31 /var/lib/mysql/mysql-relay-log.000001
-rw-r-----. 1 mysql mysql 320 7月 5 21:31 /var/lib/mysql/mysql-relay-log.000002
-rw-r-----. 1 mysql mysql 76 7月 5 21:31 /var/lib/mysql/mysql-relay-log.index
(3)导入主服务器上的数据
[root@localhost ~]# mysql -uroot -p123456 < /tmp/all_bak.sql
(4)配置主从同步参数
在从服务器上执行如下命令:
change master to
master_host='192.168.1.12',
master_port=3306,
master_user='repl',
master_password='123456',
master_log_file='mysql-bin.000005',
master_log_pos=866214;
(5)开启从库的服务(启动IO和SQL线程)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
(6)查看主从复制的状态
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.12
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000005
Read_Master_Log_Pos: 866214
Relay_Log_File: mysql-relay-log.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000005
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: 866214
Relay_Log_Space: 527
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
Master_UUID: 800e4f85-2e00-11ea-a7ce-000c29cd5d3e
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
mysql> create database mydb;
Query OK, 1 row affected (0.04 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hist |
| mydb |
| mysql |
| performance_schema |
| sys |
| wanggx |
+--------------------+
7 rows in set (0.00 sec)
mysql> use mydb;
Database changed
mysql> create table goods(id int primary key auto_increment,name char(20));
Query OK, 0 rows affected (0.28 sec)
mysql> insert into goods(name) values('mobile');
Query OK, 1 row affected (0.09 sec)
mysql> insert into goods(name) values('computer');
Query OK, 1 row affected (0.03 sec)
mysql>
mysql> select * from goods;
+----+----------+
| id | name |
+----+----------+
| 1 | mobile |
| 2 | computer |
+----+----------+
2 rows in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hist |
| mydb |
| mysql |
| performance_schema |
| sys |
| wanggx |
+--------------------+
7 rows in set (0.00 sec)
mysql>
mysql> use mydb;
Database changed
mysql> select * from goods;
+----+----------+
| id | name |
+----+----------+
| 1 | mobile |
| 2 | computer |
+----+----------+
2 rows in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hist |
| mydb |
| mysql |
| performance_schema |
| sys |
| wanggx |
+--------------------+
7 rows in set (0.00 sec)
mysql> use mydb;
Database changed
mysql> select * from goods;
+----+----------+
| id | name |
+----+----------+
| 1 | mobile |
| 2 | computer |
+----+----------+
2 rows in set (0.00 sec)
mysql> drop database mydb;
Query OK, 1 row affected (0.58 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hist |
| mysql |
| performance_schema |
| sys |
| wanggx |
+--------------------+
6 rows in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hist |
| mysql |
| performance_schema |
| sys |
| wanggx |
+--------------------+
6 rows in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hist |
| mysql |
| performance_schema |
| sys |
| wanggx |
+--------------------+
6 rows in set (0.00 sec)