mysql主从复制之异步复制
异步复制(Asynchronous Replication) 是 MySQL 主从复制的 默认模式,也是最基础、最常用的复制模式。其核心特点是 主库写入 binlog 后无需等待从库响应,直接返回成功给客户端,性能最高但存在一定的数据丢失风险。
核心流程
异步复制的流程延续主从复制的 3 线程架构,但主库与从库之间无任何同步等待机制:
- 主库执行用户的
INSERT/UPDATE/DELETE操作,事务提交时将变更写入 binlog。 - 主库完成 binlog 写入后,立即返回成功给客户端,不等待从库同步。
- 从库的 IO 线程 异步请求主库的 binlog,主库的 dump 线程 发送 binlog 事件给从库。
- 从库 IO 线程将接收的 binlog 写入 relay log,SQL 线程异步读取 relay log 并重放,实现数据同步。
核心特点
| 特点 | 说明 |
|---|---|
| 主库不等待从库 | 主库性能不受从库影响,这是异步复制性能最高的关键原因 |
| 数据一致性弱 | 主库宕机时,可能存在部分 binlog 未发送到从库,导致从库数据丢失 |
| 延迟不可控 | 从库同步完全异步,高并发场景下延迟可能持续增大 |
| 架构最简单 | 无需额外配置,默认开启,运维成本低 |
与半同步复制的区别
| 对比维度 | 异步复制 | 半同步复制 |
|---|---|---|
| 主库返回时机 | 写入 binlog 后立即返回 | 至少等待 1 个从库接收并写入 relay log 后返回 |
| 数据安全性 | 低(可能丢失数据) | 高(主库宕机时数据不丢失) |
| 性能 | 最高(无等待开销) | 略低(需等待从库响应) |
| 适用场景 | 对性能要求高、数据丢失风险可接受的场景(如普通业务系统) | 对数据安全性要求高的场景(如金融、核心交易系统) |
异步复制的配置
在 MySQL 5.7 及 8.0 中,异步复制是默认开启的。
前提:主从数据库版本一致
1、主库停服时制作主从
一、主库:192.168.15.101
1、在主库上创建一个用于复制的账号,并赋予replication slave权限,这里必须*.*不能指定库授权,因为replication slave是全局的
mysql> grant replication slave on *.* to 'mangol'@'%' identified by '123';
mysql> flush privileges;
2、修改主库配置文件,开启主库的Binlog,并设置server-id
[mysqld]
# 节点ID,确保唯一
server-id = 1
#开启mysql的binlog日志功能
log-bin = mysql-bin
#控制数据库的binlog刷到磁盘上去 , 0 不控制,性能最好,1每次事物提交都会刷到日志文件中,性能最差,最安全
sync_binlog = 1
#binlog日志格式
binlog_format = row
#binlog过期清理时间
expire_logs_days = 7
#binlog每个日志文件大小
max_binlog_size = 100m
#binlog缓存大小
binlog_cache_size = 4m
#最大binlog缓存大小
max_binlog_cache_size= 512m
#不生成日志文件的数据库,多个忽略数据库可以用逗号拼接,或者 复制黏贴下述配置项,写多行
binlog-ignore-db=mysql
# 表中自增字段每次的偏移量
auto-increment-offset = 1
# 表中自增字段每次的自增量
auto-increment-increment = 1
#跳过从库错误
slave-skip-errors = all
3、重启主库
systemctl restart mysql
4、备份主库,备份时锁表保证备份一致
mysqldump -uroot -pEgon@123 -A -E -R --triggers --master-data=2 --single-transaction > /tmp/all.sql
5、将备份文件发送给从库
scp /tmp/all.sql root@192.168.15.100:/tmp
二、从库:192.168.15.100
1、测试复制账号
mysql -umangol -p123 -h 192.168.15.101
2、导入初始数据
mysql -uroot -pMangol@123 < /tmp/all.sql
3、修改从库配置文件,增加server-id,注意这个值是唯一的,要区别于主库和其他从库
[mysqld]
server-id = 2
relay-log = mysql-relay-bin
replicate-wild-ignore-table=mysql.%
replicate-wild-ignore-table=test.%
replicate-wild-ignore-table=information_schema.%
# 从库也可以开启binlog,但通常关闭
# log-bin=mysql-bin
4、重启从库
systemctl restart mysqld
5、配置复制
先去主库查看一下binlog日志名与位置
show master status;
然后在从库进行配置
[root@slave1 ~]# mysql -uroot -pMangol@123 # 登录然后执行
change master to
master_host='192.168.15.101', -- 库服务器的IP
master_port=3306, -- 主库端口
master_user='mangol', -- 主库用于复制的用户
master_password='123', -- 密码
master_log_file='mysql-bin.000001', -- 主库日志名
master_log_pos=120; -- 主库日志偏移量,即从何处开始复制
从库启动slave线程并检查
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
2、主库运行时制作主从
1.准备纯净的从库环境
主库:192.168.15.101
从库:192.168.15.100
2.修改主库配置文件(略)
3.重启主库(略)
4.主库创建账号(略)
5.模拟主库运行,有数据写入、
for i in `seq 1 1000000`
do
mysql -uroot -p123 -e "insert db1.t1 values($i)";
sleep 1;
done
6.主库全备数据
#不打点备份(no)
mysqldump -uroot -p123 -A -R --triggers > /tmp/all.sql
#打点备份(yes)
mysqldump -uroot -p123 -A -R --triggers --master-data=2 --single-transaction > /tmp/all.sql
7.将热备数据传达从库
scp /tmp/all.sql 192.168.15.100:/tmp
8.修改从库配置文件(略)
9.重启从库(略)
10.在从库导入全备数据(导入打点备份,原因如下)
#导入不打点的数据的话,接下来主从,位置点只能去主库查看 show master status; 而数据在不停地往主库里插入,该命令查看的只是那一刻binlog的记录的位置,基于该位置同步数据会丢失所获得位置点往前一直到全备的数据,以及操作从库过程中新写入主库的数据。
#如果导入的是打点的数据,那么全量备份的起始点可以从备份文件中获得,从库可以以此为同步的基准点,去主库获取全量备份之后的数据
11.查看sql文件中的位置点(如果是打点备份的话)
该位置即主库刚刚做完全量备份时,主库binlog日志所处的位置
[root@egon ~]# head -50 /tmp/all.sql|grep 'MASTER_LOG_POS'
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=129005;
12.从库配置同步
[root@slave1 ~]# mysql -uroot -pEgon@123 # 登录然后执行
change master to
master_host='192.168.15.101',
master_port=3306,
master_user='egon',
master_password='123',
master_log_file='mysql-bin.000001',
master_log_pos=129005;
13.开启SQL线程和IO线程
start slave;
14.查看主从状态
show slave status;
3、主从复制基本故障处理
#清空主从配置
reset slave all;
(1)IO线程问题
1.检测网络:
[root@db01 ~]# ping 172.16.1.51
2.检测端口:
[root@db01 ~]# telnet 172.16.1.51 3307
#阿里云机器有的禁ping
[root@db01 ~]# tcping 172.16.1.51 3306
3.检测账号,密码:
#根据授权命令
grant replication slave on *.* to rep@'172.16.1.5%' identified by '123';
#连接测试
mysql -urep -p123 -h127.0.0.1 -P 3307
4.查看binlog是否存在
show master status;
5.反向解析
#没有跳过反向解析
ERROR 1045 (28000): Access denied for user 'root'@'db01' (using password: YES)
#配置
skip_name_resolve
(2)SQL线程问题
1.主库有的数据,从库没有
主库:a库
从库:没有a库
2.从库有的数据,主库没有
从库:a库
主库:要创建a库
3.主库与从库数据库结构有差别
#处理方法一:
#临时停止同步
mysql> stop slave;
#将同步指针向下移动一个(可重复操作)解决不了根本问题
mysql> set sql_slave_skip_counter=1;
#开启同步
mysql> start slave;
#处理方法二:
#编辑配置文件
[root@db01 ~]# vim /etc/my.cnf
#在[mysqld]标签下添加以下参数
slave-skip-errors=1032,1062,1007
1007:对象已存在
1032:无法执行DML
1062:主键冲突,或约束冲突
#处理方法三:
1.要求,主从复制之前,主库和从库的数据保证一致.
2.在从库上设置 只读:set read-only=1;
(做读写分离时使用,但是做MHA会出现提升为主库时,主库只读,后面会讲专门做读写分离的Atlas)
4、延迟从库
我们说用延时从库可以做备份,主库执行删除的时候,从库还没有删除,可以把表数据拿出来恢复回去
企业中一般会延时3-6小时
延迟从库配置
已经有主从的情况下
1.停止主从
mysql> stop slave;
2.设置延时为180秒
mysql> CHANGE MASTER TO MASTER_DELAY = 180;
3.开启主从
mysql> start slave;
4.查看状态
mysql> show slave status \G
SQL_Delay: 180
5.主库创建数据,会看到从库值变化,创建的库没有创建
SQL_Remaining_Delay: 170
没有主从的情况下
1.修改主库,从库配置文件
server_id
开启binlog
2.保证从库和主库的数据一致
3.执行change语句
change master to
master_host='172.16.1.50',
master_user='rep',
master_password='123',
master_log_file='mysql-bin.000001',
master_log_pos=2752,
master_delay=180;
延时从库停止方法
1.停止主从
mysql> stop slave;
2.设置延时为0
mysql> CHANGE MASTER TO MASTER_DELAY = 0;
3.开启主从
mysql> start slave;
#注:做延时从库只是为了备份,不提供服务
(2) 思考:延时到底是在哪里延时的
思考:IO线程还是SQL线程做的手脚?
#去主库创建一个库
create database ttt;
#查看从库的relaylog看看有没有内容
mysqlbinlog --base64-output=decode-rows -vvv db03-relay-bin.000002
总结:
延时从库是在SQL线程做的手脚,IO线程已经把数据放到relay-log里了.
SQL线程在执行的时候,会延迟你设定的时间长度.
使用延时从库恢复数据
1、场景
总数据量级500G,正常备份去恢复需要1.5-2小时
1)配置延时3600秒
mysql> CHANGE MASTER TO MASTER_DELAY = 3600;
2)主库
drop database db;
3)怎么利用延时从库,恢复数据?
2、环境准备
1.进行每日的全备
mysqldump -uroot -p123 -A -R --triggers --master-data=2 –single-transaction > /backup/full.sql
2.调整延时从库延时时间为60分钟
stop slave;
CHANGE MASTER TO MASTER_DELAY = 3600;
start slave;
3.主库写入新数据
create database yanshi;
use yanshi;
create table yanshi(id int);
insert into yanshi values(1),(2),(3),(4);
create database yanshi2;
use yanshi2;
create table yanshi2(id int);
insert into yanshi2 values(1),(2),(3),(4);
3、模拟删除数据
1.删除一个库,可以是之前的,也可以是刚创建的
#因为刚我们看了,只要我执行了,从库已经写到了relay-log,跟我数据库里的数据关系不大
drop database world;
4、使用延时从库恢复数据
1.停止从库sql线程
stop slave sql_thread;
2.查看状态
show slave status;
3.备份从库数据
mysqldump -uroot -p123 -B world > /backup/congku.sql
4.截取一下relay-log
1)确认起点,查看relay-log.info即可
[root@db02 data]# cat relay-log.info
./db02-relay-bin.000005
283
2)确认终点,找到drop语句之前
[root@db02 data]# mysqlbinlog --base64-output=decode-rows -vvv db02-relay-bin.000005
3)截取数据
[root@db02 data]# mysqlbinlog --start-position=283 --stop-position=1112 db02-relay-bin.000005 > /tmp/yanshi.sql
5.将从库全备的数据与relaylog截取数据拷贝到主库
scp /tmp/yanshi.sql 172.16.1.51:/tmp/
scp /backup/congku.sql 172.16.1.51:/tmp/
6.将数据导入主库
#导入前不要停掉binlog,
mysql < /tmp/yanshi.sql
mysql < /tmp/congku.sql
7.开启从库的sql线程
start slave sql_thread;
#主库那边执行到删除的时候没关系,因为还有创建的部分,他会再次把数据创建回来
总结
MySQL 异步复制的核心特点是什么?
答:主库写入 binlog 后立即返回客户端,不等待从库同步,性能最高但存在数据丢失风险,是 MySQL 默认的复制模式。
异步复制为什么会丢失数据?如何避免?
答:主库写入 binlog 后未发送到从库就宕机,会导致数据丢失。
避免方案:
① 配置 sync_binlog=1(事务提交立即刷盘) 和 innodb_flush_log_at_trx_commit=1(InnoDB 事务日志立即刷盘);
② 升级为半同步复制;
③ 实时备份 binlog 到第三方存储。
异步复制和半同步复制的区别?
答:核心区别在于主库返回时机:异步复制主库写入 binlog 后立即返回;
半同步复制主库需等待至少一个从库接收并写入 relay log 后才返回。半同步数据安全性更高,异步性能更高。

浙公网安备 33010602011771号