MySQL 主备同步技术演化

主库出问题了,从库怎么办?

备库:同步主库的binlog,当主库出问题时,备库切换为主库。一般不提供读服务。
从库:同步主库的binlog,只对外提供读服务。

一主多从基本结构

一主多从主备切换 方法

基于位点的主备切换

首先我们知道,设置从库时的命令

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  

master_log_file和master_log_pos 表示从主库的这个文件的pos位置开始同步,

那如何获取这个pos位置呢?

一种取同步位点的方法是这样的:

  1. 等待新主库 A’把中转日志(relay log)全部同步完成;
  2. 在 A’上执行 show master status 命令,得到当前 A’上最新的 File 和 Position;
  3. 取原主库 A 故障的时刻 T;
  4. 用 mysqlbinlog 工具解析 A’的 File,得到 T 时刻的位点。

通过命令show master status 可以得到file和pos。这里的pos是最新的,从库同步的话,是需要找故障时刻T的位点,执行 mysqlbinlog File --stop-datetime=T --start-datetime=T 获取到end_log_pos 作为同步的位点。

这种取同步位点的方法是不精确的,往往在执行的时候,需要执行一些辅助命令来跳过某些错误。

  1. 主动跳过一个事务
set global sql_slave_skip_counter=1;
start slave;

缺点是没遇到一个错误,就需要手动执行一次。

  1. 指定错误码跳过
set slave_skip_errors = "1032,1062";
start slave;

在执行主备切换时,有这么两类错误,是经常会遇到的:

  1. 1062 错误是插入数据时唯一键冲突;
  2. 1032 错误是删除数据时找不到行。

千万注意,主备切换后,要将这个参数设置为空

GTID

MySQL 5.6版本引入了GTID,将自动找位点的这一步骤完全自动化了。

那什么是GTID?

GTID 的全称是 Global Transaction Identifier,也就是全局事务 ID,是一个事务在提交的时候生成的,是这个事务的唯一标识。
GTID=server_uuid:gno

1, server_uuid 是一个实例第一次启动时自动生成的,是一个全局唯一的值
2. gno 是一个整数,初始值是 1,每次提交事务的时候分配给这个事务,并加 1。

gtid_next=automatic 代表使用默认值。
如果设置gtid_next=current_gtid, 如果current_gtid已经在实例的gtid集合中,接下来这个事务会被直接跳过,否则分配current_gtid给接下来的事务执行。注意:每个MySQL实例都维护了一个GTID集合,用来对应执行过的所有事务

基于GTID的主备切换

命令差不多

CHANGE MASTER TO 
MASTER_HOST=$host_name 
MASTER_PORT=$port 
MASTER_USER=$user_name 
MASTER_PASSWORD=$password 
master_auto_position=1 

主要是master_auto_position 表示这个主备关系使用的是GTID协议。

模拟以下GTID的主备切换。实例A的gtid集合为set_a, 实例B的gtid集合为set_b.

  1. 实例B使用change master 设置主库,使用master_auto_position参数。
  2. 实例B将set_b 发送给主库A
  3. 实例A算出set_a 与 set_b 之间的差集,即只在set_a的gtid,然后判断A的binlog是否有这个差集的所有事务,如果少了一些,则会返回错误给B,拒绝实例B建立主从同步,否则找出差集中的第一个gtid给实例B,完成主动找pos的过程
  4. 之后就从binlog这个位置将事务发给B取执行。

利用GTID主动跳过导致从库同步失败的事务

set gtid_next='aaaaaaaa-cccc-dddd-eeee-ffffffffffff:10';
begin;
commit;
set gtid_next=automatic;
start slave;

aaaaaaaa-cccc-dddd-eeee-ffffffffffff:10 是主库已经存在的事物id,该事务id会导致从库同步失败,通过设置gtid_next并提交一个空事务,将其加入从库的gtid集合中,从而跳过执行该事务

最后一个问题:基于gtid的主备切换,怎么解决主库因为binlog缺少某些事务而拒绝建立主从同步呢?

  1. 如果业务允许主从不一致的情况,那么可以在主库上先执行 show global variables like ‘gtid_purged’,得到主库已经删除的 GTID 集合,假设是 gtid_purged1;然后先在从库上执行 reset master,再执行 set global gtid_purged =‘gtid_purged1’;最后执行 start slave,就会从主库现存的 binlog 开始同步。binlog 缺失的那一部分,数据在从库上就可能会有丢失,造成主从不一致。
  2. 如果需要主从数据一致的话,最好还是通过重新搭建从库来做。
  3. 如果有其他的从库保留有全量的 binlog 的话,可以把新的从库先接到这个保留了全量 binlog 的从库,追上日志以后,如果有需要,再接回主库。
  4. 如果 binlog 有备份的情况,可以先在从库上应用缺失的 binlog,然后再执行 start slave。
posted @ 2022-04-08 00:49  yihailin  阅读(106)  评论(0编辑  收藏  举报