• mysql基础知识----redo和undo日志


    数据库通常借助⽇志来实现事务,常见的有undo log、redo log,undo/redo log都能保证事务特性,undolog实现事务原⼦性,redolog实现
    事务的持久性。
    为了最⼤程度避免数据写⼊时io瓶颈带来的性能问题,MySQL采⽤了这样⼀种缓存机制:当query修改数据库内数据时,InnoDB先将该数据
    从磁盘读取到内存中,修改内存中的数据拷贝,并将该修改⾏为持久化到磁盘上的事务⽇志(先写redo log buffer,再定期批量写⼊),⽽
    不是每次都直接将修改过的数据记录到硬盘内,等事务⽇志持久化完成之后,内存中的脏数据可以慢慢刷回磁盘,称之为Write-Ahead
    Logging。事务⽇志采⽤的是追加写⼊,顺序io会带来更好的性能优势。
    为了避免脏数据刷回磁盘过程中,掉电或系统故障带来的数据丢失问题,InnoDB采⽤事务⽇志(redo log)来解决该问题。

    ⼀、先简单了解⼏个概念

    数据库数据存放的⽂件称为data file;
    ⽇志⽂件称为log file;
    数据库数据是有缓存的,如果没有缓存,每次都写或者读物理disk,那性能就太低下了。数据库数据的缓存称为data buffer,⽇志(redo)
    缓存称为log buffer。
    内存缓冲池
    buffer pool如果mysql不⽤内存缓冲池,每次读写数据时,都需要访问磁盘,必定会⼤⼤增加I/O请求,导致效率低下。所以Innodb引擎在读
    写数据时,把相应的数据和索引载⼊到内存中的缓冲池(buffer pool)中,⼀定程度的提⾼了数据读写的速度。
    buffer pool:占最⼤块内存,⽤来存放各种数据的缓存包括有索引页、数据页、undo页、插⼊缓冲、⾃适应哈希索引、innodb存储的锁信
    息、数据字典信息等。⼯作⽅式总是将数据库⽂件按页(每页16k)读取到缓冲池,然后按最近最少使⽤(lru)的算法来保留在缓冲池中的缓存数
    据。如果数据库⽂件需要修改,总是⾸先修改在缓存池中的页(发⽣修改后即为脏页dirty page),然后再按照⼀定的频率将缓冲池的脏页刷新
    到⽂件。
    表空间
    表空间可看做是InnoDB存储引擎逻辑结构的最⾼层。表空间⽂件:InnoDB默认的表空间⽂件为ibdata1。
    段:表空间由各个段组成,常见的段有数据段、索引段、回滚段(undo log段)等。
    区:由64个连续的页组成,每个页⼤⼩为16kb,即每个区⼤⼩为1MB。
    页:每页16kb,且不能更改。常见的页类型有:数据页、Undo页、系统页、事务数据页、插⼊缓冲位图页、插⼊缓冲空闲列表页、未
    压缩的⼆进制⼤对象页、压缩的⼆进制⼤对象页。
    redo log 和undo log
      为了满⾜事务的持久性,防⽌buffer pool数据丢失,innodb引⼊了redo log。为了满⾜事务的原⼦性,innodb引⼊了undo log。

    ⼆、undo log

    Undo log 是为了实现事务的原⼦性。还⽤Undo Log来实现多版本并发控制(简称:MVCC)。
    delete/update操作的内部机制
    当事务提交的时候,innodb不会⽴即删除undo log,因为后续还可能会⽤到undo log,如隔离级别为repeatable read时,事务读取的都是开
    启事务时的最新提交⾏版本,只要该事务不结束,该⾏版本就不能删除,即undo log不能删除。
    但是在事务提交的时候,会将该事务对应的undo log放⼊到删除列表中,未来通过purge来删除。并且提交事务时,还会判断undo log分配
    的页是否可以重⽤,如果可以重⽤,则会分配给后⾯来的事务,避免为每个独⽴的事务分配独⽴的undo log页⽽浪费存储空间和性能。
    通过undo log记录delete和update操作的结果发现:(insert操作⽆需分析,就是插⼊⾏⽽已)

    1. delete操作实际上不会直接删除,⽽是将delete对象打上delete flag,标记为删除,最终的删除操作是purge线程完成的。
    2. update分为两种情况:update的列是否是主键列。
    3. 如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进⾏的。
    4. 如果是主键列,update分两部执⾏:先删除该⾏,再插⼊⼀⾏⽬标⾏。

    ①事务的原⼦性

    事务的所有操作,要么全部完成,要不都不做,不能只做⼀半。如果在执⾏的过程中发⽣了错误,要回到事务开始时的状态,所有的操
    作都要回滚。

    ②原理

    Undo Log的原理很简单,为了满⾜事务的原⼦性,在操作任何数据之前,⾸先将数据备份到⼀个地⽅(这个存储数据备份的地⽅称为Undo Log)。然后进⾏数据的修改。如果出现了错误或者⽤户执⾏了ROLLBACK语句,系统可以利⽤Undo Log中的备份将数据恢复到事务
    开始之前的状态。
    假设有A、B两个数据,值分别为1,2。进⾏+2的事务操作。

    A.事务开始. 
    B.记录A=1到undo log. 
    C.修改A=3. 
    D.记录B=2到undo log. 
    E.修改B=4. 
    F.将undo log写到磁盘。
    G.将数据写到磁盘。
    H.事务提交
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这⾥有⼀个隐含的前提条件:‘数据都是先读到内存中,然后修改内存中的数据,最后将数据写回磁盘’。
    之所以能同时保证原⼦性和持久化,是因为以下特点:
    A. 更新数据前记录Undo log。
    B. 为了保证持久性,必须将数据在事务提交前写到磁盘。只要事务成功提交,数据必然已经持久化。
    C. Undo log必须先于数据持久化到磁盘。如果在G,H之间系统崩溃,undo log是完整的,可以⽤来回滚事务。
    D. 如果在A-F之间系统崩溃,因为数据没有持久化到磁盘。所以磁盘上的数据还是保持在事务开始前的状态。
    缺点:每个事务提交前将数据和Undo Log写⼊磁盘,这样会导致⼤量的磁盘IO,因此性能很低。

    三、Redo Log

    redo log就是保存执⾏的SQL语句到⼀个指定的Log⽂件,当mysql执⾏数据恢复时,重新执⾏redo log记录的SQL操作即可。
    更正:
    redo log通常是物理⽇志,记录的是数据页的物理修改,⽽不是某⼀⾏或某⼏⾏修改成怎样怎样,它⽤来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后⼀次提交的位置)。
    引⼊buffer pool会导致更新的数据不会实时持久化到磁盘,当系统崩溃时,虽然buffer pool中的数据丢失,数据没有持久化,但是系统可以
    根据Redo Log的内容,将所有数据恢复到最新的状态。redo log在磁盘上作为⼀个独⽴的⽂件存在。默认情况下会有两个⽂件,名称分别为
    ib_logfile0和ib_logfile1。
    参数innodb_log_file_size指定了redo log的⼤⼩;innodb_log_file_in_group指定了redo log的数量,默认为2; innodb_log_group_home_dir
    指定了redo log所在路径。
    ROLLBACK语句,系统可以利⽤Undo Log中的备份将数据恢复到事务开始之前的状态。与redo log不同的是,磁盘上不存在单独的undo
    log⽂件,它存放在数据库内部的⼀个特殊段(segment)中,这称为undo段(undo segment),undo段位于共享表空间内。
    Innodb为每⾏记录都实现了三个隐藏字段:
    6字节的事务ID(DB_TRX_ID)
    7字节的回滚指针(DB_ROLL_PTR)
    隐藏的ID
    redo log的记录内容
    undo log和 redo log本⾝是分开的。innodb的undo log是记录在数据⽂件(ibd)中的,⽽且innodb将undo log的内容看作是数据,因此对undo
    log本⾝的操作(如向undo log中插⼊⼀条undo记录等),都会记录redo log。undo log可以不必⽴即持久化到磁盘上。即便丢失了,也可以通
    过redo log将其恢复。因此当插⼊⼀条记录时:

    1. 向undo log中插⼊⼀条undo log记录。
    2. 向redo log中插⼊⼀条”插⼊undo log记录“的redo log记录。
    3. 插⼊数据。
    4. 向redo log中插⼊⼀条”insert”的redo log记录。
      redo log的io性能
      为了保证Redo Log能够有⽐较好的IO性能,InnoDB 的 Redo Log的设计有以下⼏个特点:
    5. 尽量保持Redo Log存储在⼀段连续的空间上。因此在系统第⼀次启动时就会将⽇志⽂件的空间完全分配。以顺序追加的⽅式记录
      Redo Log。
    6. 批量写⼊⽇志。⽇志并不是直接写⼊⽂件,⽽是先写⼊redo log buffer,然后每秒钟将buffer中数据⼀并写⼊磁盘
    7. 并发的事务共享Redo Log的存储空间,它们的Redo Log按语句的执⾏顺序,依次交替的记录在⼀起,以减少⽇志占⽤的空间。
    8. Redo Log上只进⾏顺序追加的操作,当⼀个事务需要回滚时,它的Redo Log记录也不会从Redo Log中删除掉。
      ①原理
        和Undo Log相反,Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,不需要将数据持久化。当系统崩溃
      时,虽然数据没有持久化,但是Redo Log已经持久化。系统可以根据Redo Log的内容,将所有数据恢复到最新的状态。
    ②Undo + Redo事务的简化过程
    A.事务开始. 
    B.记录A=1到undo log. 
    C.修改A=3. 
    D.记录A=3到redo log. 
    E.记录B=2到undo log. 
    F.修改B=4. 
    G.记录B=4到redo log. 
    H.将redo log写⼊磁盘。
    I.事务提交
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    四、⼩结

    A-G的过程是在内存中进⾏的,相应的操作记录在redo log buffer(B&E),redo log buffer(E&G)中,事务执⾏结果(此时未提交)也存
    在db buffer中(C&F),buffer满了就写⼊磁盘当中,如果buffer存储的事务数量都是1个,也就意味着是将⽇志⽴即刷⼊磁盘,那么数据的
    ⼀致性很好保证。如果存储多个的话,是⼀次事务完成就会先将redo log同步到磁盘当中并有⼀个状态位来记录是否提交,再去真正的提交
    事务,将db buffer 中的数据同步到DB的磁盘当中去。要保证在db buffer中的内容写⼊磁盘数据库⽂件之前,应当把log buffer的内容写⼊磁
    盘⽇志⽂件。这种⽅式可以减少磁盘IO,增加吞吐量。不过,这种⽅式适⽤于⼀致性要求不⾼的情景。因为如果出现断电等系统故障,log
    buffer、db buffer中的完成的事务还没同步到磁盘会丢失。像银⾏这种要求事务较⾼的⼀致性,就⼀定要保证每次事务都要记录到磁盘中,
    如果服务器down了的时候去redo log中恢复,重做⼀次已经提交的事务。

    五、redo & undo log的作⽤

    数据持久化
    buffer pool中维护⼀个按脏页修改先后顺序排列的链表,叫flush_list。根据flush_list中页的顺序刷数据到持久存储。按页⾯最早⼀次被
    修改的顺序排列。正常情况下,dirty page什么时候flush到磁盘上呢?

    1. 当redo空间占满时,将会将部分dirty page flush到disk上,然后释放部分redo log。
    2. 当需要在Buffer pool分配⼀个page,但是已经满了,这时候必须 flush dirty pages to disk。⼀般地,可以通过启动参数
      innodb_max_dirty_pages_pct控制这种情况,当buffer pool中的dirty page到达这个⽐例的时候,把dirty page flush到disk中。
    3. 检测到系统空闲的时候,会flush。
      数据恢复
      随着时间的积累,Redo Log会变的很⼤。如果每次都从第⼀条记录开始恢复,恢复的过程就会很慢,从⽽⽆法被容忍。为了减少恢复
      的时间,就引⼊了Checkpoint机制。假设在某个时间点,所有的脏页都被刷新到了磁盘上。这个时间点之前的所有Redo Log就不需要
      重做了。系统记录下这个时间点时redo log的结尾位置作为checkpoint。在进⾏恢复时,从这个checkpoint的位置开始即可。
      Checkpoint点之前的⽇志也就不再需要了,可以被删除掉。

    六、恢复(Recovery

    恢复策略
      前⾯说到未提交的事务和回滚了的事务也会记录Redo Log,因此在进⾏恢复时,这些事务要进⾏特殊的处理.有2种不同的恢复策略:
    A. 进⾏恢复时,只重做已经提交了的事务。(返回给客户端的是已经提交⼀定保证数据的可恢复持久性)
    B. 进⾏恢复时,重做所有事务包括未提交的事务和回滚了的事务。然后通过Undo Log回滚那些未提交的事务。⽐如在B-E过程中down机
    了,那么恢复时根据undo log去重新模拟当时的情景(但是如果log buffer的空间很⼤,log没有同步到磁盘这个过程就没有办法来进⾏,同
    时由于事务没有提交,返回给客户端的值是未提交成功,所以也没有关系)

  • 相关阅读:
    ELK入门(一)-Elasticsearch(docker版)
    基于MATLAB开发AUTOSAR软件应用层模块-part9.AUTOSAR工具箱的功能介绍-2
    吴恩达《微调大型语言模型》笔记
    JAVA每日面试题
    YOLOv5添加注意力机制
    Linux从入门到精通(八)——Linux磁盘管理
    CEX暴雷怎么办 一文读懂加密钱包产业现状
    Vue+AntDesignVue实现a-tree树形组件的层级选中功能
    【Newman+Jenkins】实施接口自动化测试
    C++STL-string类的使用
  • 原文地址:https://blog.csdn.net/u013915286/article/details/124839101