mysql_9 主从复制
标签(空格分隔): mysql
介绍
两台或以上数据库实例,通过二进制日志,实现数据的同步关系
前提(搭建过程)
- 时间同步
- 2台实例,server_id 不同,不同的角色划分(主库、从库)、网络畅通
- 主库开binlog、专门开启一个复制用户
- 开启专用复制线程(默认开启)
- 从库"补课" 数据、 主库的连接信息、确认复制的起点
- 从库 开启专用的复制线程
搭建
实例准备 多实例
systemctl start mysql3306
systemctl start mysql3307
systemctl start mysql3308
检查关键信息
检查server_id
mysql -S /tmp/mysql3306.sock -e "select @@server_id"
mysql -S /tmp/mysql3307.sock -e "select @@server_id"
mysql -S /tmp/mysql3308.sock -e "select @@server_id"
检查binlog
mysql -S /tmp/mysql3306.sock -e "select @@log_bin"
主库建立复制用户
mysql -S /tmp/mysql3306.sock -e "grant replication slave on . to repl@'10.0.%' identified by '123' "
mysql -S /tmp/mysql3306.sock -e "select user,host from mysql.user"
主库备份恢复到从库
备份
mysqldump -S /tmp/mysql3306.sock -A --master-data=2 --single-transaction > /tmp/full.sql
恢复到从库中
mysql -S /tmp/mysql3307.sock < /tmp/all.sql
mysql -S /tmp/mysql3308.sock < /tmp/all.sql
告知从库信息
CHANGE MASTER TO
MASTER_HOST='master2.mycompany.com', #地址
MASTER_USER='replication', # 复制用户
MASTER_PASSWORD='bigs3cret', #密码
MASTER_PORT=3306, # 端口号
MASTER_LOG_FILE='master2-bin.001', #从哪里开始复制
MASTER_LOG_POS=4,
MASTER_CONNECT_RETRY=30;
主库的all sql 中有从库该从哪里复制
grep "-- CHANGE MASTER TO" /tmp/all.sql
开启专用的复制线程
mysql -S /tmp/mysql3307.sock
start slave
mysql -S /tmp/mysql3308.sock
start slave
验证主从的状态
show slave status
两个yes 表示主从成功
如果失败 去除主从
stop slave;
reset slave all;
主从复制的原理
主从复制涉及到的资源
文件
主库:binlog文件
从库:
relay-log文件: 存储接受主库的binlog
db01-relay-bin.000001
db01-relay-bin.000002
手动定义 show variables like '%relay%'
relay_log_basename= 数据目录/db01-relay-bin
master.info : 连接主库的信息,已经接收到的binlog位置点信息
默认存储在从库的数据路径下
master_info_repository= FILE/TABLE #建议用table
relay.info : 记录从库会放到的relay-log的位置点
默认在从库的数据路径下
relay-log.info
手动定义 show variables like '%relay%'
relay_log_info_repository = FILE/TABLE
线程
主库:
Binlog_dump_Thread:
作用:用于接受从库的请求,并且返回binlog日志给从库。
show PROCESSLIST 可以看见
从库:
IO 线程:
请求binlog日志,接受日志
SQL 线程:
回放日志
主从复制原理
-
change master to
提供了 ip 端口 用户 密码 binlog位置点 会被存储到master.info 文件,执行 start slave 启动sql线程和io线程 -
连接主库
-
master 分配一个Binlog_dump_Thread 专门用于和从库io线程进行通信
-
从库的io线程:请求新的日志
-
master binlog_dump_Thread 接受请求 截取日志 返回给 从库的io线程
-
从库io线程接收到binlog,日志放在tcp/ip,此时网络层面返回ack给主库,主库工作完成
-
从库io线程将binlog最终写入到relaylog中,并更新主库master.info文件 io线程工作结束
-
从库 sql线程 读取relay.info 获取上次执行到的位置点
-
从库 sql线程 向后执行新的relay-log
-
relay-log 参数 relay_log_purge=on 定期删除应用过的relay-log
-
master binlog_dump_Thread 线程实时监控主库的binlog变化,如果有变化,发信号给从库
主从监控
主
show processlist
查看dump线程的情况
show slave hosts
备
show slave status G
主库信息,来自于master.info
从库的relay-log的执行情况,来自于R.info 一般用来判断主从延时
从库线程状态,具体报错信息
过滤复制相关信息
延迟从库的配置信息
gtid相关复制信息
主从故障分析及处理
监控方法
show slave status G
Slave_IO_State: Waiting for master to send event
Master_Host: 130.17.180.71
Master_User: cpc
Master_Port: 3306
Connect_Retry: 10
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 116932874
Relay_Log_File: WINDOWS-V2DDMKC-relay-bin.000004
Relay_Log_Pos: 336557
Relay_Master_Log_File: mysql-bin.000001
io线程
Slave_IO_Running: Yes #正常状态
Slave_SQL_Running: Yes
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Slave_IO_Running io线程
正常 yes
非正常 no connection
连接主库:
1.网络不正常、防火墙、端口
2.用户 、 密码 不对
relication slave 权限的
3.主库的连接数量上限
4.版本不统一 5.7 native 8.0 sha2
故障模拟:
主从中的线程管理:
start slave # 启动所有线程
stop slave # 关闭所有线程
start slave sql_thread # 单独启动SQL线程
start slave io_thread # 单独启动io线程
stop slave sql_thread # 单独关闭SQL线程
stop slave io_thread # 单独关闭io线程
解除从库身份:
reset slave all
show slave status
请求日志,接受日志
主库二进制日志不完整、损坏、不连续
从库请求的起点问题
主从的server_id(server_uuid)相同
relaylog问题
故障模拟:
主库: reset master;
从库就会报错: last_io_error
正确的做法:
找个不繁忙的时间,
主库:
reset master;
show master status;
备库:
stop slave ;
reset slave all;
CHANGE MASTER TO
MASTER_HOST='master2.mycompany.com', #地址
MASTER_USER='replication', # 复制用户
MASTER_PASSWORD='bigs3cret', #密码
MASTER_PORT=3306, # 端口号
MASTER_LOG_FILE='master2-bin.001', #从哪里开始复制
MASTER_LOG_POS=4,
MASTER_CONNECT_RETRY=30;
等待从库重放完所有主库日志
主库 reset master
从库重新同步主库日志
sql线程故障
主要做什么工作?
回放relay-log中的日志。可以理解为执行relay-log SQL
SQL线程故障本质
为什么SQL线程执行不了SQL语句
原理整理
创建的对象已经存在了。
需要操作的对象不存在
约束冲突。
SQL_MODE,参数、版本
举个例子:
搞错了 在备库上 create databases t1;
在 主库上再 create databases t1;
主库上再建表 create table t2(id int);
发现主从断了 show slave status
解决:
方法1:
从库删掉新建的库,重新start slave;
方法2: 跳过
stop slave;
set global sql slave_skip_counter=1;
start slave
/etc/my.cnf
slave-skip-errors = 1032,1062,1007
1007:对象已存在
1032:无法执行DML
1062:主键冲突,或约束冲突
pt 第三方工具
终极办法:
重新搭建主从,备份恢复+重新构建
主库出了问题怎么办?
物理
1.看主库是否能ssh连接
2.检查一下binlog是否完整
3.手动追加日志到最新位置
4.从库代替主库工作
逻辑 drop
只能通过备份去恢复
双主情况下,一个宕机了,过了很久,另一个也宕机了 如何恢复
只能备份+binlog恢复
从库怎么称当主库
1.修复最新状态
2.清空从库身份
3.清空binlog日志信息
避免从库进行操作
从库只读 #打开这个选项 所有的普通用户 全部不能写入
select @@read_only
select @@super_read_only
中间件
隔离从库的写操作
主从延迟方面
主库发生了操作,从库很久才跟上来
show slave status;
Second_Behind_Master:0 #从库落后于主库的时间
这个指标只能得出:又或者没有延迟的情况,等于0,不代表没有延迟。
真正评估主从复制延迟的更加精确的指标是:
延迟了多少日志量
主库执行的日志量,从库执行的日志的对比
如何查看:
主库:binlog位置点
从库:relay执行的位置点
如何计算延迟的日志量
主库:
show master status;
备库:
show slave status;
cat 从库目录下的/relay-log.info
position 号 就是字节量 两者相减就是差的字节量
为什么会主从延迟
可以一主三从 从在接2从
主库:
外部: 网络、硬件配置、主库业务繁忙、从库太多
主库业务繁忙:
1.拆分业务(分布式): 组件分离、垂直、水平
2.大事务的拆分 比如1000w业务,拆分为20次执行。
内部:
二进制日志更新。 sync_binlog=1
5.7之前 没有开启gtid dump线程 是串行的 一个一个给的容易出现性能问题(主库的事务是并行的,日志量大)
5.6 + 开gtid(有了gtid 事务全局唯一了 所以不在乎并发时顺序) dump线程 改为并行的
5.7 + 版本 无需手动开启,系统会自动生成匿名的gtid信息
还是需要尽可能减少大事务,以及锁影响
从库
外部:
网络、硬件配置、参数设定。
内部:
io线程
写relay-log --> io性能
sql线程
回放sql
默认在非GTID下是串行的 一个一个执行的容易出现性能问题(主库的事务、传输是并行的,日志量大)
还是需要开启gtid 才可以使他变成并行的,进行多线程回放sql
5.6+ GTID: 基于库级别的SQL线程并发。
5.7+ 版本 Logic_clock 逻辑时钟。保证了在同库级别下的事务顺序问题。
所以可以理解为基于事务级别的并发回放。MTS
即使有以上的自带的优化机制。还是需要尽可能减少大事务,以及锁影响