大家好,我是 Snow Hide,作为《MySQL 实战》这个专栏的学员之一,这是我打卡的第 37 天,也是我第 102 次进行这种操作。

今天我温习了该专栏里一篇叫《主库出问题了,从库怎么办?》的文章。

关键词总结:基于位点的主备切换(change master 命令的六个参数、取同步位点的方法、在 T 时刻原主库执行完 insert 语句并将 binlog 传给新主库和从库后瞬间掉电的状态、切换任务时主动跳过错误的两种常用方法(主动跳过一个事务、跳过指定的错误)、执行主备切换时的两类常见错误)、GTID 全局事务 ID(解决的问题、组成格式、官方定义格式、启动该模式、两种生成方式)、基于 GTID 的主备切换(从库实例上执行 start slave 命令取 binlog 的逻辑)、GTID 和在线 DDL(打开 GTID 模式时的主备切换流程)。

 

基于位点的主备切换

change master 命令的六个参数

  • MASTER_HOSTMASTER_PORTMASTER_USERMASTER_PASSWORD 四个参数,分别代表了主库和 IP、端口、用户名和密码;
  • 最后两个参数 MASTER_LOG_FILEMASTER_LOG_POS,表示从主库的 master_log_name 文件的 master_log_pos 位置的日志继续同步。而这个位置就是同步位点,就是主库对应的文件名和日志偏移量。

取同步位点的方法

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

输出的 end_log_pos 之后的值就是新主库在 T 时刻写入新 binlog 的位置。

在 T 时刻原主库执行完 insert 语句并将 binlog 传给新主库和从库后瞬间掉电的状态

  1. 从库上同步了 binlog,新插入数据已存在;
  2. 新主库上新插入数据也已存在,日志写在 end_log_pos 位置之后;
  3. 我们在从库上执行 change master 命令以指向新主库的 File 文件的 end_log_pos 位置使新插入数据的 binlog 同步到从库执行。
  4. 从库同步线程报主键重复错误并终止同步。

切换任务时主动跳过错误的两种常用方法

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

从库接收新主库时观察,每次碰到错误执行一次跳过命令。

跳过指定的错误

设置 slave_skip_errors 参数,直接设置跳过指定的错误。

执行主备切换时的两类常见错误

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

GTID 全局事务 ID

解决的问题

MySQL 5.6 版本引入的 GTID 解决了需要通过 sql_slave_skip_counter 跳过事务和通过 slave_skip_errors 忽略错误的方法的问题。

组成格式

GTID=server_uuid:gno
  • server_uuid:是一个实例第一次启动时自动生成的全局唯一值;
  • gno:是一个初始值为 1 的整数,每次提交事务时分配给该事务,并加 1。

官方定义格式

GTID=source_id:transaction_id

启动该模式

启动 MySQL 实例时加上参数 gtid_mode=onenforce_gtid_consistency=on

两种生成方式

  1. 如果 gtid_next=automatic,则使用默认值。MySQL 把 server_uuid:gno 分配给该事务:
    a. 记录 binlog 时先记录一行 SET:
    @@SESSION.GTID_NEXT='server_uuid:gno'; b. 把该 GTID 加入实例的 GTID 集合。
  2. 如果 gtid_next 是指定的 GTID 值,例如 set gtid='current_gtid',那么有两种可能:
    a. 如果 current_gtid 已存在于实例的 GTID 集合中,则执行的事务会被忽略;
    b. 如果 current_gtid 不存在于实例的 GTID 集合中,则将其分配给执行的事务,系统不会给事务生成新 GTID,因此 gno 也不会加 1。
     

基于 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=1 表示主备关系是 GTID 协议。

从库实例上执行 start slave 命令取 binlog 的逻辑

  1. 从库指定新主库,基于主备协议建立连接;
  2. 从库将其 GTID 集合发给新主库;
  3. 新主库算出其 GTID 集合与从库 GTID 集合的差集,就是所有存在于新主库 GTID 集合但不存在于从库 GTID 集合的 GTID 集合,判断新主库是否包含了该差集所需要的所有 binlog 事务;
    a. 如果不包含,则表示新主库已将从库需要的 binlog 删掉了,注解返回错误;
    b. 如果确认全部包含,新主库从其 binlog 文件内找出第一个不在从库 GTID 集合的事务并发给从库。
     

GTID 和在线 DDL

打开 GTID 模式时的主备切换流程

  • 主库执行 stop slave
  • 从库在不关闭 binlog 的情况下执行 DDL 语句;
  • 查出 DDL 语句对应的 GTID 并标记为 server_uuid_of_Y:gno
  • 主库执行以下语句序列:
set GTID_NEXT="server_uuid_of_Y:gno";
begin;
commit;
set gtid_next=automatic;
start slave;
  • 执行完主备切换,将该流程再执行一遍。
     

末了

重新总结了一下文中提到的内容:一主多从主备切换流程、从库找新主库位点的痛点、MySQL 5.6 版的 GTID 模式、GTID 基本概念和用法。