之前写过主从恢复的文章,在那篇文章的主从搭建,若是想要主备切换的时候,需要执行一条 change master 命令
CHANGE MASTER TO
MASTER_HOST=$host_name
MASTER_PORT=$port
MASTER_USER=$user_name
MASTER_PASSWORD=$password
MASTER_LOG_FILE=$master_log_name
MASTER_LOG_POS=$master_log_pos
这条命令有这么 6 个参数:MASTER_HOST、MASTER_PORT、MASTER_USER 和 MASTER_PASSWORD 四个参数,分别代表了主库 A’的 IP、端口、用户名和密码。
最后两个参数 MASTER_LOG_FILE 和 MASTER_LOG_POS 表示,要从主库的 master_log_name 文件的 master_log_pos 这个位置的日志继续同步。而这个位置就是我们所说的同步位点,也就是主库对应的文件名和日志偏移量。
考虑到切换过程中不能丢数据,所以我们找位点的时候,总是要找一个“稍微往前”的,然后再通过判断跳过那些在从库 B 上已经执行过的事务。
一种取同步位点的方法是这样的:等待新主库 A’把中转日志(relay log)全部同步完成;在 A’上执行 show master status 命令,得到当前 A’上最新的 File 和 Position;取原主库 A 故障的时刻 T;用 mysqlbinlog 工具解析 A’的 File,得到 T 时刻的位点。
当然这个值并不精确。为什么呢?
你可以设想有这么一种情况,假设在 T 这个时刻,主库 A 已经执行完成了一个 insert 语句插入了一行数据 R,并且已经将 binlog 传给了 A’和 B,然后在传完的瞬间主库 A 的主机就掉电了。
这时候,从库 B 的同步线程就会报告 Duplicate entry ‘id_of_R’ for key ‘PRIMARY’ 错误,提示出现了主键冲突,然后停止同步。
一种做法是,主动跳过一个事务。跳过命令的写法是:
set global sql_slave_skip_counter=1;
start slave;
另外一种方式是,通过设置 slave_skip_errors 参数,直接设置跳过指定的错误。
在执行主备切换时,有这么两类错误,是经常会遇到的:
1062 错误是插入数据时唯一键冲突;
1032 错误是删除数据时找不到行。
通过 sql_slave_skip_counter 跳过事务和通过 slave_skip_errors 忽略错误的方法,虽然都最终可以建立从库 B 和新主库 A’的主备关系,但这两种操作都很复杂,而且容易出错。所以,MySQL 5.6 版本引入了 GTID,彻底解决了这个困难
GTID是MySQL 5.6版本及以上版本具有的特性之一
GTID是一个基于原始mysql服务器的服务ID与自身一个已经被成功执行的全局事务ID组合而成
GTID = source_id:transaction_id
原始服务器id(source_id):一般指server_id
全局已经执行成功的事务id(transaction_id): 原server每执行成功一个事务,mysql会自动生成一个事务id与其一一对应.
简单理解为GTID=server_id+ 事务ID
每个 MySQL 实例都维护了一个 GTID 集合,用来对应“这个实例执行过的所有事务”。
我们在实例 B 上执行 start slave 命令,取 binlog 的逻辑是这样的:
实例 B 指定主库 A’,基于主备协议建立连接。
实例 B 把 set_b 发给主库 A’。
实例 A’算出 set_a 与 set_b 的差集,也就是所有存在于 set_a,但是不存在于 set_b 的 GTID 的集合,判断 A’本地是否包含了这个差集需要的所有 binlog 事务。a. 如果不包含,表示 A’已经把实例 B 需要的 binlog 给删掉了,直接返回错误;b. 如果确认全部包含,A’从自己的 binlog 文件里面,找出第一个不在 set_b 的事务,发给 B;
之后就从这个事务开始,往后读文件,按顺序取 binlog 发给 B 去执行
主备切换不是不需要找位点了,而是找位点这个工作,在实例 A’内部就已经自动完成了。但由于这个工作是自动的,所以对 HA 系统的开发人员来说,非常友好。
在传统的slave端,binlog是不用开启的,但是在GTID中slave端的binlog是必须开启的,目的是记录执行过的GTID(强制)。
如果一个新的从库接上主库,但是需要的 binlog 已经没了,要怎么做?
如果业务允许主从不一致的情况,那么可以在主库上先执行 show global variables like ‘gtid_purged’,得到主库已经删除的 GTID 集合,假设是 gtid_purged1;然后先在从库上执行 reset master,再执行 set global gtid_purged =‘gtid_purged1’;最后执行 start slave,就会从主库现存的 binlog 开始同步。binlog 缺失的那一部分,数据在从库上就可能会有丢失,造成主从不一致。
如果需要主从数据一致的话,最好还是通过重新搭建从库来做。
如果有其他的从库保留有全量的 binlog 的话,可以把新的从库先接到这个保留了全量 binlog 的从库,追上日志以后,如果有需要,再接回主库。
如果 binlog 有备份的情况,可以先在从库上应用缺失的 binlog,然后再执行 start slave。
GTID的搭建比较简单,具体看文章:https://my.oschina.net/wangyunlong/blog/3041640
文章摘抄:极客时间-MySQL实战45讲 第27章
网友评论