一、主从复制原理
主从复制的相关程序:
-
日志
二进制日志
中继日志(relay log) -
线程
主服务器:mysql dump线程(传输二进制日志给从服务器)
从服务器:IO线程(接收二进制日志,写入中继日志),sql线程(读取中继日志,写入数据库,同步操作达到数据同步)
点击查看代码
主从复制原理:
1. 主节点负责用户的写操作,用户发起写操作后,会修改数据库
2. 数据库修改后,会更新主节点上的二进制日志
3. 从服务器会开启io线程,主动请求和主服务器同步
4. 主服务器会产生一个dump线程, 一边读取二进制日志一边将二进制日志通过 网络传给从服务器
5. io线程会将主服务器的二进制日志写入从服务器的中继日志,这时只是生成了一个文件,并没有同步
6. 从服务器再开启sql线程,将中继日志中操作写入数据库完成更新,主从数据就保持一致了
注意:复制需要考虑二进制日志事件记录格式
二、实现主从复制
1.新建主从复制
主节点:
1.启用二进制日志,为当前节点设置一个全局唯一的ID号
点击查看代码
[root@node5 ~]# systemctl stop firewalld
[root@node5 ~]# setenforce 0
[root@node5 ~]# vim /etc/my.cnf
server-id=50 //指明数据库的编号,区分自己的日志和别人的日志
log-bin=/data/mysql/mysql-bin //指明二进制日志所存在的目录
[root@node5 ~]# mkdir -p /data/mysql //建立文件夹
[root@node5 ~]# chown -R mysql.mysql /data/ //修改权限
[root@node5 ~]# systemctl restart mysqld //重启服务
2.创建有复制权限的用户账号
点击查看代码
[root@node5 ~]# mysql -uroot -pabc123
mysql> grant replication slave on *.* to test@'192.168.204.%' identified by 'Admin@123';
//注意:先建立用户,再看日志位置。否则建立用户这步操作不会记录在日志中
3.查看二进制日志的文件和位置开始进行复制
点击查看代码
mysql> show master status;
//查看同步文件和同步的位置
从节点:
1.开启二进制日志
点击查看代码
[root@node7 ~]# systemctl stop firewalld
[root@node7 ~]# setenforce 0
[root@node7 ~]# vim /etc/my.cnf
server-id=70 //要和主不一样,否则会造成主从复制失败
log-bin=/data/mysql/mysql-bin
[root@node7 ~]# mkdir -p /data/mysql
[root@node7 ~]# chown -R mysql.mysql /data/
[root@node7 ~]# systemctl restart mysqld
2.使用有复制权限的用户账号连接至主服务器,并启动复制线程
点击查看代码
mysql> help change master to //使用帮助,复制参数进行修改
CHANGE MASTER TO
MASTER_HOST='192.168.204.50',
MASTER_USER='test',
MASTER_PASSWORD='Admin@123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=449;
//最后两行要与主节点中show master status;显示的数据相对应
mysql> start slave; //开启io线程和sql线程,开启主从复制
mysql> show slave status\G; //查看从服务器状态
mysql> show processlist; //查看进程列表
验证:从主服务器上新建库,看从服务器是否同步
点击查看代码
create database cxk;
//在主节点上建立数据测试
`补充:`
如果两个线程不是Yes
stop slave;
reset slave all; //清空主从配置
重新配置
2.完备+主从复制
假设主节点的数据库已经运行了一段时间,产生了一定量的数据,主从复制只能复制开启后数据,那之前的数据如何处理?
主节点:
点击查看代码
`启用二进制日志`
[root@node5 ~]# systemctl stop firewalld
[root@node5 ~]# setenforce 0
[root@node5 ~]# vim /etc/my.cnf
server-id=50
log-bin=/data/mysql/mysql-bin
[root@node5 ~]# mkdir -p /data/mysql //建立文件夹
[root@node5 ~]# chown -R mysql.mysql /data/ //修改权限
[root@node5 ~]# systemctl restart mysqld //重启服务
`导入数据库`
[root@node5 ~]# mysql -uroot -pabc123 < hellodb_innodb.sql
[root@node5 ~]# mysql -uroot -pabc123 -e "select * from hellodb.students" //查看是否有数据
`完备`
[root@node5 ~]# mysqldump -uroot -pabc123 -A -F --master-data=1 --single-transaction > /data/all.sql
`创建用户`
[root@node5 ~]# mysql -uroot -pabc123
mysql> create user test@'192.168.204.%' identified by "Admin@123"; //新建主从复制用户
mysql> grant replication slave on *.* to test@'192.168.204.%'; //授权主从复制用户
`拷贝备份文件`
[root@node5 ~]# scp /data/all.sql 192.168.204.70:/opt
从节点:
点击查看代码
`启用二进制日志`
[root@node7 ~]# systemctl stop firewalld
[root@node7 ~]# setenforce 0
[root@node7 ~]# vim /etc/my.cnf
server-id=70
log-bin=/data/mysql/mysql-bin
[root@node7 ~]# mkdir -p /data/mysql
[root@node7 ~]# chown -R mysql.mysql /data/
[root@node7 ~]# systemctl restart mysqld
`修改备份脚本`
[root@node7 ~]# vim /opt/all.sql
//找到 CHANGE MASTER TO 的行修改如下
CHANGE MASTER TO
MASTER_HOST='192.168.204.50',
MASTER_USER='test',
MASTER_PASSWORD='Admin@123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;
//由于之前再备份的时候加入了 --master-data=1 选项,就添加了主从复制的选项000002文件的154位置往后开始主从复制
//000002文件154位置之前的配置由备份文件自行实现
`导入数据库`
[root@node7 ~]# mysql -uroot -pabc123
mysql> set sql_log_bin=0; //临时关闭二进制日志
mysql> source /opt/all.sql //导入数据库
mysql> start slave; //开启主从复制
mysql> show slave status\G; //查看从节点的状态
3.复制错误解决方法
从节点一般是只读模式,如果从节点里写入了数据那么主从复制就会失败,有可能主键冲突等等。
解决方法:
- 忽略错误,跳过错误,手动修复,适用于主从之间数据差不大
- 重建从服务器,适用于数据差比较大
点击查看代码
//系统变量,指定跳过复制事件的个数
SET GLOBAL sql_slave_skip_counter = N
//服务器选项,只读系统变量,指定跳过事件的ID
[mysqld]
slave_skip_errors=1007|ALL
示例:复制冲突的解决
点击查看代码
//先在从上建表
create table info (id int,name char(10),age char(10));
//再在主上建表 插入信息
create table info (id int,name char(10),age char(10));
insert info values(1,'a',10);
//此时报错 从主机会报错
show slave status\G
//方法1:可以跳过错误
stop slave;
set global sql_slave_skip_counter=1;
start slave;
//方法2
vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
slave_skip_errors=1007|ALL
systemctl restart mysqld
三、级联 主从复制
需要在中间的从服务器启用 log_slave_updates 配置 ,实现中间slave节点能将master的二进制日志在本机进行数据库更新,并且也同时更新本机的二进制,从而实现级联复制
实例
- 7-1 主节点 192.168.204.50
- 7-2 二级节点 192.168.204.60
- 7-3 从节点 192.168.204.70
主节点:
点击查看代码
//启用二进制日志
[root@node5 ~]# systemctl stop firewalld
[root@node5 ~]# setenforce 0
[root@node5 ~]# vim /etc/my.cnf
server-id=50
log-bin=/data/mysql/mysql-bin
[root@node5 ~]# mkdir -p /data/mysql
[root@node5 ~]# chown -R mysql.mysql /data/
[root@node5 ~]# systemctl restart mysqld
//建立用户
[root@node5 ~]# mysql -uroot -pabc123
mysql> grant replication slave on *.* to test@'192.168.204.%' identified by 'Admin@123';
//查看二进制日志位置
mysql> show master status;
二级节点:
点击查看代码
//启用二进制日志
[root@node6 ~]# systemctl stop firewalld
[root@node6 ~]# setenforce 0
[root@node6 ~]# vim /etc/my.cnf
server-id=60
log-bin=/data/mysql/mysql-bin
log_slave_updates //级联操作必须加的,只在级联节点上操作
[root@node6 ~]# mkdir -p /data/mysql
[root@node6 ~]# chown -R mysql.mysql /data/
[root@node6 ~]# systemctl restart mysqld
[root@node6 ~]# mysql -uroot -pabc123
CHANGE MASTER TO
MASTER_HOST='192.168.204.50',
MASTER_USER='test',
MASTER_PASSWORD='Admin@123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=449;
mysql> grant replication slave on *.* to test@'192.168.204.%' identified by 'Admin@123'; //检查以下有没有test用户,没有的话建立一个用户
mysql> start slave; //开启线程,开启主从复制
mysql> show slave status\G; //查看状态
mysql> show master logs; //查看从节点的复制位置
从节点:
点击查看代码
//启用二进制日志
[root@node7 ~]# systemctl stop firewalld
[root@node7 ~]# setenforce 0
[root@node7 ~]# vim /etc/my.cnf
server-id=70
log-bin=/data/mysql/mysql-bin
[root@node7 ~]# mkdir -p /data/mysql
[root@node7 ~]# chown -R mysql.mysql /data/
[root@node7 ~]# systemctl restart mysqld
[root@node7 ~]# mysql -uroot -pabc123
CHANGE MASTER TO
MASTER_HOST='192.168.204.60',
MASTER_USER='test',
MASTER_PASSWORD='Admin@123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=449;
mysql> start slave; //开启线程,开启主从复制
mysql> show slave status\G; //查看状态
四、半同步复制
- 异步复制:主服务器只管发,不管从服务器是否同步成功
- 同步复制:主服务器需要等待所有从服务器完成同步
- 半同步复制:主服务器只要有一台从服务器同步成功即可
实例
- 7-1 主服务器 192.168.204.50
- 7-2 从服务器1 192.168.204.60
- 7-3 从服务器2 192.168.204.70
主服务器:
点击查看代码
[root@node5 ~]# systemctl stop firewalld
[root@node5 ~]# setenforce 0
[root@node5 ~]# vim /etc/my.cnf
server_id=50
log-bin=/data/mysql-bin
[root@node5 ~]# mkdir /data
[root@node5 ~]# chown -R mysql.mysql /data/
[root@node5 ~]# systemctl restart mysqld
[root@node5 ~]# mysql -uroot -pabc123
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; //安装插件
mysql> SET GLOBAL rpl_semi_sync_master_enabled=1; //开启半同步(临时修改变量)
mysql> SET GLOBAL rpl_semi_sync_master_timeout = 3000; //设置3s内无法同步,也将返回成功信息给客户端
mysql> grant replication slave on *.* to test@'192.168.204.%' identified by 'Admin@123'; //建立复制用户
mysql> show master status;
mysql> SHOW GLOBAL VARIABLES LIKE '%semi%'; //查看半同步状态
mysql> show global status like '%semi%'; //查看半同步客户端
从服务器1:
点击查看代码
[root@node6 ~]# systemctl stop firewalld
[root@node6 ~]# setenforce 0
[root@node6 ~]# vim /etc/my.cnf
server_id=60
[root@node6 ~]# systemctl restart mysqld
[root@node6 ~]# mysql -uroot -pabc123
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> SET GLOBAL rpl_semi_sync_slave_enabled=1;
CHANGE MASTER TO
MASTER_HOST='192.168.204.50',
MASTER_USER='test',
MASTER_PASSWORD='Admin@123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;
mysql> start slave;
mysql> show slave status\G;
从服务器2:
点击查看代码
[root@node7 ~]# systemctl stop firewalld
[root@node7 ~]# setenforce 0
[root@node7 ~]# vim /etc/my.cnf
server_id=70
[root@node7 ~]# systemctl restart mysqld
[root@node7 ~]# mysql -uroot -pabc123
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> SET GLOBAL rpl_semi_sync_slave_enabled=1;
CHANGE MASTER TO
MASTER_HOST='192.168.204.50',
MASTER_USER='test',
MASTER_PASSWORD='Admin@123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;
mysql> start slave;
mysql> show slave status\G;
补充
- 如何确定从服务器落后于主服务器
点击查看代码
mysql> show slave status\G;
............................
Seconds_Behind_Master: 0 //落后主服务器多少
............................
- 如何确定主从节点数据是否一致
点击查看代码
percona-toolkit 需要借助工具
- 数据库不一致如何修复
点击查看代码
删除从数据库,重新复制