一主多从+Binlog Server,主库故障无法访问,如何在从库中选举一个新主库
一、基本环境
VMware10.0+CentOS6.9+MySQL5.7.19
ROLE | HOSTNAME | BASEDIR | DATADIR | IP | PORT |
M | ZST1 | /usr/local/mysql | /data/mysql/mysql3306/data | 192.168.85.132 | 3306 |
S1 | ZST2 | /usr/local/mysql | /data/mysql/mysql3306/data | 192.168.85.133 | 3306 |
S2 | ZST1 | /usr/local/mysql | /data/mysql/mysql3307/data | 192.168.85.132 | 3307 |
基于Row+Gtid搭建的一主两从异步复制结构:M->{S1、S2}。Binlog Server运行于192.168.85.133,日志保存目录/data/binlogserver
二、故障模拟
M不断地写入数据,分别暂停S1、S2的IO_Thread,然后shutdown主库,再启动S1、S2的IO_Thread。在完成上述操作后,我们来查看主、从数据情况
1、M不断地写入数据,分别暂停S1、S2的IO_Thread,然后shutdown主库
# 主库M在shutdown前的binlog及测试表中的数据
mydba@192.168.85.132,3306 [replcrash]> show master status;
+------------------+----------+--------------+------------------+--------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+--------------------------------------------+
| mysql-bin.000064 | 1679 | | | 8ab82362-9c37-11e7-a858-000c29c1025c:1-493 |
+------------------+----------+--------------+------------------+--------------------------------------------+
1 row in set (0.00 sec) mydba@192.168.85.132,3306 [replcrash]> select * from repl;
+----+----------+----------+
| id | name1 | name2 |
+----+----------+----------+
| 1 | 16:12:59 | 16:12:59 |
| 2 | 16:13:00 | 16:13:00 |
| 3 | 16:13:03 | 16:13:03 |
| 4 | 16:13:04 | 16:13:04 |
| 5 | 16:13:06 | 16:13:06 |
| 6 | 16:13:09 | 16:13:09 |
| 7 | 16:13:10 | 16:13:10 |
| 8 | 16:55:04 | 16:55:04 |
| 9 | 17:01:05 | 17:01:05 |
| 10 | 17:01:15 | 17:01:15 |
| 11 | 17:02:15 | 17:02:15 |
| 12 | 17:02:17 | 17:02:17 |
| 13 | 17:04:01 | 17:04:01 |
+----+----------+----------+
13 rows in set (0.00 sec) mydba@192.168.85.132,3306 [replcrash]> shutdown;
Query OK, 0 rows affected (0.01 sec) 2、再次启动S1、S2的IO_Thread
# 从库S1复制状态
mydba@192.168.85.133,3306 [replcrash]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 192.168.85.132
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000064
Read_Master_Log_Pos: 788
Relay_Master_Log_File: mysql-bin.000064
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Exec_Master_Log_Pos: 788
Until_Condition: None
Last_IO_Errno: 2003
Last_IO_Error: error connecting to master 'repl@192.168.85.132:3306' - retry-time: 60 retries: 1
Master_Server_Id: 1323306
Master_UUID: 8ab82362-9c37-11e7-a858-000c29c1025c
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Retrieved_Gtid_Set: 8ab82362-9c37-11e7-a858-000c29c1025c:166-490
Executed_Gtid_Set: 8ab82362-9c37-11e7-a858-000c29c1025c:1-490
Auto_Position: 1 # 从库S2复制状态
mydba@192.168.85.132,3307 [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 192.168.85.132
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000064
Read_Master_Log_Pos: 1382
Relay_Master_Log_File: mysql-bin.000064
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Exec_Master_Log_Pos: 1382
Until_Condition: None
Last_IO_Errno: 2003
Last_IO_Error: error connecting to master 'repl@192.168.85.132:3306' - retry-time: 60 retries: 1
Master_Server_Id: 1323306
Master_UUID: 8ab82362-9c37-11e7-a858-000c29c1025c
Master_Info_File: /data/mysql/mysql3307/data/master.info
SQL_Delay: 60
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Retrieved_Gtid_Set: 8ab82362-9c37-11e7-a858-000c29c1025c:484-492
Executed_Gtid_Set: 8ab82362-9c37-11e7-a858-000c29c1025c:1-492,90b30799-9215-11e7-8645-000c29c1025c:1-6
Auto_Position: 1 # 从库S1的binlog及测试表中的数据
mydba@192.168.85.133,3306 [replcrash]> show master status;
+------------------+----------+--------------+------------------+--------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+--------------------------------------------+
| mysql-bin.000001 | 5462247 | | | 8ab82362-9c37-11e7-a858-000c29c1025c:1-490 |
+------------------+----------+--------------+------------------+--------------------------------------------+
1 row in set (0.00 sec) mydba@192.168.85.133,3306 [replcrash]> select * from repl;
+----+----------+----------+
| id | name1 | name2 |
+----+----------+----------+
| 1 | 16:12:59 | 16:12:59 |
| 2 | 16:13:00 | 16:13:00 |
| 3 | 16:13:03 | 16:13:03 |
| 4 | 16:13:04 | 16:13:04 |
| 5 | 16:13:06 | 16:13:06 |
| 6 | 16:13:09 | 16:13:09 |
| 7 | 16:13:10 | 16:13:10 |
| 8 | 16:55:04 | 16:55:04 |
| 9 | 17:01:05 | 17:01:05 |
| 10 | 17:01:15 | 17:01:15 |
+----+----------+----------+
10 rows in set (0.00 sec) # 从库S2的binlog及测试表中的数据
mydba@192.168.85.132,3307 [replcrash]> show master status;
+------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+
| mysql-bin.000008 | 2703 | | | 8ab82362-9c37-11e7-a858-000c29c1025c:1-492,
90b30799-9215-11e7-8645-000c29c1025c:1-6 |
+------------------+----------+--------------+------------------+--------------------------------------------------------------------------------------+
1 row in set (0.01 sec) mydba@192.168.85.132,3307 [replcrash]> select * from repl;
+----+----------+----------+
| id | name1 | name2 |
+----+----------+----------+
| 1 | 16:12:59 | 16:12:59 |
| 2 | 16:13:00 | 16:13:00 |
| 3 | 16:13:03 | 16:13:03 |
| 4 | 16:13:04 | 16:13:04 |
| 5 | 16:13:06 | 16:13:06 |
| 6 | 16:13:09 | 16:13:09 |
| 7 | 16:13:10 | 16:13:10 |
| 8 | 16:55:04 | 16:55:04 |
| 9 | 17:01:05 | 17:01:05 |
| 10 | 17:01:15 | 17:01:15 |
| 11 | 17:02:15 | 17:02:15 |
| 12 | 17:02:17 | 17:02:17 |
+----+----------+----------+
12 rows in set (0.00 sec)
汇总执行状态
ROLE | File/Position | Executed_Gtid_Set | |
Master_Log_File/Read_Master_Log_Pos | Relay_Master_Log_File/Exec_Master_Log_Pos | ||
S1 | mysql-bin.000064/788 | mysql-bin.000064/788 | 8ab82362-9c37-11e7-a858-000c29c1025c:1-490 |
S2 | mysql-bin.000064/1382 | mysql-bin.000064/1382 | 8ab82362-9c37-11e7-a858-000c29c1025c:1-492 |
M | mysql-bin.000064/1679 | 8ab82362-9c37-11e7-a858-000c29c1025c:1-493 |
从复制状态及测试表中的数据可知S1滞后于S2,S2滞后于M。实际环境中M可能已经完全不可访问,我们只能通过对比S2和Binlog Server的binlog来确定是否还有未传递到从库的日志
三、复制结构调整
3.1、多从选主原则
1、各从库的复制是否执行完成(SQL_Thread已执行完有效的relay-log)
2、复制完成的前提下,各从库读取到主库的位置(Master_Log_File、Read_Master_Log_Pos),选择一个同步最靠前的
如果从库个数很多,肯定不适合肉眼对比各从库的Master_Log_File、Read_Master_Log_Pos,使用冒泡算法,得到最大的{Sx.Master_Log_File , Sx.Read_Master_Log_Pos}
如果所有从库读取到主库的同一位置,那么提前在配置表中设置谁优先成为主库(根据实际需求权值衡量)
3、将其他从库change到新主库
3.2、结构调整
本例中只有S1、S2两个从库,直接对比复制状态。各从库的SQL_Thread已执行完有效的relay-log;S1执行到mysql-bin.000064/788,S2执行到mysql-bin.000064/1382,因此S2作为我们的目标新主库。
S1应该change到S2的哪个位置呢?之前的复制结构中S1、S2并没有直接的关系,M上的同一个Event应用到各从库的位置并不一定相同。
3.2.1、传统复制
前提:S1、S2上开启了log_slave_updates(建议所有的从库都开启),通过解析S1上执行完的binlog last event(已commit)到S2上找对应的event
# 解析S1的binlog
[root@ZST2 ~]# cd /data/mysql/mysql3306/logs
[root@ZST2 logs]# ll
total
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.index
[root@ZST2 logs]# mysqlbinlog -v --base64-output=decode-rows mysql-bin.
...
COMMIT/*!*/;
# at
# :: server id end_log_pos CRC32 0x7645e302 GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '8ab82362-9c37-11e7-a858-000c29c1025c:490'/*!*/;
# at
# :: server id end_log_pos CRC32 0x39d04b3a Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0xb3a9a2bf Table_map: `replcrash`.`repl` mapped to number
# at
# :: server id end_log_pos CRC32 0x2648ea90 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl`
### SET
### @=
### @='17:01:15'
### @='17:01:15'
# at
# :: server id end_log_pos CRC32 0x524c761a Xid =
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
[root@ZST2 logs]#
重点关注最后一个commit事务中的server_id(master传过来)、TIMESTAMP(master传过来)
server_id+TIMESTAMP可以定位原始实例上的具体binlog,然后根据TIMESTAMP的上下文去确定pos
# S1上最后一个事务的时间戳
mysql> select from_unixtime(),unix_timestamp(now());
+---------------------------+-----------------------+
| from_unixtime() | unix_timestamp(now()) |
+---------------------------+-----------------------+
| -- :: | |
+---------------------------+-----------------------+ # 解析S2的binlog,根据前面的时间2017-- ::15存在于mysql-bin.000008文件中
# 上面的那个时间,准确来说只适合在Master上使用,例如我们将从库的SQL_Thread暂停几小时,再启用,它在binlog中的记录还是1508144475,但是我们不能确保它就写到了mysql-bin.000008文件,因此线上环境我们可能要多解析几个binlog去查找TIMESTAMP
[root@ZST1 ~]# cd /data/mysql/mysql3307/logs
[root@ZST1 logs]# ll
total
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.
-rw-r-----. mysql mysql Oct : mysql-bin.index
[root@ZST1 logs]# mysqlbinlog -v --base64-output=decode-rows mysql-bin.
...
COMMIT/*!*/;
# at
# :: server id end_log_pos CRC32 0xdae59343 GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '8ab82362-9c37-11e7-a858-000c29c1025c:490'/*!*/;
# at
# :: server id end_log_pos CRC32 0x021a70da Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x117d1f49 Table_map: `replcrash`.`repl` mapped to number
# at
# :: server id end_log_pos CRC32 0xe5a9bd74 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl`
### SET
### @=
### @='17:01:15'
### @='17:01:15'
# at
# :: server id end_log_pos CRC32 0x7ee611d4 Xid =
COMMIT/*!*/;
# at
# :: server id end_log_pos CRC32 0x1b5a4b41 GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '8ab82362-9c37-11e7-a858-000c29c1025c:491'/*!*/;
# at
# :: server id end_log_pos CRC32 0x85053196 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
...
很幸运,我们在S2的mysql-bin.000008文件找到对应的TIMESTAMP
我们只需在S2找到对应事务,然后取commit后的第一个at,作为change的起始位置
#传统复制
S1:
mysql> change master to
master_host='192.168.85.132',
master_port=3307,
master_user='repl',
master_password='repl',
master_log_file='mysql-bin.000008',
master_log_pos=2153,
master_auto_position=0;
3.2.2、GTID
直接执行,S1:stop slave;change master to S2...,master_auto_position=1;start slave;
3.3、应用Binlog Server中的binlog
前面复制已搭建S2->S1,只需对S2应用Binlog Server中的binlog,S2之前的复制状态Master_Log_File/Read_Master_Log_Pos:mysql-bin.000064/1382
# 解析binlogserver
[root@ZST2 ~]# cd /data/binlogserver
[root@ZST2 binlogserver]# mysqlbinlog -v --base64-output=decode-rows mysql-bin. --start-position=
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at
# :: server id end_log_pos CRC32 0xfd581af7 GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '8ab82362-9c37-11e7-a858-000c29c1025c:493'/*!*/;
# at
# :: server id end_log_pos CRC32 0xb9b3df4a Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
SET @@session.pseudo_thread_id=/*!*/;
SET @@session.foreign_key_checks=, @@session.sql_auto_is_null=, @@session.unique_checks=, @@session.autocommit=/*!*/;
SET @@session.sql_mode=/*!*/;
SET @@session.auto_increment_increment=, @@session.auto_increment_offset=/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=,@@session.collation_connection=,@@session.collation_server=/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
SET @@session.lc_time_names=/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0xa14412d2 Table_map: `replcrash`.`repl` mapped to number
# at
# :: server id end_log_pos CRC32 0xad9ead7e Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl`
### SET
### @=
### @='17:04:01'
### @='17:04:01'
# at
# :: server id end_log_pos CRC32 0xd2670a1c Xid =
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
[root@ZST2 binlogserver]#
Binlog Server的binlog还有未传递到从库的日志,将后续日志恢复到S2中
# 导入binlogserver到S2
[root@ZST2 ~]# mysqlbinlog /data/binlogserver/mysql-bin. --start-position= |mysql -h192.168.85. -P3307 -umydba -p
导入后S2、S1数据就和M shutdown前保持一致了,当然我们还可以把M开启,然后就变成M->S2->S1这样的级联复制~
3.4、所有从库同步位置一致
这里的一致实际包括:当前S1、S2已处于一致或者S1、S2在应用Binlog Server的binlog后处于一致
以S1作为新主库,传统模式
S1:show master status;
S2:stop salve;change master to S1...,master_log_file=S1.log_file,master_log_pos=S1.log_pos,master_auto_position=0;start slave;
GTID:直接执行,S2:stop slave;change master to S1...,master_auto_position=1;start slave;
四、总结
问题的难点是找准从库之间的"关联",如果复制是基于Row+Gtid,Change根本就不是事。至于Binlog Server,只是用于将未传递到从库的日志恢复到从库中。
一主多从+Binlog Server,主库故障无法访问,如何在从库中选举一个新主库的更多相关文章
- MySQL BinLog Server 搭建实战
一.MySQL Binlog server 介绍 MySQL Binlog Server: 它使用 mysqlbinlog 命令以 daemon 进程的方式模拟一个 slave 的 IO 线程与主库连 ...
- MongoDB副本集(一主两从)读写分离、故障转移功能环境部署记录
Mongodb是一种非关系数据库(NoSQL),非关系型数据库的产生就是为了解决大数据量.高扩展性.高性能.灵活数据模型.高可用性.MongoDB官方已经不建议使用主从模式了,替代方案是采用副本集的模 ...
- MySQL binlog server
从5.6版本开始,可以利用 mysqlbinlog命令把远程机器的日志备份到本地目录,这样就更加方便快捷的实现一个binlog server. 环境介绍:192.168.56.100是备份服务器,19 ...
- MHA 的 Binlog Server & VIP 漂移
目录 Binlog Server 在 MHA 配置文件中配置 Binlog Server 创建 Binlog 存放目录 实时传输主库 Binlog 命令 重启 MHA 检验 MHA Manager 服 ...
- 在Windows Server 2012 R2中搭建SQL Server 2012故障转移集群
需要说明的是我们搭建的SQL Server故障转移集群(SQL Server Failover Cluster)是可用性集群,而不是负载均衡集群,其目的是为了保证服务的连续性和可用性,而不是为了提高服 ...
- AlwaysOn可用性组功能测试(二)--SQL Server群集故障转移对AlwaysOn可用性组的影响
三. SQL Server群集故障转移对AlwaysOn可用性组的影响 1. 主副本在SQL Server群集CLUSTEST03/CLUSTEST03上 1.1将节点转移Server02.以下是故障 ...
- my08_mysqldump+binlog server备份
备份策略描述 ******************************************* mysqldump备份适用于小数据量的备份,比如100G以下的数据量,就可以使用逻辑备份 举例两个 ...
- 利用binlog server及Xtrabackup备份集来恢复误删表(drop)
Preface Today I'm gonna test how to rescue a dropped table from binlog server based on a ful ...
- 在主方法中定义一个大小为10*10的二维字符型数组,数组名为y,正反对角线上存的是‘*’,其余 位置存的是‘#’;输出这个数组中的所有元素。
//在主方法中定义一个大小为10*10的二维字符型数组,数组名为y,正反对角线上存的是‘*’,其余 位置存的是‘#’:输出这个数组中的所有元素. char [][]y=new char [10][10 ...
随机推荐
- mysql学习(3)10045错误,连接不上数据库
mysql8.0默认加密的方式是caching_sha2_password认证方式,当使用navicat 或者程序连接是连接不上, 好吧,那我们修改配置并重启服务可以解决此问题 找到mysql的配置文 ...
- Linux内核分析作业四
扒开系统调用的三层皮 一.用户态.内核态和中断 一般现代CPU都有几种不同的指令级别 在高级别执行级别下,代码可以执行特权指令,访问任意的物理地址,称之为内核态 在相应的低指令执行级别下,代码的掌控范 ...
- Linux内核设计与实现 第十八章
1. 内核调试的难点 重现bug困难 调试风险比较大 定位bug的初始版本困难 2. 内核调试的工具和方法 2.1 输出 LOG 输出LOG不光是内核调试, 即使是在用户态程序的调试中, 也是经常使用 ...
- Beta版本讨论
目录 组员:胡绪佩 组员:何家伟 组员:黄鸿杰 组员: 翟丹丹 组员:周政演 组员:胡青元 组员:庄卉 组员:刘恺琳 组员:何宇恒 组员:刘一好 组员:葛家灿 组员:胡绪佩 总结 通过这次的Beta版 ...
- C#(近期目标)
最近很多同学为了实习都在学Java,但是我个人更偏好C#,首先因为自己基础不是太好,而C#又更容易入门,拥有比较完善的开发环境,是微软开发出来的语言.它吸收了C++和Java两门语言的所有有点,因为它 ...
- join()方法跟踪
#join方法跟踪java.lang.Thread.join() 进入线程的join方法,实际上线程thread是实现的 runnable接口 class Thread implements Runn ...
- python自动化之调试
#####调试 #####查看日志与断言 ''' 抛出异常使用raise语句.在代码中,raise语句包含以下部分: (1)raise关键字; (2)对Exception函数的调用; (3)传递给Ex ...
- JDK8新特性,给接口添加一个默认实现
在JDK8中,允许给接口本身添加一个默认的实现.用“default”进行修饰.如下实例 package interfacetest; public interface TestInterface { ...
- 【刷题】BZOJ 1124 [POI2008]枪战Maf
Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. ...
- 简易处理图片在div中居中铺满
原文地址:http://www.cnblogs.com/JimmyBright/p/7681089.html 经常需要在一个长宽固定的div里存放一个图片,这个图片长宽未知,所以需要图片自适应div显 ...