精华内容
下载资源
问答
  • redo log
    2022-03-27 10:54:36

    1.redo日志

    事务有4种特性:原子性、一致性、隔离性和持久性。那么事务的四种特性到底是基于什么机制实现呢?
    事务的隔离性由锁机制实现。
    而事务的原子性、一致性和持久性由事务的 redo 日志和undo 日志来保证。
    REDO LOG 称为重做日志,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性
    UNDO LOG 称为回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性
    有的DBA或许会认为 UNDO 是 REDO 的逆过程,其实不然。

    1.1 为什么需要REDO日志

    一方面,缓冲池可以帮助我们消除CPU和磁盘之间的鸿沟,checkpoint机制可以保证数据的最终落盘,然而由于checkpoint 并不是每次变更的时候就触发的,而是master线程隔一段时间去处理的。所以最坏的情况就是事务提交后,刚写完缓冲池,数据库宕机了,那么这段数据就是丢失的,无法恢复。另一方面,事务包含持久性的特性,就是说对于一个已经提交的事务,在事务提交后即使系统发生了崩溃,这个事务对数据库中所做的更改也不能丢失。
    MySQL 在更新数据时,为了减少磁盘的随机 IO,因此并不会直接更新磁盘上的数据,而是先更新 Buffer Pool 中缓存页的数据,等到合适的时间点,再将这个缓存页持久化到磁盘。而 Buffer Pool 中所有缓存页都是处于内存当中的,当 MySQL 宕机或者机器断电,内存中的数据就会丢失,因此 MySQL 为了防止缓存页中的数据在更新后出现数据丢失的现象,引入了 redo log 机制。
    那么如何保证这个持久性呢? 一个简单的做法:在事务提交完成之前把该事务所修改的所有页面都刷新到磁盘,但是这个简单粗暴的做法有些问题另一个解决的思路:我们只是想让已经提交了的事务对数据库中数据所做的修改永久生效,即使后来系统崩溃,在重启后也能把这种修改恢复出来。所以我们其实没有必要在每次事务提交时就把该事务在内存中修改过的全部页面刷新到磁盘,只需要把修改了哪些东西记录一下就好。比如,某个事务将系统
    表空间中第10号页面中偏移量为100 处的那个字节的值 1 改成2 。我们只需要记录一下:将第0号表空间的10号页面的偏移量为100处的值更新为 2 。

    1.2 REDO日志的好处、特点

    1. 好处

    • redo日志降低了刷盘频率
    • redo日志占用的空间非常小
      2. 特点
    • redo日志是顺序写入磁盘的
    • 事务执行过程中,redo log不断记录

    1.3 redo的组成

    Redo log可以简单分为以下两个部分:

    • 重做日志的缓冲 (redo log buffer) ,保存在内存中,是易失的。
    • 重做日志文件 (redo log file) ,保存在硬盘中,是持久的。
      参数设置:innodb_log_buffer_size:
      redo log buffer 大小,默认16M ,最大值是4096M,最小值为1M。
      重做日志文件 (redo log file) ,保存在硬盘中,是持久的。
    mysql> show variables like '%innodb_log_buffer_size%';
    +------------------------+----------+
    | Variable_name | Value |
    +------------------------+----------+
    | innodb_log_buffer_size | 16777216 |
    +------------------------+----------+
    

    1.4 redo的整体流程

    在这里插入图片描述
    在这里插入图片描述

    第1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
    第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
    第3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加 写的方式
    第4步:定期将内存中修改的数据刷新到磁盘中
    体会:
    Write-Ahead Log(预先日志持久化):在持久化一个数据页之前,先将内存中相应的日志页持久化。
    将 redo log 日志标记为 prepare 状态和 commit 状态,这种做法称之为两阶段事务提交,它能保证事务在提交后,数据不丢失。为什么呢?redo log 在进行数据重做时,只有读到了 commit 标识,才会认为这条 redo log 日志是完整的,才会进行数据重做,否则会认为这个 redo log 日志不完整,不会进行数据重做。
    例如,如果在 redo log 处于 prepare 状态后,buffer pool 中的缓存页(脏页)也还没来得及刷入到磁盘,写完 biglog 后就出现了宕机或者断电,此时提交的事务是失败的,那么在 MySQL 重启后,进行数据重做时,在 redo log 日志中由于该事务的 redo log 日志没有 commit 标识,那么就不会进行数据重做,磁盘上数据还是原来的数据,也就是事务没有提交,这符合我们的逻辑。
    实际上要严格保证数据不丢失,必须得保证 innodb_flush_log_at_trx_commit 配置为 1。

    1.5 redo log的刷盘策略

    redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后以一定的频率刷入到真正的redo log file 中。这里的一定频率怎么看待呢?这就是我们要说的刷盘策略。
    注意,redo log buffer刷盘到redo log file的过程并不是真正的刷到磁盘中去,只是刷入到文件系统缓存(page cache)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正的写入会交给系统自己来决定(比如page cache足够大了)。那么对于InnoDB来说就存在一个问题,如果交给系统来同步,同样如果系统宕机,那么数据也丢失了(虽然整个系统宕机的概率还是比较小的)。

    针对这种情况,InnoDB给出innodb_flush_log_at_trx_commit 参数,该参数控制 commit提交事务时,如何将 redo log buffer 中的日志刷新到 redo log file 中。它支持三种策略:

    设置为0 :表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次重做日 志的同步)
    设置为1:表示每次事务提交时都将进行同步,刷盘操作( 默认值)
    设置为2 :每次事务提交时mysql都会把log buffer的数据写入log file,但是flush(刷到磁盘)操作并不会同时进行。该模式下,MySQL会每秒执行一次 flush(刷到磁盘)操作

    有了redo log,当数据库发生宕机重启后,可通过redo log将未落盘的数据恢复,即保证已经提交的事务记录不会丢失。

    更多相关内容
  • 文章目录一、MySQL日志文件类型二、几种日志的对比2-1、用途 redo log undo log binlog2-2、存储内容、格式 redo log undo log binlog2-3、日志生成 redo log undo log binlog2-4、删除策略 redo log ...
  • Oracle DG下修改redo log和standby redo log日志大小.txt
  • 43 直接强行把redo log写入磁盘?非也,揭秘redo log buffer.pdf
  • 44 redo log buffer中的缓冲日志,到底什么时候可以写入磁盘?l.pdf
  • 研究基于Redo log复制技术的数据库复制软件原理。结合模拟常用系统环境进行方案设计的试验,得出基于Redo log复制技术的数据库备份方式,不仅具有高效的资源利用、跨平台数据库同步、主备库双活、断点续传等功能,...
  • 前面文章讲述了 MySQL 系统中常见的几种日志,其实还有事务相关日志 redo log 和 undo log 没有介绍。相对于其他几种日志而言, redo log 和 undo log 是更加神秘,难以观测的。本篇文章将主要介绍这两类事务日志的...
  • MySQL数据库之undo logredo log工作原理.png,这是一份图例,画图表示undo logredo log的工作原理
  • 本文介绍了两种迁移redo log的方式:1.停止数据库实例迁移redo log;2.在线迁移redo log
  • 42 redo log是直接一条一条写入文件的吗?非也,揭秘redo log block.pdf
  • redo log 是innerDB独有的,下文的逻辑默认MySQL使用了innerDB引擎哈) 当MySQL事务提交时,首先会把数据写入缓存,也就是redo log buffer,调用了一个函数叫做WriteRedoLog。这个是每次事务提交都必须要写入的。 ...

    《朱子语类》里面有句话:“知其然知其所以然!”,笔下回曰:“然也!” 。

     前两天看到一张图,应该是大学毕业不久后保存的,很现实,当然,也有点黑色幽默的感觉,一起来看一看。

    感慨什么的,就不吐槽了,过去的生活中或许会有遗憾,未来的日子里都会充满期待与幻想,不过么,数风流人物,还看今朝!

    干了这碗鸡汤,咱们继续。MySQL数据库,大家很早应该就接触到了,毕竟数据存储,是一切业务必不可少的阶段。而MySQL的写入操作,都离不开事务这个东东,当然也不离开redo log这个“中间商”。

    数据存储自然是持久的,大家用最朴实的思想想一下,也明白,数据最终一定是存储到了磁盘里面。

                    

    笔下要把“个人精通java字符串的编写!”这句话写到磁盘的文件中,首先是在JVM堆中创建一个字符串,然后写入到“简历.txt”中,历程如下:

                    

    先从应用程序缓存到OS缓存,再到磁盘,而且,把这句话写入文件中还是非常快的。但是,如果磁盘中已经有了数万乃至数十万的文件数据,用户突然对其中的某一条或者某几条数据进行写操作,那样速度还会很快么?定位数据的位置,分配空间之类的估计就会话费不少的时间。 从度娘那里截了个图,大家可以瞅瞅,有兴趣的话,可以深入下,这里就不重点说了。

    对于MySQL来说,每次对数据库file文件的修改都是一次事务,当然直接一句insert 或 update后台就默认帮你提交了,不需要你关注那么多细节,而且这种简单的事务几乎不存在事务并发问题,毕竟耗时短,提交快,而且总有一个先后(下面说为什么有先后)。

    那么复杂的事务呢?MySQL是如何做到高速读写,不仅实现事务的提交回滚,而且可以保证数据的一致性呢?我们模拟个事务并发来看看。

    首先建立一张简单的数据表:

    
    CREATE TABLE `student`  (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
      `stu_name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '学生姓名',
      `stu_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '学生编号',
      `school_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '学校编码',
      `create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      PRIMARY KEY (`id`) USING BTREE,
      INDEX `idx_code`(`stu_code`) USING BTREE COMMENT '学生编码索引'
    ) ENGINE = InnoDB AUTO_INCREMENT = 22 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci COMMENT = '学生表' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of student
    -- ----------------------------
    INSERT INTO `student` VALUES (23, '张三1', 'ce1482d6b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (24, '张三2', 'ce14a163b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (25, '张三3', 'ce14b888b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (26, '张三4', 'ce14ebb6b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (27, '张三5', 'ce151bc1b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (28, '张三6', 'ce1538d0b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (29, '张三7', 'ce155866b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (30, '张三8', 'ce1578beb2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (31, '张三9', 'ce1591b5b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (32, '张三10', 'ce15ac92b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (33, '张三11', 'ce15c86ab2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (34, '张三12', 'ce15e20eb2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (35, '张三13', 'ce15fa18b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (36, '张三14', 'ce1612cab2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (37, '张三15', 'ce1628e3b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (38, '张三16', 'ce163cedb2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (39, '张三17', 'ce16524bb2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (40, '张三18', 'ce166a5fb2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (41, '张三19', 'ce1680fbb2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (42, '张三20', 'ce169964b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (43, '张三21', 'ce16b0b9b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (44, '张三22', 'ce16c723b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (45, '张三23', 'ce16decab2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (46, '张三24', 'ce170106b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (47, '张三25', 'ce171d10b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (48, '张三26', 'ce173b93b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (49, '张三27', 'ce1759e3b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');
    INSERT INTO `student` VALUES (50, '张三28', 'ce177224b2d211ebaa2abce92fdc3ad6', '20', '2021-05-12 11:33:24');

     启动事务一(操作的数据id是34):

    start transaction;
    
    select * from student where stu_code = 'ce15e20eb2d211ebaa2abce92fdc3ad6';
    update student set school_code = 30 where stu_code ='ce15e20eb2d211ebaa2abce92fdc3ad6';
    -- update student set school_code = 40 where stu_code ='ce15e20eb2d211ebaa2abce92fdc3ad6';
    select * from student where stu_code = 'ce15e20eb2d211ebaa2abce92fdc3ad6';
    commit;

    可以看到最后查询的 school_code = 30 ,再启动事务2: 

    start transaction;
    
    select * from student where stu_code = 'ce15e20eb2d211ebaa2abce92fdc3ad6';
    update student set school_code = 50 where stu_code = 'ce15e20eb2d211ebaa2abce92fdc3ad6';
    

    我们可以看到school_code = 20,而且,修改的操作陷入了等待,也就是一直在执行中。也就是说发生了事务并发,触发了行锁,事务2进入了锁等待。

    此时对于数据库来说school_code = 20,对于事务1来说,school_code = 30。如果事务一提交,那么事务二修改完成后,再查询,school_code = 50

    在启动一个事务三,如果仅仅事务一提交,查询的话结果也是school_code = 30;

    start transaction;
    select * from student where stu_code = 'ce15e20eb2d211ebaa2abce92fdc3ad6';

    说到这里,就不得不说下MySQL的一个机制了,MVCC(Multi-Version Concurrency Control ),也就是多版本并发控制。

    事物的隔离级别分为Read uncommitted,Read committed,Repeatable read,Seralizable这四种,Mysql在可重复读隔离级别下保证事务较高的隔离性,其中必不可少的机制就是MVCC!其中一个重要部分就是undo log!

                    

    undo log实际上是就是一个日志版本链,比如,某一行数据被多个事务进行了修改,那么每次修改都会记录一个undo log 回滚日志,如果某次修改最终rollback了,那么就根据undo log日志,进行数据回滚。每条undo log 有三个关键字段,row_id、trx_id和roll_pointer,也就是该条数据主键id、事务的id和这条数据上一个版本的指针,通过事务id将undo log 串联成一个历史记录版本链,那么,事务的任何SQL查询结果从对应版本链里的最新数据开始逐条对比从而获取最终的快照结果。

    根据上面的两个事务,衍生一个undo log版本链。

    通俗的说下,就是在当前事务进行查询的时候,从当前记录向上查找,直到找到当前数据的提交的那条undo log,在这段记录中,如果没有本事务对该条数据的操作,那么就返回已经提交的数据,如果有当前事务对这条数据的修改,那么久返回当前事务修改的数据。

    对着上面的栗子来看下:

    就看事务二,第一次查询的时候,已提交的数据,也就是数据库的数据,school_code=20,查询的结果也就是20。

    第二次查询的时候,事务一提交了,数据库的数据是school_code=40,但是当前事务对school_code=40进行了修改,改成了50,那就需要根据当前事务修改后的数据为主,故返回50,是不是挺清晰的?就是MVCC和MySQL的锁保证了事务的正确执行,是不是挺牛掰?

                     

    undo log 是事务数据查询,回滚等用到的,那么,redo log是干啥的?

            MySQL数据库最终是以文件的形式存储在磁盘中,为了保证数据的持久性,对数据进行新增修改的时候,肯定要把数据写入到磁盘中的。而对磁盘数据进行修改的时候,也就是我们操作数据库的时候,肯定是随机修改其中的数据,这样的话,修改速度肯定满足不了我们的要求。

            随机写性能比较差,肯定有优化方法呀!比如,计算机,CPU读写速度肯定都远远超过磁盘,如果每次操作都是直接对磁盘进行操作,无疑会拖慢CPU的读写速率,于是有了CPU缓存,内存条等中间存储设备!

            MySQL也是采取类似的方法,对读写速率进行了优化,不过更为复杂,而且为了保证MySQL中数据的持久性和一致性,数据每次或者每隔很短的时间就要写入磁盘。而redo log就在其中扮演了一个十分重要的角色!(redo log 是innerDB独有的,下文的逻辑默认MySQL使用了innerDB引擎哈)

                    

            当MySQL事务提交时,首先会把数据写入缓存,也就是redo log buffer,调用了一个函数叫做WriteRedoLog。这个是每次事务提交都必须要写入的。

            接着,肯定是要把应用级缓存写入到操作系统缓存呀,也就是要发起系统调用写文件write。当然这个什么时候写就看配置了,可以每次事务完成都写入到操作系统级别的缓存,也可以每隔一段时间写一次。不过这个时候文件还是没有进入磁盘的,如果发生宕机或者断电之类的,数据自然也就丢失了哦。

                    

    最后,再由操作系统将操作系统中的缓存(OS cache)数据,最终fsync到磁盘上,也就是顺序写到redo log,速度自然超过随机写一大截!这个时候,停电宕机什么也不会影响到数据了。

            

     当然,这个时候也仅仅是将数据也到了redo 日志中,并未真正的写到数据库文件中,后面还有操作将redo log file同步到数据库,不过这一步已经影响不到数据的安全性了,不多说。

    为了保证数据的持久性,也就是需要三步,如下图:

                    

     如果在写入OS cache之前,应用程序崩溃了,数据就丢失;

    如果在写入redo log file 之前,机器宕机或者断电之类的,数据也丢失了。

    所以,MySQL默认的是每次事务提交,都会写入到redo log file。

    redo log file的写入虽然是顺序写,但是每次事务提交都写入磁盘,对性能的影响仍然是很大的。每隔1-2s批量写一次行不行?

    行!

            MySQL里面有个参数,innodb_flush_log_at_trx_commit,就是控制事务提交的时候,刷新数据的策略。

    默认innodb_flush_log_at_trx_commit=1, 强一致性,也就是每次事务提交,既要刷新到OS cache,也要写入到redo log中去,不用担心数据丢失。

            如果要性能最佳的话,设置innodb_flush_log_at_trx_commit=0,提交后,只是写入到redo log buffer,每隔1s,才将redo log buffer 中的数据批量写入OS cache,同时写入redo log。单次写改成批量写,速度肯定快很多的。当然,如果应用程序挂了或者操作系统挂了,就要丢失1s的数据。

            再有就是折中一下,设置innodb_flush_log_at_trx_commit=2,提交后,每次写入到redo log buffer,write到OS cache,每隔一秒,OS cache 中的数据批量刷新到redo log文件。效率或许会比innodb_flush_log_at_trx_commit=0 差一点,但也不会相差太多,因为就是多一步内存写操作,速度不会有太大影响的。当然,如果操作系统宕机或者停电什么的,也是会丢失1s的数据的。

            一般来说,innodb_flush_log_at_trx_commit=0与innodb_flush_log_at_trx_commit=2,效率相差几倍,与innodb_flush_log_at_trx_commit=1相比,效率要相差几十倍甚至上百倍。

    不过,哪怕应用程序崩溃,操作系统一般也不会轻易宕机,停电什么的,对一般的大型机房很少会发生这种问题, innodb_flush_log_at_trx_commit=2已经足够,而且可以更容易的适应高并发业务。

            当然,如果对数据一致性要求特别高,也可以设置innodb_flush_log_at_trx_commit=1,应对高并发的时候,可以加机器么~,分库分表什么的,就是业务麻烦了一点。

            除了redo log之外,MySQL在执行事务提交的时候,还会将提交的SQL语句,写入到一个叫做binlog的文件中。

            binlog是MySQL数据库上层产生的,记录了MySQL数据库执行更改的所有操作,不包括select和show这类操作,因为这类操作本身并没有修改数据。

    redo log是在innerDB存储引擎产生,是innerDB独有,而且记录的是物理日志,而且大小是有限制的,超过固定大小之后,会返回起点,循环使用。

            binlog 不循环使用的,在写满或者重启之后,会生成新的binlog文件,一般来说binlog文件比较大,用于恢复数据、主从复制搭建,而redo log 则是作为异常宕机或者介质故障后数据恢复使用。下面copy一张SQL执行 的逻辑图,大家可以瞅一瞅哈!

    好了,今天的分享就到这里吧,感觉还行的话,点个赞呗~

                     

    人贵有志,学贵有恒!

    若有志何须三更睡五更起?最无益只怕一日曝十日寒!

                    

     no sacrifice ,no victory~

    展开全文
  • hex格式redo log解析

    2015-06-24 12:02:40
    关于文件头、日志头、块头、以及一条insert语句的详细解析,并结合dump文件做验证。吐血整理。
  • 所做的增删改查都是先去`buffer pool`缓冲池(内存区域)里面操作,再通过种种情况去进行入盘(数据存入磁盘),因为增删改都是在内存操作,这样就存在系统异常导致数据丢失的情况,redolog就是为了解决系统异常导致...

    https://www.bilibili.com/video/BV11Z4y1X7Kg


    在前面的文章里面也大致讲过redolog,小伙伴们可以先回顾下


    一、redolog的概念

    1-1、redolog的作用

    MySQL在innodb引擎下,所做的增删改查都是先去buffer pool缓冲池(内存区域)里面操作,再通过种种情况去进行入盘(数据存入磁盘),因为增删改都是在内存操作,这样就存在系统异常导致数据丢失的情况,redolog就是为了解决系统异常导致内存修改丢失的问题


    1-2、redolog如何保证数据不丢失

    所有的操作都是以事物为单位的,在事物未执行完毕的时候数据库异常导致数据丢失是正常的,因为事物未提交成功。

    在事物提交的时候,我们把redolog从内存刷入到磁盘中去,从而保证修改不丢失,如果入盘失败,那事物也将提交失败


    1-3、既然总是要落盘?为什么不直接把修改更新到磁盘?

    可能很多小伙伴和最初的我有一样的疑问,在提交事物的时候为什么不直接把我们的修改刷入磁盘,而是先去把redolog刷入磁盘呢?

    之所以innodb在操作的时候要先去操作内存,而不是直接操作磁盘目的只有一个提高性能、提升速度

    虽然redolog落盘的时候也是入磁盘,但它是顺序写入,而直接对磁盘上数据修改是随机写入,顺序写的速度要远远快于随机写。

    看过之前文章的朋友应该知道,把数据从磁盘读入到内存它不是一条条数据读取,而是一页页(每页16k)的读取。一般一个事物操作的数据远远要小于这个16k。


    1-4、redolog数据是如何存储的呢?

    所有的入盘操作最后都会转成二进制,这个并不重要,你可以把redolog磁盘空间理解成下面这个图,带颜色的区域就是存储数据区域

    在这里插入图片描述
    如你所见,redolog存储空间就像一个圆,从头开始存储,存储满了就开始覆盖之前的数据。

    当然实际上它不是一个圆,也是一块磁盘空间,当存储满了的时候就会覆盖之前的,所以用圆来形容它很贴切。


    其实我觉得只需要了解上面这些就差不多的,但为了文章的完整性,下面对于redolog的存储进一步讲解。

    一个事物里面大概率是有多个操作的,看过之前文章的小伙伴也知道,只有当事物提交的时候才会对redolog入盘操作,那在事物提交之前数据如何存储呢?

    毫无疑问在这之前数据也是存储在内存中的,这块内存叫做 redolog buffer,可以通过 innodb_log_buffer_size 来进行配置。

    innodb_log_buffer_size 的默认大小是16MB
    在这里插入图片描述

    分配的内存区域并不是一块大的区域,我们不停的去写入,然后刷入磁盘,而是把这块区域划分成了N个小的区域每个小区域512KB大小,取名为 redo log block,每个redo log block 里面还有一些细节,这里就不去讨论了。

    之前我们讲buffer pool的时候,说到数据存在磁盘的时候是以16KB大小为一个单位叫数据页,存储到缓存的时候也是以这个大小,叫做缓存页。这个redo log block也是一样的,进行数据入盘的时候就把这个512KB整体刷入磁盘。

    它具体进行入盘的时机有这么几个

    1. 当缓存内容大于全部空间一半的时候(默认大小16MB,一半就是MB)
    2. 后台有个线程定时每秒刷入磁盘
    3. 每个事物提交的时候
    4. MySQL关闭的时候

    1-5、redolog和binlog的区别

    • redolog是属于innodb引擎,binlog属于mysql
    • redolog会覆盖之前的数据,而binlog会一直增长(可以设置过期时间)
    • redolog是用来防止mysql异常导致修改数据丢失,binlog是用来数据备份和主从节点数据同步的。
    • redolog是物理日志,记录的是“在某个数据页上做了什么修改”(数据页上某个偏移量的值);binlog是逻辑日志,记录的是这个语句的原始逻辑(sql、数据行)

    二、redolog配置

    2-1、缓存大小

    innodb_log_buffer_size
    

    默认大小 16MB


    2-2、刷盘策略

    innodb_flush_log_at_trx_commit
    

    提交事物写入磁盘中,会根据这个配置的策略进行同步。

    • 0 提交事物的时候不会把redo log buffer 里的数据刷入磁盘
    • 1 提交事物的时候,必须把日志刷入磁盘中,可以严格保证数据不丢失 (默认且推荐策略)
    • 2 提交事物的时候,先把日志刷入磁盘文件对应的 os cache 缓存里,隔一段时间再把数据刷入磁盘

    2-3、磁盘目录

     innodb_log_group_home_dir
    

    这个就是配置redolog在磁盘存放位置,如果没有配置,默认在 datadir 配置下(这个datadir也是配置)
    在这里插入图片描述

    这里有个不知道是不是坑的坑,我在修改了innodb_log_group_home_dir之后,MySQL就启动失败了,找了半天,看日志发现下面的提示

    在这里插入图片描述

    2-4、文件个数

    innodb_log_files_in_group
    

    默认是2,命名规则 ib_logfilex

    在这里插入图片描述



    如果对你有帮助的话,可以关注我的微信公众号: 小道仙97

    在这里插入图片描述

    展开全文
  • MySQL 为什么需要 redo log

    千次阅读 2022-03-15 16:20:31
    redo log 的诞生4.1 redo log buffer4.2 redo log 落盘 今天想和大家聊一聊 MySQL 中的 redo log,其实最早我是想聊两阶段提交的,后来想想可能有小伙伴还不了解 binlog,所以就先整了一篇 binlog: 手把手教你玩 ...


    今天想和大家聊一聊 MySQL 中的 redo log,其实最早我是想聊两阶段提交的,后来想想可能有小伙伴还不了解 binlog,所以就先整了一篇 binlog:

    binlog 大家懂了之后,接下来还差个 redo log,redo log 大家也懂了,那么再讲两阶段提交相信小伙伴们就很容易懂了,咱们一步一步来。

    1. 谁的 redo log

    学习 redo log,我觉得首先要搞明白一个问题,就是是谁的 redo log?

    我们知道,MySQL 架构整体上分为两层:Server 层和存储引擎层,如下图:

    前面松哥文章+视频跟大家聊的 binlog,是 MySQL 自己提供的 binlog,而 redo log 则不是 MySQL 提供的,而是存储引擎 InnoDB 自己提供的。所以在 MySQL 中就存在两类日志 binlog 和 redo log,存在两类日志既有历史原因(InnoDB 最早不是 MySQL 官方存储引擎)也有技术原因,这个咱们以后再细聊。

    先把这个问题搞清楚,后面很多地方就容易懂了。

    2. buffer pool

    在正式介绍 redo log 之前,还有一个 buffer pool 需要大家了解。

    小伙伴们知道,InnoDB 引擎存储数据的时候,是以页为单位的,每个数据页的大小默认是 16KB,我们可以通过如下命令来查看页的大小:

    16384/1024=16

    刚好是 16KB。

    计算机在存储数据的时候,最小存储单元是扇区,一个扇区的大小是 512 字节,而文件系统(例如 XFS/EXT4)最小单元是块,一个块的大小是 4KB,也就是四个块组成一个 InnoDB 中的页。我们在 MySQL 中针对数据库的增删改查操作,都是操作数据页,说白了,就是操作磁盘。

    但是大家想想,如果每一次操作都操作磁盘,那么就会产生海量的磁盘 IO 操作,如果是传统的机械硬盘,还会涉及到很多随机 IO 操作,效率低的令人发指。这严重影响了 MySQL 的性能。

    为了解决这一问题,MySQL 引入了 buffer pool,也就是我们常说的缓冲池。

    buffer pool 的主要作用就是缓存索引和表数据,以避免每一次操作都要进行磁盘 IO,通过 buffer pool 可以提高数据的访问速度。

    通过如下命令可以查看 buffer pool 的默认大小:

    134217728/1024/1024=128

    默认大小是 128MB,因为松哥这里的 MySQL 是安装在 Docker 中,所以这个分配的小一些。一般来说,如果一个服务器只是运行了一个 MySQL 服务,我们可以设置 buffer pool 的大小为服务器内存大小的 75%~80%。

    3. change buffer

    在正式介绍 redo log 之前,还有一个 change buffer 需要大家了解。

    前面我们说的 buffer pool 虽然提高了访问速度,但是增删改的效率并没有因此提升,当涉及到增删改的时候,还是需要磁盘 IO,那么效率一样低的令人发指。

    为了解决这个问题,MySQL 中引入了 change buffer。change buffer 以前并不叫这个名字,以前叫 insert buffer,即只针对 insert 操作有效,现在改名叫 change buffer 了,不仅仅针对 insert 有效,对 delete 和 update 操作也是有效的,change buffer 主要是对非唯一的索引有效,如果字段是唯一性索引,那么更新的时候要去检查唯一性,依然无法避免磁盘 IO。

    change buffer 就是说,当我们需要更改数据库中的数据的时候,我们把更改记录到内存中,等到将来数据被读取的时候,再将内存中的数据 merge 到 buffer pool 然后返回,此时 buffer pool 中的数据和磁盘中的数据就会有差异,有差异的数据我们称之为脏页,在满足条件的时候(redo log 写满了、内存写满了、其他空闲时候),InnoDB 会把脏页刷新回磁盘。这种方式可以有效降低写操作的磁盘 IO,提升数据库的性能。

    通过如下命令我们可以查看 change buffer 的大小以及哪些操作会涉及到 change buffer:

    • innodb_change_buffer_max_size:这个配置表示 change buffer 的大小占整个缓冲池的比例,默认值是 25%,最大值是 50%
    • innodb_change_buffering:这个操作表示哪些写操作会用到 change buffer,默认的 all 表示所有写操作,我们也可以自己设置为 none/inserts/deletes/changes/purges 等。

    不过 change buffer 和 buffer pool 都涉及到内存操作,数据不能持久化,那么,当存在脏页的时候,MySQL 如果突然挂了,就有可能造成数据丢失(因为内存中的数据还没写到磁盘上),但是我们在实际使用 MySQL 的时候,其实并不会有这个问题,那么问题是怎么解决的?那就得靠 redo log 了。

    4. redo log 的诞生

    在正式介绍 redo log 之前,还需要给大家普及一个概念:WAL。

    WAL 全称是 Write-Ahead Logging 中文译作预写日志。啥意思呢?就是说 MySQL 的写操作并不是立刻更新到磁盘上,而是先记录在日志上,然后在合适的时间再更新到磁盘上,这样的好处是错开高峰期的磁盘 IO,提高 MySQL 的性能。

    配合上前面的 buffer pool 和 change buffer,WAL 就是说在操作 buffer pool 和 change buffer 之前,会先把记录写到 redo log 日志中,然后再去更新 buffer pool 或者 change buffer,这样,即使系统突然崩了,将来也可以通过 redo log 恢复数据。当然,redo log 本身又分为:

    • 日志缓冲(redo log buffer),该部分日志是易失性的。
    • 重做日志(redo log file),这是磁盘上的日志文件,该部分日志是持久的。

    那有人说,写 redo log 不就是磁盘 IO 吗?而写数据到磁盘也是磁盘 IO,既然都是磁盘 IO,那干嘛不把直接把数据写到磁盘呢?还费这事!

    此言差矣。

    写 redo log 跟写数据有一个很大的差异,那就是 redo log 是顺序 IO,而写数据涉及到随机 IO,写数据需要寻址,找到对应的位置,然后更新/添加/删除,而写 redo log 则是在一个固定的位置循环写入,是顺序 IO,所以速度要高于写数据。

    如前文所说,redo log 涉及到两个东西:redo log buffer 和 redo log file,这两个东西我们分别来介绍。

    4.1 redo log buffer

    先来说 redo log buffer。

    我们说数据的变化先写入 redo log 中,并不是上来就写磁盘,也是先写到内存中,即 redo log buffer,在时机成熟时,再写入磁盘,也就是 redo log file。

    我们先来看看 redo log buffer 有多大:

    16777216 ÷ 1024 ÷ 1024 = 16MB

    可以看到,这个 redo log buffer 大小刚好是 16MB,如果你觉得这个值有点小,也可以自行修改其大小。

    数据的变更都会首先记录在这块内存中。小伙伴们知道,MySQL 的增删改,如果我们没有显式的开启事务,MySQL 内部也是有一个事务存在的,当内部这个事务 commit 的时候,redo log buffer 会持久化到磁盘中。

    具体来说,有如下几个持久化时机:

    1. innodb_flush_log_at_trx_commit

    通过 innodb_flush_log_at_trx_commit 参数来控制持久化时机,该参数默认值为 1,如下图:

    当然开发者可根据自己的实际需求修改该参数。该参数有三种取值,含义分别如下:

    • 0:每秒一次,将 redo log buffer 中的数据刷新到磁盘中。
    • 1:每次 commit 时,将 redo log buffer 中的数据刷新到磁盘中,即只要 commit 成功,磁盘上就有对应的 redo log 日志,这是最安全的情况,也是推荐使用的参数
    • 2:每次 commit 时,将 redo log buffer 中的数据刷新到操作系统缓存中,操作系统缓存中的数据每秒刷新一次,会持久化到磁盘中。

    这是第一种 redo log buffer 持久化的时机。

    1. 当 redo log buffer 的使用量达到 innodb_log_buffer_size 的一半时,将其写入磁盘成为 redo log file。
    2. MySQL 关闭时,将 redo log buffer 写入磁盘成为 redo log file。

    那如果 redo log buffer 中的数据还没有磁盘,MySQL 就挂了该怎么办?没写入磁盘,说明你还没 commit,既然没 commit,那就数据修改操作都还没有完成,那只能丢了就丢了,如果已经 commit 了,那么数据就会持久化到 redo log file 中,此时即使 MySQL 挂了,将来 MySQL 重启恢复了,数据也是可以被恢复的。具体的恢复逻辑,就涉及到两阶段提交了,这个松哥在后面的文章中再和大家详细介绍。

    4.2 redo log 落盘

    还有一个需要大家注意的问题就是 redo log 落盘,落盘的数据从哪里来?是从 redo log 日志中来还是从 buffer pool 中来?

    在前面的文章中我们说过:binlog 是一种逻辑日志,他里边所记录的是一条 SQL 语句的原始逻辑,例如给某一个字段 +1,这区别于 redo log 的物理日志,物理日志记录的是在某个数据页上做了什么修改。

    由于 redo log 并没有记录数据页的完整数据,所以正常的落盘其实用不到 redo log,数据落盘的时机到了时,直接拿着将脏页(buffer pool)持久化到磁盘中即可。

    好啦,今天就和大家分享这么多,redo log 还有一些内容,我们在后面的文章中再继续聊~

    参考资料:

    • https://www.cnblogs.com/ZhuChangwu/p/14096575.html
    展开全文
  • 什么是redo log和undo log

    千次阅读 2021-12-03 13:52:15
    MySQL日志系统中最重要的日志为重做日志redo log和归档日志bin log,后者为MySQL Server层的日志,前者为InnoDB存储引擎层的日志。 1 重做日志redo log 1.1 什么是redo log redo log用于保证事务的持久性,即ACID...
  • MySQL的日志 - redo log

    千次阅读 多人点赞 2021-01-13 22:28:32
    文章目录前言什么是redologrelaylog的作用物理日志VS逻辑日志redolog的组成redolog的两阶段提交reldolog日志的刷盘redolog对事物的支持redolog和binlog的区别redolog其他的几个参数最后 前言 前面的文章中,我们依次...
  • redo log详解

    千次阅读 2021-08-14 17:01:49
    没错,就是通过redo log(下文简称redo)。 注意,绝对的数据不丢失是做不到的。我们所谈论的redo log,是针对事务而言。我们只要能保证事务中的数据不丢就行,说简单点就是redo保证了事务的原子性和持久性。 简单...
  • innodb事务日志包括redo log和undo logredo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。undo log不是redo log的逆向过程,其实它们都算是用来恢复的日志:1.redo log通常是物理日志,记录的...
  • Undo log Undo Log介绍 Undo:意为撤销或取消,以撤销操作为目的,将数据返回到某个状态的操作(有点类似ctrl+z)。 Undo Log:数据库事务开始之前,会将要修改的记录存放到 Undo 日志里,当事务回滚时或者数 据库...
  • 1、redo log含义 2、redo log类型 3、redo log格式 4、redo log写磁盘过程 4.1、redo log里记录了: 4.2、redo log block 4.3、redo log buffer 4.4、写磁盘过程 5、 redo log buffer中缓冲日志,什么时候...
  • 作为开发,我们重点需要关注的是二进制日志(binlog)和事务日志(包括redo log和undo log),本文接下来会详细介绍这三种日志。 binlog binlog用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在...
  • MySQL中的redo log和undo log MySQL日志系统中最重要的日志为重做日志redo log和归档日志bin log,后者为MySQL Server层的日志,前者为InnoDB存储引擎层的日志。 1 重做日志redo log 1.1 什么是redo log redo ...
  • MySQL性能优化(四)redo log实现原理

    千次阅读 2021-12-09 10:09:03
    本文介绍redo log的作用,结构,以及刷盘
  • 接下来重点介绍二进制日志(bin log)和事务日志(redo log和 undo log)。 bin log binlog用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。binlog是Mysql的逻辑日志,并且由...
  • 文章目录redo 日志格式简单的 redo 日志类型复杂的 redo 日志格式举个例子redo 日志格式小结Mini-Transcation以组的形式写入 redo 日志Mini-Transaction 的概念redo 日志写入过程redo log blocklog block headerlog ...
  • 1 bin log 1.1 定义 bin log应该说是Mysql里最核心的日志,是MySQL数据库级别的文件,记录对MySQL数据库各种引擎下执行修改的所有操作(包括DDL和DML语句),不会记录select和show语句,主要用于恢复数据库和同步...
  • 一、redo log的概念 redo log,重做日志,也叫重放日志。和undo log回滚日志一样,都是在数据库发生意外时用来进行数据恢复的,通过前面一篇文章对undo log的总结,我们都知道undo log记录的是数据更新前的样子,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 111,520
精华内容 44,608
关键字:

redolog

友情链接: areyaljotithms.rar