下图是一张正常的数据库一主多从架构示意图:


mysql8主从切换测试 mysql主从切换步骤_mysql8主从切换测试

A和A’互为主备,负责所有的写入和部分读取;从库B,C,D主库A负责剩余的读取请求。当主库A出现问题,需要进行主备切换,切换示意图如下:


mysql8主从切换测试 mysql主从切换步骤_mysql8主从切换测试_02

27.1基于位点的主备切换

从库B需要切换主库时,我们需要执行change master命令,具体如下:

CHANGE MASTER TO 
# IP地址
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_POS如何定位?下面是得到位点的方法如下:

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

但是上面方法得出来的位点会出现错误,从库可能已经把这个日志同步好了,就会报出错误,例如 Duplicate entry ‘id_of_R’ for key ‘PRIMARY’ ,导致同步停止。

如果出现问题,通常有以下两种方式:

1.启动一个事务,跳过错误

跳过错误的命令如下:

set global sql_slave_skip_counter=1;
start slave;

这种方式需要一遍一遍地尝试,知道不出现错误。

2.跳过指定错误

通过设定 slave_skip_errors 参数 ,来指定设定的错误类型。

例如常见的错误类型:

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

在切换中,我们必须要保证这个操作为无损的,在同步完成后,我们还是需要将这个参数设置回来。

27.2GTID

每个 MySQL 实例都维护了一个 GTID 集合,用来对应“这个实例执行过的所有事务”。 主备执行完事务之后,就会将GTID加入集合;从库在同步日志之后也会将GTID加入集合。

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

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

GTID 模式的启动也很简单,我们只需要在启动一个 MySQL 实例的时候,加上参数 gtid_mode=on 和 enforce_gtid_consistency=on 就可以了。

这个 GTID 有两种生成方式,而使用哪种方式取决于 session 变量 gtid_next 的值。

  • 如果 gtid_next=automatic,代表使用默认值。这时,MySQL 就会把 server_uuid:gno 分配给这个事务。a. 记录 binlog 的时候,先记录一行 SET @@SESSION.GTID_NEXT=‘server_uuid:gno’;b. 把这个 GTID 加入本实例的 GTID 集合。
  • 如果 gtid_next 是一个指定的 GTID 的值,比如通过 set gtid_next='current_gtid’指定为 current_gtid,那么就有两种可能:
  • a. 如果 current_gtid 已经存在于实例的 GTID 集合中,接下来执行的这个事务会直接被系统忽略;
  • b. 如果 current_gtid 没有存在于实例的 GTID 集合中,就将这个 current_gtid 分配给接下来要执行的事务,也就是说系统不需要给这个事务生成新的 GTID,因此 gno 也不用加 1。

27.3 基于 GTID 的主备切换

在 GTID 模式下,备库 B 要设置为新主库 A’的从库的语法如下:

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 协议。

我们在实例 B 上执行 start slave 命令,取 binlog 的逻辑是这样的:

  1. 实例 B 指定主库 A’,基于主备协议建立连接。
  2. 实例 B 把 set_b 发给主库 A’。
  3. 实例 A’算出 set_a 与 set_b 的差集,也就是所有存在于 set_a,但是不存在于 set_b 的 GTID 的集合,判断 A’本地是否包含了这个差集需要的所有 binlog 事务。a. 如果不包含,表示 A’已经把实例 B 需要的 binlog 给删掉了,直接返回错误;b. 如果确认全部包含,A’从自己的 binlog 文件里面,找出第一个不在 set_b 的事务,发给 B;
  4. 之后就从这个事务开始,往后读文件,按顺序取 binlog 发给 B 去执行。

练习问题:

  1. 一主多从的状态图,切换后的状态图
  2. 基于位点的主备切换和遇到的问题及解决方法
  3. GITD概念,如何开启,参数如何设置
  4. GITD模式下的切换流程