基础环境
基于centOS7-MySQL8.0.35版本
我们先准备一台主服务器两台从服务器来实现我们主从同步的诉求
Master:192.168.75.142
slave1:192.168.75.143
slave:192.168.75.145
binlog主从同步
主库配置
#我们需要在主从库中都需要添加server_id,每个库的server_id都不唯一
[root@localhost ~]# tail -1 /etc/my.cnf
server_id=1
#重启mysql服务让配置分件生效
[root@localhost ~]# systemctl restart mysqld
#备份:
[root@localhost ~]# mysqldump --opt -B -u root -p school school1> school.sql
#授权用户:
mysql> create user rep@'192.168.75.%' identified with mysql_native_password by 'Mhn@2001';
mysql> grant replication slave on *.* to rep@'192.168.75.%';
从库配置
[root@localhost ~]# tail -1 /etc/my.cnf
server_id=2
[root@localhost ~]# systemctl restart mysqld
[root@localhost ~]# tail -1 /etc/my.cnf
server_id=3
[root@localhost ~]# systemctl restart mysqld
#还原主库备份,到从服务器家目录下:
scp db.sql 192.168.75.143:/root/
scp db.sql 192.168.75.145:/root/
#在两台从主机上将复制的备份文件导入数据库
mysql -uroot -pMysql@123 < school.sql
#主库查看
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 679 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
从库配置
change master to
master_host='192.168.75.42',
master_user='rep',
master_password='Mhn@2001',
master_log_file='mysql-bin.000001',
master_log_pos=679,
get_master_public_key=1;
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.75.142
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: binlog.000002
Read_Master_Log_Pos: 694
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 323
Relay_Master_Log_File: binlog.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
从这里可以查看到状态没有问题可以进行主从同步
其他可选配置
#[可选] 0(默认)表示读写(主机),1表示只读(从机)
read-only=0
#设置日志文件保留的时长,单位是秒
binlog_expire_logs_seconds=6000
#控制单个二进制日志大小。此参数的最大和默认值是1GB
max_binlog_size=200M
#[可选]设置不要复制的数据库
binlog-ignore-db=test
#[可选]设置需要复制的数据库,默认全部记录。
binlog-do-db=需要复制的主数据库名字
#[可选]设置binlog格式
binlog_format=STATEMENT
素材
数据库备份,数据库为school,素材如下
1.创建student和score表
CREATE TABLE student (
id INT(10) NOT NULL UNIQUE PRIMARY KEY ,
name VARCHAR(20) NOT NULL ,
sex VARCHAR(4) ,
birth YEAR,
department VARCHAR(20) ,
address VARCHAR(50)
);
创建score表。SQL代码如下:
CREATE TABLE score (
id INT(10) NOT NULL UNIQUE PRIMARY KEY AUTO_INCREMENT ,
stu_id INT(10) NOT NULL ,
c_name VARCHAR(20) ,
grade INT(10)
);
2.为student表和score表增加记录
向student表插入记录的INSERT语句如下:
INSERT INTO student VALUES( 901,'张老大', '男',1985,'计算机系', '北京市海淀区');
INSERT INTO student VALUES( 902,'张老二', '男',1986,'中文系', '北京市昌平区');
INSERT INTO student VALUES( 903,'张三', '女',1990,'中文系', '湖南省永州市');
INSERT INTO student VALUES( 904,'李四', '男',1990,'英语系', '辽宁省阜新市');
INSERT INTO student VALUES( 905,'王五', '女',1991,'英语系', '福建省厦门市');
INSERT INTO student VALUES( 906,'王六', '男',1988,'计算机系', '湖南省衡阳市');
向score表插入记录的INSERT语句如下:
INSERT INTO score VALUES(NULL,901, '计算机',98);
INSERT INTO score VALUES(NULL,901, '英语', 80);
INSERT INTO score VALUES(NULL,902, '计算机',65);
INSERT INTO score VALUES(NULL,902, '中文',88);
INSERT INTO score VALUES(NULL,903, '中文',95);
INSERT INTO score VALUES(NULL,904, '计算机',70);
INSERT INTO score VALUES(NULL,904, '英语',92);
INSERT INTO score VALUES(NULL,905, '英语',94);
INSERT INTO score VALUES(NULL,906, '计算机',90);
INSERT INTO score VALUES(NULL,906, '英语',85);
create database school;
use school;
CREATE TABLE `Student` (
`Sno` int(10) NOT NULL COMMENT '学号', `Sname` varchar(16) NOT NULL COMMENT '姓名',
`Ssex` char(2) NOT NULL COMMENT '性别', `Sage` tinyint(2) NOT NULL DEFAULT '0' COMMENT '学生年龄',
`Sdept` varchar(16) DEFAULT 'NULL' COMMENT '学生所在系别', PRIMARY KEY (`Sno`)
) ;
INSERT INTO `Student` VALUES (1, '陆亚', '男', 24, '计算机网络'),(2, 'tom', '男', 26, '英语'),(3, '张阳', '男', 21, '物流管理'), (4, 'alex', '女', 22, '电子商务');
gtid主从同步
GTID的工作原理:
1.当一个事务在主库端执行并提交时,产生GTID,一同记录到binlog日志中。
2.binlog传输到slave,并存储到salve的relaylog后,读取这个GTID的这个值设置GTID——next变量,即告诉slave,下一个要执行的GTID值。
3.sql线程从relaylog中获取GTID,然后对比slave端的binlog是否有该GTID。
4.如果有记录说明该GTID的事务已经执行,slave会忽略。
5.如果没有记录,slave会执行该GTID事务,并记录到该GTID到自身的binlog,在读取该事务前会检查其他session持有该GTID,确保不被重复执行。
6.在解析过程中会判断是否有主键,如果没有就用二级索引,如果有就用全部扫描。
主库配置
主库配置
[root@localhost ~]# vim /etc/my.cnf
server_id=1
gtid_mode=ON #开启gtid模式
enforce-gtid-consistency=ON #强制gtid一致性,开启后对特定的create table不支持
log-bin=mysql-bin #开启二进制日志
log-slave-updates=1 #从库binlog记录主库同步的操作日志
skip-slave-start=1 #跳过slave复制线程
#重启服务
[root@localhost ~]# systemctl restart mysqld
#查看服务状态
[root@localhost ~]# systemctl status mysqld
● mysqld.service - MySQL Server
Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
Active: active (running) since 四 2024-02-29 11:04:01 CST; 37min ago
Docs: man:mysqld(8)
http://dev.mysql.com/doc/refman/en/using-systemd.html
Process: 3740 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
Main PID: 3770 (mysqld)
Status: "Server is operational"
Tasks: 40
CGroup: /system.slice/mysqld.service
└─3770 /usr/sbin/mysqld
[root@localhost ~]# mysql -uroot -pMysql@123
mysql> show variables like '%gtid%';
+----------------------------------+------------------------------------------+
| Variable_name | Value |
+----------------------------------+------------------------------------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | ff800e4d-d478-11ee-83a4-000c29b35fbd:1-8 |
| gtid_executed_compression_period | 0 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+------------------------------------------+
9 rows in set (0.01 sec)
从库配置
#slave1
server_id=2
gtid_mode=ON
enforce-gtid-consistency=ON
log-bin=mysql-bin
log-slave-updates=1
skip-slave-start=1
mysql> show variables like '%gtid%';
+----------------------------------+------------------------------------------+
| Variable_name | Value |
+----------------------------------+------------------------------------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | ff800e4d-d478-11ee-83a4-000c29b35fbd:1-8 |
| gtid_executed_compression_period | 0 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+------------------------------------------+
9 rows in set (0.00 sec)
#slave2
server_id=3
gtid_mode=ON
enforce-gtid-consistency=ON
log-bin=mysql-bin
log-slave-updates=1
skip-slave-start=1
mysql> show variables like '%gtid%';
+----------------------------------+------------------------------------------+
| Variable_name | Value |
+----------------------------------+------------------------------------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | ff800e4d-d478-11ee-83a4-000c29b35fbd:1-8 |
| gtid_executed_compression_period | 0 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+------------------------------------------+
9 rows in set (0.00 sec)
开启主从同步
#主库
mysql> stop slave;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> create user rep@'192.168.75.%' identified with mysql_native_password by 'Mhn@2001';
Query OK, 0 rows affected (0.04 sec)
mysql> grant replication slave on *.* to rep@'192.168.75.%';
Query OK, 0 rows affected (0.00 sec)
#从库,两个都一样
mysql> CHANGE MASTER TO
-> MASTER_HOST = '192.168.75.142',
-> MASTER_USER = 'rep',
-> MASTER_PASSWORD = 'Mhn@2001',
-> MASTER_AUTO_POSITION = 1;
Query OK, 0 rows affected, 7 warnings (0.01 sec)
#主库建立数据库
mysql> create database book;
Query OK, 1 row affected (0.00 sec)
mysql> use book;
Database changed
mysql> CREATE TABLE books (name char(66),price int,pages int);
'80','666');
INSERT INTO books(name,price,pages) VALUES('Artificial Intelligence','166','666');Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO books(name,price,pages) VALUES('Linux','30','666');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO books(name,price,pages) VALUES('Cloud Computing','60','666');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO books(name,price,pages) VALUES('Operation System','80','666');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO books(name,price,pages) VALUES('Artificial Intelligence','166','666');
Query OK, 1 row affected (0.00 sec)
mysql> select * from books;
+-------------------------+-------+-------+
| name | price | pages |
+-------------------------+-------+-------+
| Linux | 30 | 666 |
| Cloud Computing | 60 | 666 |
| Operation System | 80 | 666 |
| Artificial Intelligence | 166 | 666 |
+-------------------------+-------+-------+
4 rows in set (0.00 sec)
#从库的状态查看
#slave1
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.75.142
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 680
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 896
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
#slave2
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.75.142
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 680
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 896
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
#从库查看
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| book |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
mysql> use book;
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> show tables;
+----------------+
| Tables_in_book |
+----------------+
| books |
+----------------+
1 row in set (0.00 sec)
mysql> select * from book.books;
+-------------------------+-------+-------+
| name | price | pages |
+-------------------------+-------+-------+
| Linux | 30 | 666 |
| Cloud Computing | 60 | 666 |
| Operation System | 80 | 666 |
| Artificial Intelligence | 166 | 666 |
+-------------------------+-------+-------+
4 rows in set (0.00 sec)
主库
从库1
从库2
可以看到最后的gtid值都一样这就说明我们配置完成。
解决问题
在gtid配置中如果出现 Last_IO_Error: Error connecting to source 'root@192.168.75.142:3306'. This was attempt 1/86400, with a delay of 60 seconds between attempts. Message: Host '192.168.75.143' is not allowed to connect to this MySQL server
可以尝试更改一下主库的mysql> create user rep@'192.168.75.%' identified with mysql_native_password by 'Mhn@2001';
Query OK, 0 rows affected (0.04 sec)
首先我们需要将所有的库进行stop slave;操作,然后进行操作,修改完成后再次开启就可以使用。
在遇到问题可以使用翻译和查询日志来进行查看
如果我们是使用一段时间mysql后才配置的gtid主从同步需要注意gtid值需要开始的位置,不能从1开始
需要注入空事务,从而解决起始位置相同
stop slave;
set gtid_next='gtid值:开始位置';
begin;commit;
set gtid_next='AUTOMATIC';
初始化mysql
学习过程中因为gtid数据不同步可以进行初始化mysql
在初始化之前必须要将mysql数据目录所有内容全部清空
systemctl stop mysqld
mysql --initialize --uesr=mysql
然后重新启动mysql
systemctl restart mysqld
进入mysql,进入后需要刷新权限表
FLUSH PRIVILEGES;
最后再修改密码
alter user root@localhost identified by 'Mysql@123';
最后需要在配置文件中删除--skip-grant-tables