一 前言

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 NCOMMIT;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 NUpdate replication info
COMMIT
复制代码

一图胜千言:

绿色的代表实际业务的事务,蓝色的是开启 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 记录的位点是已经执行并且提交的事务之后位点信息。

一图胜千言:

蓝色的 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 进行复制。举个?

实例 a 的事务集合 set_a, 实例 b 的事务集合 set_b ,设置 b 为 a 的从库的时候,其中的 binlog 协议伪算法如下:

  1. 实例 b 指向主库实例 a, 基于主备协议建立主从关系

  2. 实例 b 将 GTID 信息发送给实例 a

    UNION(@@global.gtid_executed, Retrieved_gtid_set - last_received_GTID)

  3. 实例 a 计算出 set_b 与 set_a 的差集,也就是存在于 set_a 但是不存在与 set_b 的 GTID 集合,判断实例 a 本地的 binlog 是否包含了该差集所需要的所有 binlog 事务。

a 如果不包含,表示实例 a 已经把实例 b 需要的 binlog 删除了,直接返回报错。

b 如果确认全部包含 实例 a 从本地 binlog 文件里面,找到第一个不在 set_b 的事务,发送给实例 b。

  1. 从这个事务开始,往后读文件,按顺序取 binlog 发送给实例 b。

GTID 模式下,slave crash-safe 运行机制

蓝色 ABC:3 表示已经执行并提交的事务,绿色 ABC:4表示正在执行的事务,此时 slave crash,实例记录的 gtid_executed=ABC:1-3,系统重启 relay_log 被删除。slave 将 UNION(@@global.gtid_executed, null) 发送到主库,主库会将 ABC:3 以后的 binlog 传送给 slave 继续执行。

注意

从新的复制协议中slave重启时是基于binlog中的GTID信息进行复制的,并不依赖于mysql.slave_replay_log_info。为了保障binlog及时落盘slave要设置 双1模式 sync_binlog = 1 innodb_flush_log_at_trx_commit = 1

3.4 如何开启 crash-safe 特性

通过配置两个如下两个参数开启该特性。

relay_log_info_repository = TABLE
relay_log_recovery = ON
复制代码

看到这里是不是有疑问为什么没有 master.info 相关的参数配置?

其实开启 slave 的 crash-safe 之后,slave 重启的时候会自动清空之前的 relay-log,IO thread 从 mysql.slave_relay_log_info 表中记录的位点开始拉取数据,而不是依赖 slave_master_info 表相关数据。

注意: 如果是 MySQL 5.6.5 或者更早期。slave_master_info 和 slave_relay_log_info 表默认使用 MyISAM 引擎。所以还得修改成 innodb,如下:

ALTER TABLE mysql.slave\_master\_info ENGINE=InnoDB;
ALTER TABLE mysql.slave\_relay\_log\_info ENGINE=InnoDB;
复制代码

3.5 相关参数

  1. 开启 crash-safe 之后,slave 重启之后,不再依赖 master info 相关的参数,所以这两个参数不做过多讨论。不过为了和 relay log info 存储一致,推荐存储 maste-info 到表里,sync_master_info 保持默认,设置为比较低的值,在写压力比较大的情况下,会有 IO 损耗。
master_info_repository =TABLE
sync_master_info=0
复制代码
  1. 开启 crash-safe 必要参数
 relay_log_info_repository = TABLErelay_log_recovery = 1
复制代码

这 2 个不多做介绍了,前面已经将的非常透彻。

  1. relay log 相关

    当 relay_log_info_repository=file 时, 更新位点信息的频率依赖于sync_relay_log_info = N (N>=0):

    a 当 sync_relay_log_info=0 时,MySQL 依赖 OS 系统定期更新。

    b 当 sync_relay_log_info=N时(N>0), MySQL server 会在每执行 N 个事务之后调用 fdatasync() 刷 relay-log.info 文件。

    当 relay_log_info_repository=table

    如果 mysql.slave_relay_log_info 是 innodb 存储引擎,则每次事务更新,系统会自动忽略 sync_relay_log_info 的设置。 [图片上传失败...(image-c3b7d0-1560153907706)]

    如果 mysql.slave_relay_log_info 是非事务存储引擎,则

    a 当 sync_relay_log_info=0 时,不更新。

    b 当 sync_relay_log_info=N 时(N>0), MySQL server 会在每执行 N 个事务之后调用 fdatasync() 刷 relay-log.info 文件。

    sync_relay_log 控制着 relay-log 的刷新策略,类似 sync_binlog。不过这个参数在开启 crash-safe 特性之后没有什么实质的意义。建议保持该参数为默认值即可

四 其他问题

每个硬币都有它的两面性。开启 crash-safe 会带来哪些潜在的问题?

1 重启 slave,重新拉取 relay-log,一主多从的集群会给主库带来 IO 和带宽压力。

2 主库不可用,或者 binlog 被删除了,slave 找不到所需要的 binlog。

参考文章

[1] hackmongo.com/post/crash-…

[2] dev.mysql.com/doc/refman/…

[3] dev.mysql.com/doc/refman/…

转载于:https://juejin.im/post/5cfe10a7f265da1bd3054e17

深入浅出MySQL crash safe相关推荐

  1. 阿里云RDS深度定制-XA Crash Safe

    简介: 近几年,随着分布式数据库系统的兴起,特别是基于MySQL分布式数据库系统,会用到XA来保证全局事务的一致性.众所周知,MySQL对XA事务的支持是比较弱的,存在很多问题.为了满足分布式数据库系 ...

  2. 深入解读MySQL8.0 新特性 :Crash Safe DDL

    前言 在MySQL8.0之前的版本中,由于架构的原因,mysql在server层使用统一的frm文件来存储表元数据信息,这个信息能够被不同的存储引擎识别.而实际上innodb本身也存储有元数据信息.这 ...

  3. replication crash safe

    什么是主从复制的replication crash safe? 参数master_info_repository有两个值: FILE (对应的文件master.info),  or TABLE (对应 ...

  4. 《深入浅出MySQL:数据库开发、优化与管理维护(第2版)》一一第 1 章  MySQL的安装与配置...

    第 1 章 MySQL的安装与配置 深入浅出MySQL:数据库开发.优化与管理维护(第2版) 近几年,开源数据库逐渐流行起来.由于具有免费使用.配置简单.稳定性好.性能优良等优点,开源数据库在中低端应 ...

  5. 深入浅出MySQL事务处理和锁机制

    深入浅出MySQL事务处理和锁机制 2015-01-13 架构师之旅 1. 事务处理和并发性 1.1. 基础知识和相关概念 1 )全部的表类型都可以使用锁,但是只有 InnoDB 和 BDB 才有内置 ...

  6. 《深入浅出MySQL:数据库开发、优化与管理维护(第2版)》一一1.2 MySQL的安装...

    本节书摘来自异步社区出版社<深入浅出MySQL:数据库开发.优化与管理维护(第2版)>一书中的第1章,第1.2节,作者: 唐汉明 , 翟振兴 , 关宝军 , 王洪权 , 黄潇,更多章节内容 ...

  7. 深入浅出MySQL出版了

    经过近一年的写作,我们的新书,也是大家的第一本书<<深入浅出MySQL>>终于出版了,近期已经在全国上市,下面是图示的封面: 还有程序员杂志做的宣传: 从china-pub前两 ...

  8. 读《深入浅出MySQL数据库开发、优化与管理维护(第2版)》笔记2 WITH ROLLUP关键字

    读<深入浅出MySQL数据库开发.优化与管理维护(第2版)>笔记2 WITH ROLLUP关键字 WITH ROLLUP是可选语法,表名是否对分类聚合后的结果进行再汇总; 我自己的使用实例 ...

  9. [深入浅出]MySQL安全规范

    [深入浅出]MySQL安全规范 一.Mysql服务器安全规范 1. 禁止应用直连DB,一般通过代理访问. 2. 禁止DB公网访问. 3. 禁止生产和办公互通,需生产环境和办公环境隔离. 4. Linu ...

  10. 深入浅出Mysql - 优化篇(锁)

    深入浅出Mysql - 优化篇(锁) 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保 ...

最新文章

  1. Spring 中的Scheduler
  2. DTW动态时间规整算法
  3. 嵌入式 Linux 的分类
  4. MongoDB 安装与基本命令
  5. MySQL性能优化之道
  6. 熬夜写代码,不如换女装入 GitHub 获上千 Star?
  7. docker machine介绍和使用
  8. 【matlab】元胞数组的创建
  9. WLAN配置实例(一)——二层组网直接转发
  10. mongodb 日期分组聚合_如何在MongoDB中按其他字段分组时聚合时间序列数据?
  11. JPA Example查询
  12. 制造行业相关名词释义
  13. (转) 很牛的求职经历
  14. 计算机网络自顶向下第七版第四章答案,《计算机网络·自顶向下方法》第七版 第四章 课后习题与问题 答案...
  15. Shawn's 杂记
  16. 医院挂号系统源码(含数据库)
  17. JVM和DVM的区别
  18. 在Firefox中以电影院风格观看YouTube视频
  19. Matlab-算术编码
  20. 【信号处理】基于优化算法的 SAR 信号处理(Matlab代码实现)

热门文章

  1. 生产者消费者之爸爸妈妈儿子女儿苹果橘子编程实现
  2. Log4j2 Zero Day 漏洞 Apache Flink 应对指南
  3. c语言程序设计教程 郭浩志,C语言程序设计教程答案杨路明郭浩志.doc
  4. 学生选课系统代码-2view视图层代码【MVC--v】代码
  5. php阿拉伯语字符串,使用PHP将RTL(阿拉伯语)文本写入图像
  6. python画哆啦a梦图片_画了个多啦A梦,但是感觉怪怪的
  7. 5.Scalal语法03 - 函数
  8. 空指针、NULL指针、零指针
  9. 【电源】开关电源、线性稳压电源
  10. Nginx 读写分离详解