日志系统:WAL和二阶段提交

news2024/11/16 9:57:22

1. 前言

一条更新语句在执行过程中不仅仅要操作不仅仅是通过数据库的组件(分析器、优化器、执行器、存储引擎等)操作表数据还涉及以下内容:

  • 要操作日志系统的redo log、binlog和undo log,

  • 更新操作也不是实时更新到磁盘的而是通过3.Write-Ahead Logging机制先写日志后面再将数据写磁盘的

  • rdoo log日志 和 bin log 日志的顺序又涉及到4.二阶段提交。

  • 如果数据涉及到索引还要对5.change buffer进行操作

2. MySQL日志系统

在MySQL中,有三种日志。分别是redo log、binlog和undo log。在更新过程中要对日志进行更新(其中undo log主要用于协助回滚,和redo logbinlog的联系不大,可以单独讨论)。

重启后,undo log也还是需要的,会丢失吗?所以undo log的保存策略还是很重要的

做数据恢复的操作会记录到undo log中吗?

2.1 redo log(重做日志)

Write-Ahead Logging机制

在数据更新过程中,如果每次的更新操作都需要写进磁盘,IO成本很高,故MySQL采用 先将数据写到内存中,在适当的时候将数据刷新到磁盘 的方式提高SQL操作的性能。

但是只写内存如果遇到数据库宕机就可能造成数据丢失(内存数据不能持久化),MySQL使用WAL技术(全称Write-Ahead Logging)解决内存数据可能丢失和数据更新IO成本高的问题。WAL的关键点是先写日志再写磁盘。具体来说,当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log里面并更新内存,InnoDB引擎会在适当的时候将这个数据刷新到磁盘里面。

redo log的结构

InnoDB的 redo log 是固定大小的,比如可以配置一组4个文件,每个文件大小是1G。那么redo log总共可以记录4GB的操作,从头开始写,写到末尾又回到开头循环写。??当写满时擦除一部分记录。存储的是物理逻辑(xxxx页修改了xxx)。

哪些日志是可以删除的?

redo log要想代替真实数据实现数据持久化,肯定也要写磁盘,也需要IO,为什么说优化了SQL操作的性能?

  • 在了解redo log的结构和写log的规则后知道,redo log写磁盘是顺序写的,数据的更新时随机写的,顺序写不需要寻址移动等操作,性能优。

  • redo log 组合提交

2.2 binlog(归档日志)

为什么有两份日志?

binlog是Server层的日志,redo log是InnoDB引擎特有的日志。最开始MySQL里并没有InnoDB引擎,MySQL自带的引擎是MyISAM,但是MyISAM没有crash-safe的能力, binlog日志只能用于归档。 而InnoDB是另一个公司以插件形式引入MySQL的, 既然只依靠binlog是没有crash-safe能力的, 所以InnoDB使用另外一套日志系统——也就是redo log来实现crash-safe能力。

redo log 和 binlog的区别

  1. 存储的内容:可以这样理解,binlog记载的是update/delete/insert这样的SQL语句,而redo log记载的是物理修改的内容(xxxx页修改了xxx)。所以在搜索资料的时候也会有这样的说法:binlog 记录的是数据的逻辑变化redo log 记录的是数据的物理变化

  2. 功能:

    • redo log的作用是实现持久化。数据库更新写完内存中的数据,如果数据库挂了,那我们可以通过redo log来恢复内存还没来得及刷到磁盘的数据,将redo log加载到内存里边,那内存就能恢复到挂掉之前的数据了。

    • binlog的作用是进行复制和恢复。主从服务器需要保持数据的一致性,通过binlog来同步数据。如果整个数据库的数据都被删除了,binlog存储着所有的数据变更情况,那么可以通过binlog来对数据进行恢复。

  3. 载体:redo log是InnoDB引擎特有的。binlog是MySQL的Server层实现的,所有引擎都可以使用。(也因此MyISAM是没有crash-safe能力的)

  4. 记录方式:redo log是循环写的,空间固定会用完;binlog是追加写入的,一个文件写满后会切换到下一个文件而不会去覆盖以前的日志。

3.3 undo log

undo log 主要有两个作用:回滚和多版本并发控制(MVCC)

在数据修改的时候,不仅记录了redo log,还记录undo log,如果因为某些原因导致事务失败或回滚了,可以用undo log进行回滚undo log主要存储的也是逻辑日志,比如我们要insert一条数据了,那undo log会记录的一条对应的delete日志。我们要update一条记录时,它会记录一条对应相反的update记录。

回滚的实现就是找到undo log中对应的相反操作语句执行。 而多版本并发控制则是利用undo log做版本的回退(聊MVCCC时再具体讲)

3. 数据更新过程

首先是MySQL的各个功能模块,在MySQL查询过程会详细介绍。

以更新ID为2的行的某个值+1为例:

  1. 数据库连接,然后通过分析器进行词法分析和语法分析,再经过优化器选择索引等必要步骤。

  2. 取数据:执行器先找引擎取ID=2这一行。 ID是主键, 引擎直接用树搜索找到这一行。 如果ID=2这一行所在的数据页本来就在内存中, 就直接返回给执行器; 否则, 需要先从磁盘读入内存, 然后再返回。

  3. 更新数据到内存:执行器拿到引擎给的行数据, 把这个值加上1, 比如原来是N, 现在就是N+1, 得到新的一行数据, 再调用引擎接口写入这行新数据到内存(使用change buffer则不会马上更新到磁盘)。

  4. 写prepare状态redo log:将这个更新操作记录到redo log里面, 此时redo log处于prepare状态。 然后告知执行器执行完成了, 随时可以提交事务。

  5. 写binlog:执行器生成这个操作的binlog, 并把binlog写入磁盘。

  6. 修改redo log状态为commit:执行器调用引擎的提交事务接口, 引擎把刚刚写入的redo log改成提交(commit) 状态, 更新完成。

上图中,浅色框表示是在InnoDB内部执行的, 深色框表示是在执行器中执行的。

4. 二阶段提交

上图执行过程中,redo log分为prepare阶段和commit阶段,在写入binlog的前后执行,这就是二阶段提交。

4.1 为什么需要二阶段提交

为什么必须有“两阶段提交”呢? 这是为了让 redo logbinlog 日志的数据逻辑保持一致(两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案,并非MySQL日志系统的专有,日常开发中也有可能会用到。):

  • 先写redo log再写binlog:主服务器正常,从服务器(或通过备份+binlog重放恢复的某时刻数据的临时库)丢失数据。

  • 先写binlog再写redo log:从服务器(或通过备份+binlog重放恢复的某时刻数据的临时库)正常,主服务器丢失数据。

4.2 二阶段提交怎么解决问题

崩溃恢复时的判断规则。

  1. 如果redo log里面的事务是完整的, 也就是已经有了commit标识, 则直接提交;

  2. 如果redo log里面的事务只有完整的prepare, 则判断对应的事务binlog是否存在并完整:完整则提交事务;否则则回滚事务

上图1、2位置处发生崩溃,这个事务会怎么处理:

  • 上图的①时(也就是写入redo log 处于prepare阶段之后、 写binlog之前, 发生了崩溃): 由于此时binlog还没写, redo log也还没提交, 所以崩溃恢复的时候, 这个事务会回滚。

  • 时刻B发生crash对应的就是redo log中有完整prepare且binlog完整的情况:崩溃恢复过程中事务会被提交

怎么判断binlog的完整性?

  • statement 格式的 binlog,最后会有 COMMIT;

  • row 格式的 binlog,最后会有一个 XID event

另外, 在MySQL 5.6.2版本以后, 还引入了binlog-checksum参数, 用来验证binlog内容的正确性。 对于binlog日志由于磁盘原因, 可能会在日志中间出错的情况, MySQL可以通过校验checksum的结果来发现。 所以, MySQL还是有办法验证事务binlog的完整性的。

注:binlog有三种格式:statement、row和mixed(statement和row的混合)

redo log 和 binlog是怎么关联起来的?

redo logbin log 有一个共同的数据字段,叫 XID。

崩溃恢复的时候,会按顺序扫描 redo log

  • 如果碰到既有 prepare、又有 commit 的 redo log,就直接提交;

  • 如果碰到只有 parepare、而没有 commit 的 redo log,就拿着 XID 去 binlog 找对应的事务。

追问3: 处于prepare阶段的redo log加上完整binlog, 重启就能恢复, MySQL为什么要这么设计?

为什么需要判断binlog完整才认为该事务有效?即为什么需要二阶段提交?

追问4: 如果这样的话, 为什么还要两阶段提交呢? 干脆先redo log写完, 再写binlog。 崩溃恢复的时候, 必须得两个日志都完整才可以。 是不是一样的逻辑?

其实, 两阶段提交是经典的分布式系统问题, 并不是MySQL独有的,是因为MySQL需要保证 binlogredo log 两个日志的事务的同时提交和回滚。

两阶段提交是为了给所有人一个机会, 当每个人都说“我ok”的时候, 再一起提交。避免 redo log 提交了但 binlog 又写入失败了,此时 redo log 已经回滚不了的情况。

追问5: 不引入两个日志, 也就没有两阶段提交的必要了。 只用binlog来支持崩溃恢复, 又能支持归档, 不就可以了?

不可以,binlog没有能力恢复“数据页”,binlog记录的是逻辑操作,必须配合一份全量备份,然后重放binlog才能实现恢复。

追问6: 那能不能反过来, 只用redo log, 不要binlog?

不可以,因为生态问题,binlog不能被redo log替代。binlog被用在高可用系统的的复制、异构的数据分析下游系统获取数据

追问7: redo log一般设置多大?

redo log 太小会导致WAL机制的能力发挥不出来,每次数据都必须强行刷数据

如果是现在常见的几个TB的磁盘的话, 就不要太小气了, 直接将redo log设置为4个文 件、 每个文件1GB吧。

追问8: 正常运行中的实例, 数据写入后的最终落盘, 是从redo log更新过来的还是从buffer pool更新过来的呢?

从buffer pool更新过去的。实际上,redo log并没有记录数据页的完整数据,所以它并没有能力自己去更新磁盘数据页,它最多只能在crash崩溃时被读取到内存中,再用内存中的数据更新磁盘中的数据。

追问9: redo log buffer是什么? 是先修改内存, 还是先写redo log文件?

redo log buffer就是一块内存, 用来先存redo日志的。

  • 写redo log buffer:在执行第一个insert的时候, 数据的内存被修改了, redo log buffer也写入了日志。

  • 写redo log 文件:真正把志写到redo log文件(文件名是 ib_logfile+数字) , 是在执行commit语句的时候做的。

MySQL是先写数据到内存且写redo log buffer,在事务提交时只更新刷redo log文件

crash-safe能力

使用binlog恢复数据:当需要恢复到指定的某一秒时, 比如某天下午两点发现中午十二点有一次误删表, 需要找回数据, 那你可以这么做:

  1. 首先, 找到最近的一次全量备份, 如果你运气好, 可能就是昨天晚上的一个备份, 从这个备份恢复到临时库;

  2. 然后, 从备份的时间点开始, 将备份的binlog依次取出来, 重放到中午误删表之前的那个时刻。

  3. 这样你的临时库就跟误删之前的线上库一样了, 然后你可以把表数据从临时库取出来, 按需要恢复到线上库去。

使用 redo log 保证数据持久化:

有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe,保证了ACID特性的持久性。

当异常重启时,数据库根据磁盘数据和redo log对比保证数据正常。

??应该结合binlog一起讲恢复的完整过程

数据和日志更新的过程和时机

binlog的写入机制:

binlog的写入逻辑: 事务执行过程中, 先把日志写到binlog cache, 事务提交的时候, 再把binlog cache写到binlog文件中并清空binlog cache。

一个事务的binlog是不能被拆开的, 因此不论这个事务多大, 也要确保一次性写入。这也影响了binlog的cache写入机制:系统给binlog cache分配了一片内存, 每个线程一个,以保证每个事务都是一次性完整连续写入的。模型如下:

其中,每个线程都有自己的binlog cache,但是共用同一份binlog files,而且会涉及到write和fsync两个动作:

  • write: 指的就是指把日志写入到文件系统的page cache, 并没有把数据持久化到磁盘, 所以速度比较快。

  • fsync: 才是将数据持久化到磁盘的操作。 一般情况下, 我们认为fsync才占磁盘的IOPS

write 和fsync的时机, 是由参数sync_binlog控制的,它的取值有三个:

  • 0:表示每次提交事务都只write, 不fsync;

  • 1:表示每次提交事务都会执行fsync;

  • N(N>1):表示每次提交事务都write, 但累积N个事务后才fsync。

参数sync_binlog的设置:

在实际的业务场景中, 考虑到丢失日志量的可控性, 一般不建议将这个参数设成0, 比较常见的是将其设置为100~1000中的某个数值。同时,将sync_binlog设置为N的风险是: 如果主机发生异常重启, 会丢失最近N个事务的binlog日志 丢失了就不能保证持久性了啊 。

redo log的写入机制

事务在执行过程中, 生成的 redo log 会先写到 redo log buffer ,然后 write 到文件系统的page cache中,最后再 fsync 持久化到磁盘

为了控制redo log的写入策略, InnoDB提供了innodb_flush_log_at_trx_commit参数, 它有三种可能取值:

  • 0: 表示每次事务提交时都只是把redo log留在redo log buffer中;

  • 1:表示每次事务提交时都将redo log直接持久化到磁盘;

  • 2:表示每次事务提交时都只是把redo log写到page cache。

同时InnoDB有一个后台线程, 每隔1秒, 就会把redo log buffer中的日志, 调用write写到文件系统的page cache, 然后调用fsync持久化到磁盘。(不管上面的innodb_flush_log_at_trx_commit参数设置为何值,这个后台线程都会这样执行)

被顺道持久化到磁盘的redo log怎么处理?

有三种场景会让一个没有提交的事务的redo log写入到磁盘中:

  • redo log buffer占用的空间即将达到 innodb_log_buffer_size一半的时候,后台线程会主动写盘。 注意, 由于这个事务并没有提交, 所以这个写盘动作只是write, 而没有调用fsync, 也就是只留在了文件系统的page cache。

  • 并行的事务提交的时候, 顺带将这个事务的redo log buffer持久化到磁盘。 假设一个事务A执行到一半, 已经写了一些redo log到buffer中, 这时候有另外一个线程的事务B提交, 如果innodb_flush_log_at_trx_commit设置的是1, 那么按照这个参数的逻辑, 事务B要把redo log buffer里的日志全部持久化到磁盘。 这时候, 就会带上事务A在redo log buffer里的日志一起持久化到磁盘。

  • InnoDB后台线程每隔1秒, 就会把redo log buffer中的日志, 调用write写到文件系统的page cache, 然后调用fsync持久化到磁盘。

以上redo log怎么处理?redo log是有prepare状态和commit状态的,它commit状态或prepare状态+完整binlog日志的事务日志才会提交。

配置建议:双一配置

  • redo log用于保证crash-safe能力。 innodb_flush_log_at_trx_commit这个参数设置成1的时候,表示每次事务的redo log都直接持久化到磁盘。 这个参数我建议你设置成1, 这样可以保证MySQL异常重启之后数据不丢失。

  • sync_binlog这个参数设置成1的时候, 表示每次事务的binlog都持久化到磁盘。 这个参数我也建议你设置成1, 这样可以保证MySQL异常重启之后binlog不丢失。

双一配置下,一个事务完整提交前, 需要等待两次刷盘, 一次是redo log(prepare 阶段) , 一次是binlog

一天一备跟一周一备的对比。

好处是“最长恢复时间”更短。在一天一备的模式里, 最坏情况下需要应用一天的binlog。 比如, 你每天0点做一次全量备份,而要恢复出一个到昨天晚上23点的备份,一周一备最坏情况就要应用一周的binlog了。

系统的对应指标是:RTO(恢复目标时间。当然这个是有成本的, 因为更频繁全量备份需要消耗更多存储空间, 所以这个RTO是成本换来的, 就需要你根据业务重要性来评估了。

参考文章:

浅谈mysql的两阶段提交协议 MySQL实战45讲——丁奇

  • 02 | 日志系统: 一条SQL更新语句是如何执行的?

  • 15 | 答疑文章(一) : 日志和索引相关问题

  • 23 | MySQL是怎么保证数据不丢的?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/134330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DDR3 数据传输 (五)

目录 引言 设计说明 参数说明 设计简图 IP配置说明 写FIFO IP

在linux上使用CMake构建和安装gtest

在linux上使用CMake构建和安装gtest一、准备工作二、构建并安装gtest的静态库三、构建并安装gtest的共享库一、准备工作 本机环境: 系统版本:RHEL 7.6GCC/G版本: 12.1.1googletest版本:1.12.1 注意,gtest的1.12.x分…

基于准则匹配的图像对准

一、概述 在图像处理相关的问题中,图像对准是一类典型的问题,也就是要将两幅图严丝合缝地对应起来。通常来讲,两幅图大小不一,一个是模板,一个是母图,也就是要在母图中搜寻定位到与模板图最为接近的区域。 …

QML教程(七) JavaScript

目录 一、对属性值使用 JavaScript 表达式 二、在 QML 中添加 JavaScript 函数 三、使用 JavaScript 文件 四、属性绑定中的 JavaScript 五、信号处理程序中的 JavaScript 六、将信号连接到 JavaScript 函数 七、启动执行 JavaScript QML 提供的 JavaScript 主机环境可以…

算法学习-并查集(持续更新中)

本文参考: 最容易理解的并查集详解 详解:并查集(Union-Find) 「代码随想录」684. 冗余连接:【并查集基础题目】详解! 并查集从入门到出门 并查集常常在做图相关的题目时冒出来,但是笔者经常去回避这样的解法…

Exynos_4412——轮询与中断

目录 一、CPU与硬件的交互方式 1.1轮询 1.2中断 1.3DMA 二、轮询方式的按键实验 三、GPIO中断相关寄存器 四、GPIO中断编程 五、小作业 一、CPU与硬件的交互方式 1.1轮询 CPU执行程序时不断地询问硬件是否需要其服务,若需要则给予其服务,若不需…

Android Jetpack Compose——一个简单的微信界面

一个简单的微信界面简述效果视频底部导航栏导航元素导航栏放入插槽绘制地图消息列表效果图实现聊天效果图实现气泡背景联系人界面效果图实现好友详情效果图实现发现效果图实现未读红点未读条数朋友圈效果图实现上拉加载个人设置效果图实现个人信息功能区钱包效果图实现切换主题…

【Vue】项目搭建规范

1. 集成editorconfig配置 EditorConfig 有助于为不同 IDE 编辑器上处理同一项目的多个开发人员维护一致的编码风格。 VSCode需要安装一个插件:EditorConfig for VS Code 创建 .editorconfig 文件: # http://editorconfig.orgroot true[*] # 表示所有文…

js Proxy 的使用

文章目录一、什么是Proxy二、语法三、Proxy 方法1、get() 方法2、set() 方法3、apply() 方法4、has() 方法5、construct() 方法6、deleteProperty() 方法一、什么是Proxy Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问&#xff…

[Vulnhub] DC-2

Vlunhub下DC系列靶机第二台,难度与DC-1 差不多,为简单。共有五个Flag 下载地址:Vulnhub:DC-2 目录 信息搜集 cewl爬行网站字典&hydra爆破wordpress用户密码 -rbash逃逸 git提权 信息搜集 nmap -sP 192.168.236.0/24 扫描一下靶机i…

c++语法欠缺地方(持续更新)

sizeof是用来计算变量占多大内存的,单位是字节(byte);sizeof 后面跟类型时,必须加上括号,例如sizeof(double);后面跟变量可以不用加括号,例如:sizeof d %d是以十进制形式输出有符号…

hadoop之kerberos权限配置(ranger基础上)(三)

文章目录一、kerberos服务端二、kerberos客户端三、hadoop集群安装HTTPS服务四、kerberos整合zk五、kerberos整合ranger六、kerberos整合hdfs七、kerberos整合yarn八、kerberos整合hive九、kerberos整合hbase十、遇到的问题一、kerberos服务端 上传kerberos安装包到/opt/rpm 安…

数据库,计算机网络、操作系统刷题笔记22

数据库,计算机网络、操作系统刷题笔记22 2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得去找开发,测开 测开的话,你就得学数据库,sql,oracle…

最值得推荐的3个免费PDF 转换器

当您需要将 PDF 转换为另一种格式(如 Microsoft Word、图像(如 JPG)、Excel、电子书、PowerPoint 等,反之亦然)时,最好的 PDF 转换器非常重要。 但是找到一个可靠的 PDF 转换软件来使用是具有挑战性的。因…

JAVA设计模式--行为型模式--策略模式

1.策略模式(Strategy Pattern) 1.1介绍 一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对…

【C++】网络编程(TCPUDP)

网络编程是C API操作中很重要的一部分,包含TCP和UDP。 网络传输模型可以抽象为7个层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。 但在使用TCP/IP协议时,可以简化为这4层:网络接口、网络层、传输层、应用层。…

物理层基本概念

目录物理层的基本概念物理层传输方式串行传输并行传输同步传输异步传输单向通信(单工)双向交替通信(半双工)双向同时通信(全双工)编码与调制常用编码基本调制方法信道极限容量物理层的基本概念 物理层考虑的…

路由 OSPF常见4种网络类型MA、P2P、NBMA、P2MP、OSPF报头字段信息简介。

4.2.1 路由 OSPF(OSPF常见4种网络类型、OSPF报头信息) 目录OSPF常见的4种网络类型广播类型(Broadcast 或 MA)P2PNBMAP2MPOSPF报文发送形式对于不同OSPF网络类型的组网OSPF报头信息实际抓包分析OSPF常见的4种网络类型 OSPF应用于不…

Kali最强渗透工具- metasploit

数据来源 本文仅用于信息安全学习,请遵守相关法律法规,严禁用于非法途径。若观众因此作出任何危害网络安全的行为,后果自负,与本人无关。 metasploit是什么? msf是一款开源安全漏洞利用和测试工具,集成了…

C++GUI之wxWidgets(9)-编写应用涉及的类和方法(4)-事件处理(3)

目录动态事件处理如何处理事件事件如何向上传播事件处理程序链动态事件处理 void MyFrameHandler::OnFrameExit(wxCommandEvent&) {// Do something useful. }MyFrameHandler myFrameHandler;MyFrame::MyFrame() {Bind(wxEVT_MENU, &MyFrameHandler::OnFrameExit,&…