正常测试主备切换: 主备节点正常
- 备节点读取 seconds_behind_master 值如果符合可接受影响时间大小则进行下一步, 如果不能接受则继续等待同步
- 将主库设置为read_only,, 查看备库节点应用完中专日志,
- 设置备节点为read_only=false,
- 切换地址,主备切换完成
- 恢复业务连接
主节点故障down机,切换方案:
主备-从节点主机故障切换
基于位点的主备切换
- 执行一条change master命令:
- 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表示,要从主库的 master_log_name文件的master_log_pos这个位置的日志继续同步 ,master_log_name--文件名, master_log_pos -- 文件偏移量
- 取同步位点:
- 等待新主库A‘ 应用完中转日志(realy_log)
- 在A’上执行show master status; 命令,得到当前A‘上最新的File 和Position;
- 记录源主库故障的时间点T
- 用mysqlbinlog 工具解析A’ 的File,得到T时刻的位点Position
- mysqlbinlog File --stop-datetime=T --start-datetime=T
- 展示中: end_log_pos 的值就是这个 $master_log_pos
- 如果出现同步数据到备库以及主库down 就发生在传完中转日志的时刻, 此时会导致这个位点再一次回传给备库执行, 进而报错冲突问题, 所以需要跳过此报错
- 主动跳过一个事务。跳过命令的写法是: set global sql_slave_skip_counter=1; start slave;
- 另外一种方式是,通过设置slave_skip_errors参数,直接设置跳过指定的错误。 在执行主备切换时,有这么两类错误,是经常会遇到的:
- 1062错误是插入数据时唯一键冲突;
- 1032错误是删除数据时找不到行。
GTID
理解: 对这个文件名以及文件位点进行打包, 加入集合中, 每个实例中有各自的对应集合包, 比对每个主从关系的集合是否同步
格式:
GTID= server_uuid:gno【官方标准格式: GTID=source_id:transaction_id 】
source_id就是server_uuid
- gtid_next=automatic, 代表使用默认值,MySQL会把server_uuid:gno 分配给这个事务
- 记录binlog时, 先记录一行 SET @@SESSION.GTID_NEXT='server_uuid:gno';
- 将这个GTID加入本实例的GTID集合
- 如果gtid_next是一个指定的GTID值, 比如通过set gtid_nest='current_gtid' 指定为current_gtid, 有两种可能
- 如果这个current_gtid已经存在于实例中的GTID 集合, 那么这个事务直接被忽略
- 如果不存在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的逻辑是这样的
- 实例B 指定主库A’, 基于主备切换协议建立连接
- 实例B把set_b 发给主库A‘
- 实例A’算出set_a与set_b的差集, 判断A;本地是否包含了这个差集需要的所有binlog 事务
- binlog判断, 如果不包含, 标识A‘已经把实例B 所需要的binliog给删除了, 直接反馈报错
- 如果确认全部包含, A; 从自己的binloig 文件里面, 找出第一个不再set_b事务,发给B;
- 之后按照这个事务开启, 依次读取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
补充:
- binlog判断, 如果不包含, 标识A‘已经把实例B 所需要的binliog给删除了, 直接反馈报错
问题: GTID模式下,如果一个新的从库接上主库,但是需要的binlog已经没 了,要怎么做?
- 如果业务允许主从不一致, 可以现在主库执行show global variables like "gtid_purged", 得到主库已经删除的GTID集合, 假设是gtid_purged1; 然后先在从库执行reset master, 再执行set global gtid_purged="gtid_purged1"; 最后执行 start slave, 就会从主库现存的binlog开始同步。 binlog 确实的那一部分,数据在从库上就可能会有丢失, 造成主从不一致
- 如果需要主从数据一致, 最好是通过重新搭建从库来做
- 如果有其他从库保留全量binlog, 可以把新的从库接到这个保留全量binlog 的从库, 追上日志之后, 如果有需要,再接回主库
- 如果binlog 有备份, 可以先在从库上应用缺失的binlog,然后再执行start slave