大家好,我是 Snow Hide,作为《MySQL 实战》这个专栏的学员之一,这是我打卡的第 37 天,也是我第 102 次进行这种操作。
今天我温习了该专栏里一篇叫《主库出问题了,从库怎么办?》的文章。
关键词总结:基于位点的主备切换(change master 命令的六个参数、取同步位点的方法、在 T 时刻原主库执行完 insert 语句并将 binlog 传给新主库和从库后瞬间掉电的状态、切换任务时主动跳过错误的两种常用方法(主动跳过一个事务、跳过指定的错误)、执行主备切换时的两类常见错误)、GTID 全局事务 ID(解决的问题、组成格式、官方定义格式、启动该模式、两种生成方式)、基于 GTID 的主备切换(从库实例上执行 start slave 命令取 binlog 的逻辑)、GTID 和在线 DDL(打开 GTID 模式时的主备切换流程)。
基于位点的主备切换
change master 命令的六个参数
-
MASTER_HOST
、MASTER_PORT
、MASTER_USER
和MASTER_PASSWORD
四个参数,分别代表了主库和 IP、端口、用户名和密码; - 最后两个参数
MASTER_LOG_FILE
和MASTER_LOG_POS
,表示从主库的master_log_name
文件的master_log_pos
位置的日志继续同步。而这个位置就是同步位点,就是主库对应的文件名和日志偏移量。
取同步位点的方法
- 等待新主库把中转日志(relay log)全部同步完成;
- 在新主库上执行
show master status
命令,得到其最新的File
和Position
; - 取原主库故障时刻 T;
- 用
mysqlbinlog
工具解析新主库的File
,得到 T 时刻的位点。
mysqlbinlog File --stop-datetime=T --start-datetime=T
输出的 end_log_pos
之后的值就是新主库在 T 时刻写入新 binlog 的位置。
在 T 时刻原主库执行完 insert 语句并将 binlog 传给新主库和从库后瞬间掉电的状态
- 从库上同步了 binlog,新插入数据已存在;
- 新主库上新插入数据也已存在,日志写在
end_log_pos
位置之后; - 我们在从库上执行
change master
命令以指向新主库的 File 文件的end_log_pos
位置使新插入数据的 binlog 同步到从库执行。 - 从库同步线程报主键重复错误并终止同步。
切换任务时主动跳过错误的两种常用方法
主动跳过一个事务
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=on
和 enforce_gtid_consistency=on
。
两种生成方式
- 如果
gtid_next=automatic
,则使用默认值。MySQL 把server_uuid:gno
分配给该事务:
a. 记录 binlog 时先记录一行 SET:@@SESSION.GTID_NEXT='server_uuid:gno';
b. 把该 GTID 加入实例的 GTID 集合。 - 如果 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 的逻辑
- 从库指定新主库,基于主备协议建立连接;
- 从库将其 GTID 集合发给新主库;
- 新主库算出其 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 基本概念和用法。