复制中断处理
- 1677错误
- 第一种将主库改成statement格式
- 第二种在从库设置slave_type_conversions
- 从库出现写入数据,把自增ID占用:1062错误
- 将从库该条数据删除
- 能确定数据一致也可以跳过该错误
- 从库上出现少数据,delete,update操作时,找不到相应的记录,出现1032错误
- delete可以跳过错误
- update只能补数据,在master的binlog中解析出哪个位置出错了,将这条数据插入,主要是主键个非空列,开启复制sql_thread,查看status
- 从库gtid值大于主库gtid值
- 有可能主库被reset了
- 新回复的从库将auto.cnf也恢复了,binlog还删除了,也有可能会出现这种场景
复制延迟排查
- 搞明白当前的数据库在干什么
- show processlist;
- show slave status\G定位到sql_thread执行到位置
- io_tread同步到主库的binlog位置:Master_Log_File;Read_Master_Log_Pos
- sql_thread重放到对应主库的binlog位置:Relay_Master_Log_File;Exec_Master_Log_Pos
- Seconds_Behind_Master:这个值是怎么计算的?
- io_thread.event.timestamp-sql_thread.event.timestamp 单位秒
- 查看当前的SQL状态
- 机器负载很高
- 索引不合理!!!
- Statement索引不合理,造成同步延迟
- mysql>pager more
- mysql>show processlist;
- 可以直接用select * from information_schema.processlist where 1=1 order by TIME desc limit 10;
- USER不是sys的,感觉没什么问题的,时间太长快死掉的连接都可以杀掉
- 在从库上能看到执行的SQL都有问题的!!!
- 机器负载很高
- 利用perf top 查看MySQL的调度情况
- perf top -p `pidof mysqld`
- 利用Google
- 利用源码定位出问题的地方
- 延迟现象一
- Seconds_Behind_Master一直在增大,但Exec_master_log_pos就是卡着不动
- 解析sql_thread执行的binlog
- mysqlbinlog -v --base64-output=decode=rows --start-position=xxx mysql-bin.xxxx
- 去主库上面找
- Relay_Master_Log_File,Exec_Master_Log_Pos这两个参数定位
- 在从库上面找
- Relay_Log_File,Relay_Log_Pos这两个参数
- 大事务卡的两个原因
- 真的是大事务等待,一次更新50W行以上,坐等
- 更新这个表可能没有索引
- stop slave不了可以mysqladmin -S/mysql3306.sock shutdown
- 关闭都关闭不了,只能kill -9,从库这么干,主库还是不要这么干
- 重启mysql,重建索引,之后start slave
如何避免延迟
- 从库的配置适当高一点
- 使用MySQL5.7开启并行复制
- 表结构设计时,一定要有主键,而且主键要短小
- 使用新型硬件:PCI-E&SSD类设备
- 程序端适当的Cache,减少数据库的压力
复制结构调整Tips
- 场景
-
将下图中的机器加内存,并修改buffer pool,业务暂停时间小于1分钟
- 凌晨读写压力不大的情况下,可以考虑将读写都放在M上
- 将s1->stop slave;
- s1,s11,s12,s13全部shutdown,加内存,修改buffer pool
- 在s1和M上装keepalived,vip先指到M上,之后停掉M,查看vip是否指到s1上
- 如果是gtid复制,M启动后直接change master指到s1就可以
- 在将s11,s13,M都指向s12就ok了
- 如果是传统复制,要经过一下几步
- 在vip指过去之前在s1上执行show master status;
- sleep 1;
- show master status;结果没变化可以将结果保存到一个文件中
- show master status>/tmp/1.log
- M启动后change master to指s1就可以
- 将s11,s13,M指向s12有两种办法
- 第一种
- 可以手工制造个错误,使s11,s12,s13,M都停在同一个位置
- 在s12上执行show master status>/tmp/1.log
- 在将s11,s13,M都指向s12就ok了
- 之后再s12上跳过错误或者将错误修复
- 第二种
- 将s11,s12,s13,M全部停掉sql_thread
- 在s1上执行show master status;
- s11,s12,s13,M执行start slave sql_thread until master_log_file='xxx',master_log_pos=xxx;
- 使s11,s12,s13,M机器都停在s1执行的show master status节点上
- 在s12上执行show master status>/tmp/1.log
- 在将s11,s13,M都指向s12就ok了
-
将级联复制改成正常的一级复制
- gtid可以直接change过去
- 传统复制
- 在s1上执行stop slave;
- 在s1上查看show slave status;
- 在s11上的change master语句,host,port指定到M上
- master_log_file='Relay_Master_Log_File' #在s1上执行show slave status查看出来的
- master_log_pos=Exec_Master_Log_Pos #在s1上执行show slave status查看出来的
- s2,s21同上
- 将所有的从库开启复制start slave
- 假设s1机器电源坏了,不能登录,将s11机器挂到M下或者挂到s2下,怎么搞定?
- gtid可以直接change master过去
- 传统复制
- 一种是将s21机器复制一份数据将s11机器还原,挂到s2下
- 另一种是不需要重新备份
- 解析s21机器的mysql-binlog,找到最后一个M库的server_id对应的事务,在这个事务上面找到它对应的timestamp,开启中继日志情况下server_id和timestamp具有传递性
- 解析出timestamp对应的时间,去M机器上面找到对应的mysql-binlog,大概找到这个时间是写入的哪个binlog,可以用ls查看
- 解析这个binlog,在这个binlog中查找上述的timestamp,找到对应的事务,要和从库上的那个事务语句一样才可以,查看一下从库的这个事物执行完没有(commit还是没commit),如果没执行完就要记录这个事物begin之前的log_pos,执行完了就记录下一个事务开始的log_pos
- 将上述的binlog和log_pos写入到从库的change master to上面,开启复制,就可以将机器挂到M下面了