MYSQL 一个事务在提交的时候能够保证binlog和redo log是同时提交的,并且能在宕机恢复后保持binlog 和redo log的一致性。

先来看看什么是redo log 和binlog,以及为什么要保持它们的一致性。

什么是redo log,binlog

redo log是innodb引擎层产生的日志, MYSQL从磁盘读取数据的单位是一页,当修改页中某条数据时,该行所在的数据页就变成了脏页,由于脏页并不会立马刷新到磁盘,所以redo log会记录下数据页进行了哪些变动,用于服务崩溃时的数据恢复。redo log是固定大小的,由多个文件组成一个环形的结构,

redo log由两个指针,write pos 和checkpoint,都是顺时针移动,write pos 记录redo log当前写入的位置, checkpoint往前移动,就代表就移动过的redo log记录的脏页刷新到磁盘上。所以,write poscheckpoint 之间的位置就代表redo log 还可以写的空间大小,当write pos等于checkpoint时,MYSQL则必须等待脏页刷新完毕后才能继续进行修改操作。

binlog 是mysql server服务层产生的日志。两者的用途也不一样。binlog 则主要用于数据库的备份,主从同步。binlog记录的是行变化,记录格式也有3种,statement,row,mixed,这里就不细讲了。

在了解了redo log 和binlog的含义和各自的作用后,我们先来看看它们在一次sql更新中是如何运作的。

sql 更新过程详解

来看下在一次事务过程中,它们的工作机制。假设我们在进行修改操作,那么可以用下面的流程图来表示,

1,首先判断要修改的数据是否在内存里,没有的话就从磁盘读取到内存。

2,写入redo log,注意这里写入的redo log仅仅是prepare状态,只有等到正式提交的时候才会变成commit状态。并且写入redo log也不是直接落盘,其实是写入到了redo log buffer 中,落盘时机受到innodb_flush_log_at_trx_commit 参数控制。

MYSQL会有一个后台线程,定时刷新redo log buffer 中的数据到磁盘上。除此以外,当innodb_flush_log_at_trx_commit 值为1时 redo log则会在在prepare阶段将redo log buffer 中的数据落入磁盘。

注意,这里说的事务提交的时候redo log buffer中的数据刷到磁盘上,并不仅仅是执行的当前事务,比如A,B两个事务,A事务执行到一半,写了部分数据到redo log buffer,那么B此时提交事务,同样也会将A事务的redo log 刷到磁盘上。

innodb_flush_log_at_trx_commit 值为 0 时,redo log buffer则不会在prepare或者事务提交时刷盘,而是由后台定时任务定时刷新redo log buffer中的数据到磁盘上。

innodb_flush_log_at_trx_commit 值为2时,则是将redo log buffer中的内容刷新到文件系统缓存中,由操作系统决定何时刷新到磁盘上。

所以可以看到,在事务执行过程中,redo log是可能一部分在内存,一部分已经落入磁盘了

3, 在写完redo log后,会去写binlog,写binlog同样不是直接写文件,而是写到binlog cache中,那么binlog是何时刷新到磁盘上呢,这个是由sync_bin参数决定的。

  • sync_binlog = 0 :提交事务时,将内存中的binlog cache写到文件系统缓存中,后续交由操作系统决定何时将数据持久化到磁盘

  • sync_binlog = 1 :提交事务时,将binlog cache中的数据写入到文件系统缓存,并立马刷新到磁盘。

  • sync_binlog =N(N>1) :提交事务时,都写到文件系统缓存,但累积 N 个事务后才 fsync 刷新到磁盘。

4, 最后一步便是对事物进行提交,按参数设置分别对redo log和binlog进行落盘处理。

为什么要保证binlog 和redo log 同时提交

看完了整个sql更新过程,先说下结论,innodb_flush_log_at_trx_commitsync_binlog都设置为1 能够保证binlog 和redo log 同时提交

再来看看如果redo log和binlog不同时提交会导致什么问题

redo log和binlog不同时提交会导致主备不一致

如果在一个事务提交过程中, binlog写入成功了,此时主库宕机,redo log写入失败,主库恢复后,那么binlog可能就会被从库拿去执行,然而主库的redo log是没有修改数据的,所以造成主备不一致。

换过来,redo log写入成功,但是binlog提交失败,从库就会缺失新的修改数据,造成主备不一致。

两阶段提交避免数据不一致

接着,我们来细聊 MYSQL在上述sql更新过程中,是如何保证redo log和binlog是同时提交的。

上述事务执行过程中,可以看到对于redo log的提交分了两个阶段,第一个是redo log的prepare 阶段,第二个是commit阶段。

宕机恢复时,redo log执行恢复的逻辑概括如下

1,只要redo log变成了commit状态,MYSQL就认为事务是成功了。

2,而恢复时,发现redo log是prepare 状态的话,就会去判断对应事务的binlog 是否完整,完整则对还未提交的事务进行提交,不完整则回滚事务。

我们来分析下异常的情况:

如上图所示,

1,在第一种异常情况下,redo log 和binlog都没有写入,主备是一致的。

2,第二和第三种异常情况, redo log已经落入磁盘,最后就看binlog是否完整了,完整宕机恢复后进行事务提交,备库即使得到binlog,也能保证与主库恢复后事务提交的数据 保持一致。

需要注意的是,innodb_flush_log_at_trx_commit 为1时才能保证redo log是在binlog写入前是已经落盘的,如果是0或者2,则有可能出现节点崩溃时,redo log没有写入到磁盘而丢失,而binlog是完整的情况,造成主备不一致。

两阶段提交带给业务开发上的思考

从MYSQL 实现两阶段提交的逻辑,可以归纳下,它是如何做到对两个业务做到最终一致的。

我举个业务上的例子, 比如有A,B两个服务,A服务依赖B服务,如何保证在A服务上的数据操作和请求B服务接口这两个动作同时成功或失败

我直接说下结论,

借鉴两阶段提交的逻辑,我们可以将A服务的数据操作在业务设计上增加一个预扣减的概念,先锁定A服务数据资源,然后去请求B服务的接口,失败的话,则释放A服务锁定的数据资源,成功的话则进行真实的扣减。

除此以外,还需要增加一个对A服务数据进行补偿修复的定时任务,类似与MYSQL数据库宕机根据binlog是否完整看事务是否提交一样,定时任务定期查看还没有终结的A服务数据,拎出来请求B服务查看业务成功状态,B服务返回成功,则将A服务的业务数据进行真实扣减,否则释放A服务锁定的数据资源。

通过两阶段提交,来查看业务的最终一致性。

最后,

自荐一波:

欢迎朋友们关注我的公众号:【蓝胖子的编程梦】!

学习容器知识,性能监控,Golang 相关编程知识

MYSQL 是如何保证binlog 和redo log同时提交的?的更多相关文章

  1. binlog和redo log日志提交

    组提交(group commit)是MYSQL处理日志的一种优化方式,主要为了解决写日志时频繁刷磁盘的问题.组提交伴随着MYSQL的发展不断优化,从最初只支持redo log 组提交,到目前5.6官方 ...

  2. MySQL中的重做日志(redo log),回滚日志(undo log),以及二进制日志(binlog)的简单总结

    MySQL中有六种日志文件,分别是:重做日志(redo log).回滚日志(undo log).二进制日志(binlog).错误日志(errorlog).慢查询日志(slow query log).一 ...

  3. MySQL:binlog 和 redo log

    [参考文章]:MySQL中Redo与Binlog顺序一致性问题? [参考文章]:极客时间 1. 数据更新时的日志处理流程 1.1 redo log(prepare状态) 此时SQL已经成功执行了,已经 ...

  4. 必须了解的mysql三大日志-binlog、redo log和undo log

    日志是 mysql 数据库的重要组成部分,记录着数据库运行期间各种状态信息.mysql日志主要包括错误日志.查询日志.慢查询日志.事务日志.二进制日志几大类.作为开发,我们重点需要关注的是二进制日志( ...

  5. 3000帧动画图解MySQL为什么需要binlog、redo log和undo log

    全文建立在MySQL的存储引擎为InnoDB的基础上 先看一条SQL如何入库的: 这是一条很简单的更新SQL,从MySQL服务端接收到SQL到落盘,先后经过了MySQL Server层和InnoDB存 ...

  6. 技术分析 | 通过DML语句浅谈binlog和redo log

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1 ...

  7. 数据库日志——binlog、redo log、undo log扫盲

    日志是数据库中比较重要的组成部分,很多核心的功能必须依靠日志才能完成. 该篇文章简要介绍了binlog.redo log与undo log,能够在一定程度上拓宽对mysql日志的整体认识. binlo ...

  8. MySQL的两种日志类型,redo log,binlog

    文章内容学习:极客时间-林晓彬老师-MySQL实战45讲 整理而得 我们知道MySQL数据库在发生意外宕机的情况下,可以将数据恢复到历史的某个时间点,能实现这个功能依靠的是日志,MySQL提供两种类型 ...

  9. binlog、redo log、undo log区别

    root@(none) 04:17:18>show variables like 'innodb_log_group_home_dir';+--------------------------- ...

  10. MySQL是怎么保证redo log和binlog是完整的?

    摘要:WAL机制保证只要redo log和binlog保证持久化到磁盘,就能确保MySQL异常重启后,数据可以恢复. 本文分享自华为云社区<MySQL会丢数据吗?>,作者: JavaEdg ...

随机推荐

  1. 硬盘SMART信息解读

    目录 一.SMART概述        4 二.SMART的ID代码        4 三.SMART的描述(Description)        5 四.SMART的值        5 1.临界 ...

  2. unordered_map模拟实现|STL源码剖析系列|开散列

    博主很久没有更新过STL源码剖析这个系列的文章了,主要是因为大部分STL常用的容器,博主都已经发过文章了,今天博主带着大家把哈希表也模拟实现一下. 前言 那么这里博主先安利一下一些干货满满的专栏啦! ...

  3. 【Linux】常用基本指令大汇总系列(篇一)【超详细的图解保姆教程】

    常用基本指令大汇总系列(篇一) 大家好,欢迎大家来到我的博客.从今天开始,博主就要开启一个全新的系列了!Linux操作系统常用基本指令汇总系列,当大家按顺序学完这个系列,在Linux上编写基本的C语言 ...

  4. ASCII、Unicode、UTF8 10年后,重新整理《专题1》

    以后基本都是Unicode定义二进制对应的字符,UTF8来按照一种格式来存储Unicode二进制,所以只需知道 unicode unicode 官网:https://home.unicode.org/ ...

  5. C#对于加密的一点整合 (AES,RSA,MD5,SHA256)

    aes 对称加密  密钥必须是32字节 using System; using System.Security.Cryptography; using System.Text; namespace C ...

  6. nginx做白名单和限流

    ​ 在我们生产环境中使用到了地图服务,每个月有免费请求次数,近一个月请求次数突然暴涨,导致直接开启付费模式,一个月上百刀的花销着实难扛,根据实际我们的业务使用情况,远达不到付费标准,故考虑做白名单和限 ...

  7. Host跨网段的ARP request

    写得很清楚的文章:ARP协议在同网段及跨网段下的工作原理 对应的官方ARP文档:RFC 826 对文档的解读:详解RFC 826文档 ARP跨网段进行request包发送,需要先检测自身子网是否与对方 ...

  8. Python中文件读写操作

    1 txt文件 1.1 写操作 import numpy as np def write(fileName,data): file=open(fileName,'w') row,col=data.sh ...

  9. 初探富文本之文档diff算法

    初探富文本之文档diff算法 当我们实现在线文档的系统时,通常需要考虑到文档的版本控制与审核能力,并且这是这是整个文档管理流程中的重要环节,那么在这个环节中通常就需要文档的diff能力,这样我们就可以 ...

  10. 如何在Windows上使用Git创建一个可执行脚本?

    长话短说,今天介绍如何在windows上使用Git上创建一个可执行的shell脚本. 首先我们要知道windows上Git新添加的文件权限是:-rw-r--r--(对应权限值是644),而通常创建的s ...