Mysql一主多从复制主库崩溃后如何提升从库为主库




mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql 相减


当主库崩溃后,需要提升一台从库来代替它,这个过程不太容易,如果只有一个备库,可以直接使用这台备库,但如果有超过一台备库,就需要做一些额外的工作。

另外还有潜在的丢失复制事件的问题,可能主库已经发生的修改还没有更新到它的任何一台从库上,甚至还有可能一条语句在主库上执行了回滚,但是在从库上没有回滚。这样备库可能超过主库的逻辑复制位置,如果能在某一点恢复主库数据,也许就可以取得丢失的语句并手动执行它们。

在以下步骤中,需要确保在计算中使用 master_log_file 和 read_master_log_pos 的值,以下是对主备拓扑结构中备份的提升过程

1. 确定那台备库数据最新,检查每台备库上的 show slave stauts 的输出,找出 master_log_file 和 read_master_log_pos最新的那个

2. 让所有备库执行完所有从崩溃钱的旧主库那获取的中继日志,如果在未完成前修改备库的主库,它会完全抛弃剩下的日志事件,从而无法获知该备库从那个地方停止

3. 在新主库上执行stop slave

stop slave;

show slave status;

4. 在新主库上执行 rest slave all,使其断开于老主库的连接,并丢弃master.info里面的记录信息(如果连接信息记录在my.cnf里,会无法正确工作),这里我们不建议将该信息放到my.cnf中去

reset slave all;

show slave status;

5. 在新主库上 show master status 记录新主库的二进制日志信息

show master status;

6. 比较每台备库和新主库的master_log_file 和 read_master_log_pos值

7. 将客户端连接上新主库恢复程序应用(保证生产环境可以正常运行)

8. 在每台备库上执行 change master to 语句,使用之前新主库上使用 show master status 获取二进制作为,来指向新的主库。

这些操作都是基于在所有备库上都已经设置了 log_bin 和 log_slave_updates, 如果没有设置这两个选项是无法做到这一点的。

确定期望日志的位置

如果备库和新主库的位置不相同,则需要找出最后一条执行的事件在新主库的二级制日志中的位置,然后在使用change master to,可以通过mysqlbinlog工具来找到备库上最后一条执行的命令,然后在主库上查找相同的查询,进行简单的计算即可得到。

为了便于描述,假设每个日志事件有一个自增的数字id,最新的备库,也就是新主库,在旧主库崩溃时获得了编号为100的事件。假设有两个备库 rep2 和 rep3, rep2已经获取了99编号的事件,rep3获取了99编号的事件,如果把两台备库都指向新主库同一个日志位置,他们将从101开始复制,从而导致数据不一致,但是只要新主库的二级制日志已经通过log_slave_updates打开,就可以在新主库的二进制日志中找到99 和100 号日志,从而能将数据恢复到一致状态。

由于服务器重启,不同配置 ,日志轮转 或者 flush logs 等命令,同一个事件在不同的服务器上可能由不同的偏移量,找到这些事件或者中继日志中解析出每台备库的最后一个事件,并使用该命令解析新主库的二级制日志,并找到相同的查询, mybinlog会打印出该事件的偏移量,我们就可以使用该偏移量在change master to 中使用该偏移量。

更快的方法是吧新主库和停止的别克上的字节偏移量相减,就可以得到期望的查询位置,然后只需要验证一下就可以据此启动新的复制。

测试案例演示

一主两个从,在一个测试机上搭建3个mysql实例 端口分别为 3306 3307 3308

,3307 为主库,3306 和3308 为从库

1. 模拟从库位置不统一情况先将从库3308 停止slave

stop slave;

show slave status;


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_偏移量_02


2. 主库3307 上继续插入数据 和删除数据操作

delete from mytest where id =2;

update mytest set myname ='ceshi' where id =4;

insert into mytest(myname) values('m'),('n'),('o');

show master status ;


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql 相减_03


3. 查询从库3306 和其slave情况

select * from test.mytest;


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql_04


show slave status;


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql 相减_05


4. 模拟主库3307 崩溃,将mysql实例2停机

5. 在从库3306 和3308 中读取slave信息获取最新的从库

show slave status;


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql 相减_06


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_偏移量_07


从上面连个图片中我们确定3306 是最新的日志,我们使用3306为主库

6. 切换3306为主库

show master status;


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql_08


stop slave;

reset slave all;

show slave status;

set global read_only=0;

show variables like '%read_only%'


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_偏移量_09


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_数据_10


这里要确认 log_bin 和 log_slave_updates 之前是开启的,如果之前没有开启则无法保证3308正确同步3306数据,另外我们这里因为提升3306为主库,所以要把 read_only注释掉,允许3306 可写

7. 将客户端指定到3306, 程序等可以正常运行,保证生产恢复

8. 将3308的复制主库指向3306,先确定偏移量

3306 slave日志偏移量为2058 3308slave日志偏移量为 1231 相差为2058-1231=827

新主库3306的master日志偏移量为2022,我们以此向前827步 也就是 2022-827=1195

我们使用 mysqlbinlog去查看3306的主日志mysql3306-bin.000004

mysqlbinlog -vv /data/3306/mysql3306-bin.000004

找到偏移量在1195附近的信息


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_数据_11


有个1191 ,这个正是我们需要的偏移节点,我们把它后面的执行的sql打印出来

mysqlbinlog --start-position="1191" -vv /data/3306/mysql3306-bin.000004

注意这里position 一定要写对,必须是日志中有的,如果你写个1190是无法获取需要的内容的


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql 相减_12


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_数据_13


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql_14


从上面几个截图正好对应我们第2步中在主库3307的操作,所有我们确定使用偏移量1191即可

9. 在3308上设置复制

change master to master_host='10.106.216.182',

master_user='repl',

master_port=3306,

master_password='123456',

master_log_file='mysql3306-bin.000004',

master_log_pos=1191;


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql 相减_15


start slave;

show slave status;


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_数据_16


10. 检查新的主从数据情况

select * from test.mytest


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql_17


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql 相减_18


11. 主库上继续操作 并在从库上校验是否正确同步

update test.mytest
set myname='go'
where id=28;
delete from test.mytest
where id in (10,12,14);


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql 相减_19


mysql主主 Master_Server_Id mysql主从 主挂了怎么办_mysql_20


主从一致,切换完成。