当前位置:

首页 > 编程开发 > MySQL日志之redo log和undo log实例分析

MySQL日志之redo log和undo log实例分析

RedoLogREDOLOG称为重做日志,当MySQL服务器意外崩溃或者宕机后,保证已经提交的事务持久化到磁盘中(持久性)。InnoDB是以页为单位去操作记录的,增删改查都会加载整个页到bufferpool中(磁盘->内存),事务中的修改操作并不是直接修改磁盘中的数据,而是先修改内存中bufferpool中的数据,后台线程每隔一段时间再异步刷新到磁盘中。bufferpool:可存放索引、数据,可加速读写,直接在内存中操作数据页,有专门的线程去把bufferpool中的脏页写入磁盘。为什么不直接修改磁盘中的

    Redo Log

    REDO LOG称为重做日志 ,当MySQL服务器意外崩溃或者宕机后,保证已经提交的事务持久化到磁盘中(持久性)。

    InnoDB是以页为单位去操作记录的,增删改查都会加载整个页到buffer pool中(磁盘->内存),事务中的修改操作并不是直接修改磁盘中的数据,而是先修改内存中buffer pool中的数据,后台线程每隔一段时间再异步刷新到磁盘中。

    buffer pool:可存放索引、数据,可加速读写,直接在内存中操作数据页,有专门的线程去把buffer pool中的脏页写入磁盘。

    为什么不直接修改磁盘中的数据?

    因为直接修改磁盘数据的话,它是随机IO,修改的数据分布在磁盘中不同的位置,需要来回的查找,所以命中率低,消耗大,而且一个小小的修改就不得不将整个页刷新到磁盘,利用率低;

    与之相对的是顺序IO,磁盘的数据分布在磁盘的一块,所以省去了查找的过程,节省寻道时间。

    使用后台线程以一定的频率去刷新磁盘可以降低随机IO的频率,增加吞吐量,这是使用buffer pool的根本原因。

    修改内存再异步同步到磁盘的问题:

    因为buffer pool是在内存中的区域,系统意外崩溃的话数据有可能会丢失,有些脏数据可能会来不及刷新到磁盘,事务的持久性得不到保证。因此,引入了redo log。修改数据时,额外记录一次日志,内容是xx页xx偏移量发生了xx变化,当系统崩溃时可以根据日志内容进行恢复。

    写日志和直接刷新磁盘的区别是:写日志是追加写入,顺序IO,速度更快,且写入的内容相对更小

    redo log由两部分组成:

    1. redo log buffer(内存层面,默认16M,通过innodb_log_buffer_size参数可修改)

    2. redo log file(持久化的,磁盘层面)

    修改操作大致过程:

    MySQL日志之redo log和undo log实例分析

    第1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝,产生脏数据

    第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值

    第3步:默认在事务提交后将redo log buffer中的内容刷新到redo log file,对redo log file采用追加写的方式

    第4步:定期将内存中修改的数据刷新到磁盘中(这里说的是那些还没及时被后台线程刷盘的脏数据)

    通常所说的Write-Ahead Log(预先日志持久化)指的是在持久化一个数据页之前,先将内存中相应的日志页持久化。

    redo log的好处:

    • 减少了磁盘刷新频率

    • redo log占用空间小

    • redo log写入速度快

    redo log一定能保证事务的持久性吗?

    不一定,这要根据redo log的刷盘策略决定,因为redo log buffer同样是在内存中,如果提交事务之后,redo log buffer还没来得及将数据刷新到redo log file进行持久化,此时发生宕机照样会丢失数据。如何解决?刷盘策略。

    redo log刷盘策略

    InnoDB中给出了innodb_flush_log_at_trx_commit参数控制redo log buffer刷新到redo log file时的三种策略:

    • 值为0:开启一个后台线程,每1s刷新一次到磁盘中,提交事务时就不需要进行刷新了

    • 值为1:commit时再进行同步刷新(默认值),真正保证数据的持久性

    • 值为2:commit的时候,只是刷新进os的内核缓冲区,具体的刷盘时机不确定

    值为0的情况:

    MySQL日志之redo log和undo log实例分析

    因为有1s的间隔,所以最坏情况下会丢失1秒的数据。

    值为1的情况:

    MySQL日志之redo log和undo log实例分析

    commit时需要先主动刷新redo log buffer到redo log file,如果中途宕机了,事务也就失败了,不会有任何损失,真正能保证事务的持久性。但是效率最差。

    值为2的情况:是根据os决定。

    可以调整为0或2提高事务的性能,但是丧失了ACID特性

    其他参数

    • innodb_log_group_home_dir:指定 redo log文件组所在的路径,默认值为 ./ ,表示在数据库的数据目录下。MySQL的默认数据目录下默认有两个名为ib_logfile0和ib_logfile1的文件,log buffer中的日志默认情况下就是刷新到这两个磁盘文件中。

    • innodb_log_files_in_group:指明redo log file的个数,命名方式如:ib_logfile0,iblogfile1... iblogfilen。默认2个,最大100个。

    • innodb_log_file_size:单个 redo log 文件设置大小,默认值为 48M 。

    Undo Log

    undo log用于保证事务的原子性和一致性。作用有两个:①提供回滚操作 ②多版本控制MVVC

    回滚操作

    前面redo log中说过,后台线程会不定时的去刷新buffer pool中的数据到磁盘,但是如果该事务执行期间出现各种错误(宕机)或者执行rollback语句,那么前面刷进去的操作都是需要回滚的,保证原子性,undo log就是提供事务回滚的。

    MVVC

    当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据——快照读。

    快照读:SQL读取的数据是历史版本,不用加锁,普通的SELECT就是快照读。

    undo log的组成部分:

    • 当insert记录的时候,必须将该记录的主键值记录下来,这样才可以回滚时删除该数据。

    • 当update记录的时候,必须将修改的旧值全部记录下来,回滚时更新为旧值即可。

    • 当delete的时候,必须将所有的记录都记录下来,回滚时再重新插入该内容的记录。

    select操作不会产生undo log

    回滚段与undo页

    在InnoDB存储引擎中,undo log使用rollback segment回滚段进行存储,每隔回滚段包含了1024个undo log segment。 MySQL5.5之后,一共有128个回滚段。即总共可以记录128 * 1024个undo操作。

    每个事务只会使用一个回滚段,一个回滚段在同一时刻可能会服务于多个事务。

    事务提交后不能立即删除该undo log,可能有些事务会想要读取之前的数据版本(快照读)。所以事务提交时将undo log放入一个链表中,称为版本链,undo log的删除与否由一个称为purge的线程判断。

    Undo类型

    undo log分为:

    insert undo log

    因为insert操作的记录,只对事务本身可见,对其他事务不可见(这是事务隔离性的要求),故该undo log可以在事务提交后直接删除。不需要进行purge操作。

    update undo log

    update undo log记录的是对delete和update操作产生的undo log。该undo log可能需要提供MVCC机制,因此不能在事务提交时就进行删除。提交时放入undo log链表,等待purge线程进行最后的删除。

    undo log的生命周期

    假设有2个数值,分别为A=1和B=2,然后某个事务将A修改为3,B修改为4,修改过程可简化为:

    1.begin
    2.记录A=1到undo log
    3.update A=3
    4.记录A=3到redo log
    5.记录B=2到undo log
    6.update B=4
    7.记录B=4到redo log
    8.将redo log刷新到磁盘
    9.commit

    • 在1-8步骤的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。

    • 如果在8-9之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时redo log已经持久化。

    • 若在9之后系统宕机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据redo log把数据刷回磁盘。

    MySQL日志之redo log和undo log实例分析

    详细生成过程

    对于InnoDB引擎来说,每个行记录除了记录本身的数据之外,还有几个隐藏的列:

    • DB_ROW_ID∶记录的主键id。

    • DB_TRX_ID:事务ID,当对某条记录发生修改时,就会将这个事务的Id记录其中。

    • DB_ROLL_PTR︰回滚指针,版本链中的指针。

    MySQL日志之redo log和undo log实例分析

    当我们执行INSERT时:

    begin;
    INSERT INTO user (name) VALUES ('tom');

    插入的数据都会生成一条insert undo log,并且数据的回滚指针会指向它。undo log会记录undo log的序号、插入主键的列和值...,那么在进行rollback的时候,通过主键直接把对应的数据删除即可。

    MySQL日志之redo log和undo log实例分析

    当我们执行UPDATE时:

    对于更新的操作会产生update undo log,并且会分更新主键的和不更新主键的,假设现在执行:

    UPDATE user SET name='Sun' WHERE id=1;

    MySQL日志之redo log和undo log实例分析

    这时会把新的undo log记录加入到版本链中,它的undo no是1,并且新的undo log的回滚指针会指向老的undo log (undo no=0)。

    假设现在执行:

    UPDATE user SET id=2 WHERE id=1;

    MySQL日志之redo log和undo log实例分析

    对于更新主键的操作,会先把原来的数据deletemark标识打开,这时并没有真正的删除数据,真正的删除会交给清理线程去判断,然后在后面插入一条新的数据,新的数据也会产生undo log,并且undo log的序号会递增。

    可以发现每次对数据的变更都会产生一个undo log,当一条记录被变更多次时,那么就会产生多条undo log,undo log记录的是变更前的日志,并且每个undo log的序号是递增的,那么当要回滚的时候,按照序号依次向前推,就可以找到我们的原始数据了。

    undo log是如何回滚的

    以上面的例子来说,假设执行rollback,那么对应的流程应该是这样:

    1. 通过undo no=3的日志把id=2的数据删除

    2. 通过undo no=2的日志把id=1的数据的deletemark还原成0

    3. 通过undo no=1的日志把id=1的数据的name还原成Tom

    4. 通过undo no=0的日志把id=1的数据删除

    MySQL MVVC多版本并发控制

    扩展

    bin log

    binlog即binary log,二进制日志文件,也叫作变更日志(update log)。它记录了数据库所有执行的更新语句。

    binlog主要应用场景:

    • 数据恢复:如果MySQL意外停止,可以通过该日志进行恢复、备份

    • 数据复制:master把它的二进制日志传递给slaves来达到master-slave数据的一致性

    show variables like '%log_bin%';

    查看bin log日志:

    mysqlbinlog -v "/var/lib/mysql/binlog/xxx.000002"

    使用日志恢复数据:

    mysqlbinlog [option] filename|mysql –uuser -ppass;

    删除二进制日志:

    PURGE {MASTER | BINARY} LOGS TO ‘指定日志文件名'
    PURGE {MASTER | BINARY} LOGS BEFORE ‘指定日期'

    写入时机

    事务执行过程中,先把日志写到bin log cache ,事务提交的时候,再把binlog cache写到binlog文件中。因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。

    MySQL日志之redo log和undo log实例分析

    binlog与redo log对比

    • redo log是物理日志,记录内容是“在xx数据页做了xx修改”,属于InnoDB存储引擎层产生的。

    • 而binlog是逻辑日志,记录内容是语句的原始逻辑,类似于给ID=2这一行的c字段加1,属于服务层。

    两个侧重点也不同, redo log让InnoDB有了崩溃恢复的能力,binlog保证了MySQL集群架构的数据一致性。

    两阶段提交

    在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机不一样。

    MySQL日志之redo log和undo log实例分析

    redo log与binlog两份日志之间的逻辑不一致,会出现什么问题?

    以update语句为例,假设id=2的记录,字段c值是0,把字段c值更新成1,SQL语句为update T set c=1 where id=2。

    假设执行过程中写完redo log日志后,binlog日志写期间发生了异常,会出现什么情况呢?

    MySQL日志之redo log和undo log实例分析

    由于binlog没写完就异常,这时候binlog里面没有对应的修改记录。因此,之后用binlog日志恢复数据或者slave读取master的binlog时,就会少这一次更新,恢复出来的这一行c值是0,而原库因为redo log日志恢复,这一行c值是1,最终数据不一致。

    MySQL日志之redo log和undo log实例分析

    为了解决两份日志之间的逻辑一致问题,InnoDB存储引擎使用两阶段提交方案。将redo log拆成了两个步骤prepare和commit,这就是两阶段提交。

    让redo log和bin log最终的提交绑定到一起,前面说过的,事务commit时默认需要让redo log先同步完才算commit成功,所以如果绑定到一起的话,bin log也具有该特性了,就保证了数据不会丢失。

    MySQL日志之redo log和undo log实例分析

    使用两阶段提交后,写入binlog时发生异常也不会有影响,因为MySQL根据redo log日志恢复数据时发现redo log还处于prepare阶段,并且没有对应binlog日志,就会提交失败,回滚数据。

    MySQL日志之redo log和undo log实例分析

    另一个场景,redo log的commit阶段发生异常,那会不会回滚事务呢?

    MySQL日志之redo log和undo log实例分析

    并不会回滚事务,它会执行上图框住的逻辑,虽然redo log是处于prepare阶段,但是能通过事务id找到对应的binlog日志,所以MySQL认为是完整的,就会提交事务恢复数据。

    本文内容来源于互联网,如有侵权请联系删除。
    作者最新文章
    编程开发
    相关文章 更多
    using namespace 使用中遇到的问题怎么解决
    using namespace 使用中遇到的问题怎么解决

    命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

    c语言函数递归 实操经验总结:这些技巧很实用
    c语言函数递归 实操经验总结:这些技巧很实用

    理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接

    c语言函数递归 怎么选?常见方案对比分析
    c语言函数递归 怎么选?常见方案对比分析

    递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的

    Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
    Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解

    理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的

    如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
    如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏

    理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de

    深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制
    深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制

    内存管理的基石在Objective-C的世界里,内存管理是开发者必须掌握的核心技能之一。作为一门在手动引用计数(MRC)时代诞生的语言,Objective-C要求程序员对对象的生命周期有清晰的认识。dealloc方法正是这一生命周期中至关重要的终点站。它是一个实例方法,当对象的引用计数降为零时,系统

    理解 native2ascii:Java 国际化开发中的字符编码工具
    理解 native2ascii:Java 国际化开发中的字符编码工具

    native2ascii 工具的基本定位在Ja va应用程序的国际化与本地化开发过程中,处理非拉丁字符集是一个常见且关键的环节。Ja va内部使用Unicode字符集来统一表示全球各种语言的文字,但其属性文件(.properties)在历史上要求使用ASCII编码,或者更准确地说,要求非ASCII字

    如何使用 native2ascii 转换中文字符为 Unicode 转义序列
    如何使用 native2ascii 转换中文字符为 Unicode 转义序列

    理解 native2ascii 工具的基本用途在软件开发,特别是涉及国际化处理的场景中,开发者常常需要处理不同编码的文本资源。native2ascii 是 Ja va 开发工具包(JDK)中提供的一个命令行实用程序,其主要功能是将包含本地字符编码(非ASCII字符)的文件,转换为包含 Unicode

    Java native2ascii 命令详解:解决属性文件乱码问题
    Java native2ascii 命令详解:解决属性文件乱码问题

    native2ascii 命令的由来与作用在Ja va开发中,处理国际化资源文件是一个常见需求。资源文件通常以.properties格式存储,用于支持多语言界面。然而,Ja va属性文件默认采用ISO-8859-1字符集编码,这导致了一个直接的问题:当文件中包含非拉丁字符(如中文、日文、韩文等)时,

    一个 memwatch 实战案例:定位野指针问题
    一个 memwatch 实战案例:定位野指针问题

    内存监控工具的价值与挑战在软件开发,尤其是使用C/C++这类手动管理内存的语言时,内存错误是程序员最常遭遇的难题之一。其中,野指针问题因其隐蔽性和破坏性,往往成为最难定位的“幽灵”缺陷。它可能潜伏在代码中,在特定条件下才被触发,导致程序崩溃、数据损坏或难以预测的行为。传统的调试手段,如打印日志或使用

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    macOS软件
    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    Mac软件 更多
    灵活计算器
    灵活计算器
    macOS/iOS/Android

    灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

    赤友清理大师
    赤友清理大师
    macOS

    赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

    极度公式
    极度公式
    Windows/macOS/Linux

    极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

    WINDOWS 更多
    Windows 10
    Windows 10
    Windows

    Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

    极度公式
    极度公式
    Windows/macOS/Linux

    极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

    密码键盘
    密码键盘
    Windows/macOS/iOS/Android

    密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。