MySQL主备切换

时间:2023-01-17 18:59:36

正常测试主备切换: 主备节点正常

  1. 备节点读取 seconds_behind_master 值如果符合可接受影响时间大小则进行下一步, 如果不能接受则继续等待同步
  2. 将主库设置为read_only,, 查看备库节点应用完中专日志,
  3. 设置备节点为read_only=false,
  4. 切换地址,主备切换完成
  5. 恢复业务连接


主节点故障down机,切换方案:

主备-从节点主机故障切换

基于位点的主备切换

  1. 执行一条change master命令:
  1. CHANGE MASTER TO MASTER_HOST=$host_name
  2. MASTER_PORT=$port
  3. MASTER_USER=$user_name
  4. MASTER_PASSWORD=$password
  5. MASTER_LOG_FILE=$master_log_name
  6. MASTER_LOG_POS=$master_log_pos
  1. MASTER_LOG_FILE和MASTER_LOG_POS表示,要从主库的 master_log_name文件的master_log_pos这个位置的日志继续同步 ,master_log_name--文件名, master_log_pos -- 文件偏移量
  2. 取同步位点:
  1. 等待新主库A‘ 应用完中转日志(realy_log)
  2. 在A’上执行show master status; 命令,得到当前A‘上最新的File 和Position;
  3. 记录源主库故障的时间点T
  4. 用mysqlbinlog 工具解析A’ 的File,得到T时刻的位点Position
  5. mysqlbinlog File --stop-datetime=T --start-datetime=T
  1. 展示中: end_log_pos 的值就是这个 $master_log_pos
  2. 如果出现同步数据到备库以及主库down 就发生在传完中转日志的时刻, 此时会导致这个位点再一次回传给备库执行, 进而报错冲突问题, 所以需要跳过此报错
  1. 主动跳过一个事务。跳过命令的写法是: set global sql_slave_skip_counter=1; start slave;
  2. 另外一种方式是,通过设置slave_skip_errors参数,直接设置跳过指定的错误。 在执行主备切换时,有这么两类错误,是经常会遇到的:
  1. 1062错误是插入数据时唯一键冲突;
  2. 1032错误是删除数据时找不到行。


GTID

理解: 对这个文件名以及文件位点进行打包, 加入集合中, 每个实例中有各自的对应集合包, 比对每个主从关系的集合是否同步

格式:

GTID= server_uuid:gno【官方标准格式: GTID=source_id:transaction_id 】

source_id就是server_uuid

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

基于GTID 的主备切换

主库down, A‘作为新的主库即将切换业务, 备库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协议。

实例A‘算出set_a 与set_b 的差集,所有存在于set_a,但是不存在于set_b的GTID

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

  1. 实例B 指定主库A’, 基于主备切换协议建立连接
  2. 实例B把set_b 发给主库A‘
  3. 实例A’算出set_a与set_b的差集, 判断A;本地是否包含了这个差集需要的所有binlog 事务
  1. binlog判断, 如果不包含, 标识A‘已经把实例B 所需要的binliog给删除了, 直接反馈报错
  2. 如果确认全部包含, A; 从自己的binloig 文件里面, 找出第一个不再set_b事务,发给B;
  1. 之后按照这个事务开启, 依次读取binlog 发送给B执行


对于这个一主多从:

当A主库发生故障。 新的主库A’, B,C, D作为从节点分别发起change master命令将同步节点切换到A‘

新的主库A'的server_uuid_of_A:1-N, B从库的GTID集合是server_uuid_of_A':1-M,则主备切换后, B的集合就显示的是;server_uuid_of_A':1-M,server_uuid_of_A:1-N


补充:

  1. binlog判断, 如果不包含, 标识A‘已经把实例B 所需要的binliog给删除了, 直接反馈报错

问题: 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