欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

如何保障MySQL主从复制关系的稳定性?关键词(新特性、crash-safe)

程序员文章站 2022-06-03 18:53:46
MySQL 主从架构已经被广泛应用,保障主从复制关系的稳定性是大家一直关注的焦点。MySQL 5.6 针对主从复制稳定性提供了新特性: slave 支持 crash-safe。该功能可以解决之前版本中系统异常断电可能导致 relay_log.info 位点信息不准确的问题。 本文将从原理,参数,新的... ......

如何保障MySQL主从复制关系的稳定性?关键词(新特性、crash-safe)

一 前言

mysql 主从架构已经被广泛应用,保障主从复制关系的稳定性是大家一直关注的焦点。mysql 5.6 针对主从复制稳定性提供了新特性: slave 支持 crash-safe。该功能可以解决之前版本中系统异常断电可能导致 relay_log.info 位点信息不准确的问题。
本文将从原理,参数,新的问题等几个方面对该特性进行介绍。

二 crash-unsafe

在了解 slave crash-safe 之前,我们先分析 mysql 5.6 之前的版本出现 slave crash-unsafe 的原因。我们知道在一套主从结构体系中,slave 包含两个线程:即 io thread 和 sql thread。两个线程的执行进度(偏移量)都保存在文件中。

io thread 负责从 master 拉取 binlog 文件并保存到本地的 relay-log 文件中。

sql thread 负责执行重复 sql,执行 relay-log 记录的日志。

crash-unsafe 情况下 sql_thread 的 的工作模式:

start transaction;
 statement 1
  ...
 statement n
 commit;

update replication info files (master.info, relay_log.info)

 

io thread 的执行状态信息保存在 master.info 文件, sql thread 的执行状态信息保存在 relay-log.info 文件。slave 运行正常的情况下,记录位点没有问题。但是每当系统发生 crash,存储的偏移量可能是不准确的(需要注意的是这些文件被修改后不是同步写入磁盘的)。因为应用 binlog 和更新位点信息到文件并不是原子操作,而是两个独立的步骤。比如 sql thread 已经应用 relay-log.01 的4个事务

 trx1(pos:10)
 trx2(pos:20)
 trx3(pos:30)
 trx4(pos:40) 

 

但是 sql thread 更新位点 (relay-log.01,30) 到 relay-log.info 文件中,slave 实例重启的时候 sql thread 会重复执行事务 trx4,于是乎,大家就看到比较常见的复制报错 error 1062,error 1032。

mysql 5.5 通过两个参数来缓解该问题,使用 sync_master_info=1 和sync_replay_log_info=1 来保证 slave 的两个线程每次写一个事务就分别向两个文件同步一次 io thread 和 sql thread 当前执行的位点信息。当然同步操作不是免费的,频繁更新磁盘文件需要消耗性能。

但是,即使设置了 sync_master_info=1 和 sync_relay_info=1,问题还是会出现,因为复制信息是在 transactions 提交后写入的,如果 crash 发生在事务提交和 os 写文件之间,那么 relay-log.info 就可能是错误的。当 slave 从新启动的时候,最后那个事务可能会被执行两次.具体的影响取决于事务的具体操作.复制可能会继续运行比如 update/delete,或者报错 比如 insert 操作,此时主从数据的一致性可能会被破坏。

三 crash-safe 特性

3.1 保障 apply log 和更新位点信息操作的原子性

通过上面的分析,我们知道 slave crash-unsafe 的原因在于应用 binlog 和更新文件的非原子性。mysql 5.6 版本通过将更新位点信息存放到表中,并且和正常的事务一起执行,进而保障 apply binlog 的事务和更新 relay info 信息到 slave_relay_log_info 的原子性.

就是把 sql thread 执行事务和更新 mysql.slave_replay_log_info 的语句合并为同一个事务,由 mysql 系统来保障事务的原子性。我们可以通过伪代码来模拟 crash-safe 的原理:crash-safe 情况下 sql_thread 的工作模式

start transaction;
  statement 1
  ...
  statement n
  update replication info
commit

 

一图胜千言:

如何保障MySQL主从复制关系的稳定性?关键词(新特性、crash-safe)

 

绿色的代表实际业务的事务,蓝色的是开启 mysql 执行的更新slave_replay_log_info 相关位点信息的 sql ,然后将这两个 sql 合并在一个事务中执行,利用 mysql 事务机制和 innodb 表保障原子性。不会出现应用 binlog 和更新位点信息两个动作割裂导致不一致的问题。

3.2 crash 后的恢复动作

通过设置 relay_log_recovery = on,slave 遇到异常 crash,然后重启的时候,系统会删除现有的 relay log,然后 io thread 会从 mysql.slave_replay_log_info 记录的位点信息重新拉取主库的 binlog。mysql 如此设计的出发点是:

  1. sql thread apply binlog 的位点永远小于等于 io thread 从主库拉取的位点。
  2. sql thread 记录的位点是已经执行并且提交的事务之后位点信息。

一图胜千言:

如何保障MySQL主从复制关系的稳定性?关键词(新特性、crash-safe)

 

蓝色的 update 语句代表已经执行并提交的事务,绿色的 delete 语句表示正在执行的 sql,还未提交。此时 slave_replay_log_info 表记录的 relay log info是**update 语句结束,delete 语句开始之前的位点 
(relay_log.01,100)** 。如果遇到系统 crash,slave 实例重启之后,会删除已经有的 relaylog,并且 io thread 会从(relay_log.01,100)对应的 master binlog 位点重新拉取主库的 binlog,sql thread 也会从这个位点开始应用 binlog。

3.3 gtid 模式下的 crash safe

和基于位点的复制不同,gtid 模式下使用新的复制协议 com_binlog_dump_gtid 进行复制。举个