美文网首页JAVA
3.1、事务日志

3.1、事务日志

作者: flyjar | 来源:发表于2022-05-26 17:49 被阅读0次

    Mysql事务日志
    前言
    一、事务四大特性ACID的实现机制
    二、REDO日志
    1.为什么需要REDO日志?
    2.REDO日志的好处和特点?
    3.REDO的组成
    4.REDO的整体流程
    5.REDO的刷盘策略
    三、UNDO日志
    1.为什么需要UNDO日志?
    2.UNDO LOG的作用
    3.UNDO LOG的组成
    3.1.回滚段与undo页
    3.2.回滚段与事务
    3.3.回滚段中的数据分类
    3.4.undo的类型
    3.5.undo log的生命周期
    最后
    前言
      上一章《Mysql数据库事务四大特性、事务状态、事务使用、事务隔离级别》讲到了事务有4种特性:原子性、一致性、隔离性、持久性。那么 ,这些特性到底是基于什么机制实现的呢?本章理论或许枯燥,但是,我们不正是要会别人不会的,才能安享35岁晚年吗?

    一、事务四大特性ACID的实现机制
      事务的隔离性由锁机制实现;
      事务的原子性、一致性、持久性由REDO LOG和UNDO LOG实现的。
      REDO LOG称为重做日志,提供在写入操作,恢复提交事务修改的页操作,用来保证事务的持久性;
      UNDO LOG称为回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
    注意:
      UNDO LOG并不是REDO LOG的逆过程,二者都是一种恢复操作。
      REDO LOG是存储引擎层(Innodb)生成的日志,记录的是物理级别上的页修改操作,比如页号,偏移量 写入‘ddd’数据,主要为了保证数据可靠性。
      UNDO LOG是存储引擎层(Innodb)生成的日志,记录的是逻辑操作,比如当用户进行insert操作时,UNDO LOG就记录一条与之相反的delete操作,主要用于事务回滚和一致性非锁定读(undo log回滚行记录到某种特定的版本…MVCC,即多版本并发控制)。

    二、REDO日志
      InnoDB存储引擎是以页为单位来管理存储空间的,会将磁盘上的页缓存到内存buffer Pool之后才可以访问,所有变更都必须先更新缓冲池中的数据,然后缓冲池中的脏页(脏页:与磁盘页数据发生变化的页)会以一定的频率刷入到磁盘(checkPoint机制),通过缓冲池来优化CPU和磁盘之间的鸿沟,保证性能。

    1.为什么需要REDO日志?
      checkPoint是操作系统master线程隔一段时间去处理的,所以最坏的情况是事务提交后,刚写完缓冲池,数据库宕机了,那么这段数据就是丢失了,违背了“事务提交后,对数据修改不能丢失”的原则。那么如何保证这个持久性呢?有人会说,在事务提交完成后立即把修改刷新到磁盘,但是这个简单粗暴的做法有些问题:
    (1)修改量与刷新磁盘工作量严重不成比例
      Innodb是以页为单位来进行磁盘IO的,页默认是16kB,如果我们只修改了一个字节就要刷新16KB的数据到磁盘上,显然小题大做了。
    (2)随机IO刷新较慢
      一个事务包含很多语句,即使是一条语句也可能修改很多页,而且这些页并不相邻,那么在刷盘时,随机IO比顺序IO要慢,特别是传统机械硬盘。

    另一个解决思路:我们不需要把每次commit的修改都立即更新到磁盘,只需要把修改了哪些东西记录一下就好,比如:某个事务将系统空间中第10号页中偏移量为100处的值更新成2。
      Innodb引擎的事务采用WAL技术,就是先写日志,在写磁盘,只要日志写入成功,才算事务提交成功,这里的日志就是REDO LOG,当数据库突然宕机,重启时也能通过REDO LOG恢复数据,保证持久性,这就是REDO LOG的作用。

    2.REDO日志的好处和特点?
    好处:
    (1)REDO日志降低了刷盘频率;
    (2)REDO日志占用的空间非常小。
      存储表空间ID、页号、偏移量以及要更新的值,存储空间小,刷新快。

    特点:
    (1)REDO日志是顺序写入磁盘的;
      当一条执行语句产生多条redo日志时,是顺序写入磁盘的,也就是顺序IO,效率比随机IO快。
    (3)事务执行过程中,redo log不断记录
      Redo log和bin log的区别,redo log是存储引擎层的,bin log是数据库层的。比如,一个事务对表做10万条插入,在这个插入过程中,会持续往redo log中记录。直到事务提交时,才会一次写入到bin log文件中。

    3.REDO的组成
    (1)重做日志缓存(redo log buffer)
    保存在内存中,在Mysql服务器启动时,会向操作系统申请一大片称为redo log buffer的连续内存空间,翻译中文叫“redo日志缓冲区”,这片内存空间被划分成若干个联系的redo log block,一个redo log block占用512字节大小。
    注意:redo log buffer默认16M,最大是4096M,最小是1M。

    (2)重做日志文件(redo log file)

    4.REDO的整体流程

    5.REDO的刷盘策略
      Innodb以一定频率将redo log buffer中的数据刷新到磁盘(redo log file)中,这个一定频率是分刷盘策略的。
    注意:
      这里的刷盘不是只是真正刷到磁盘中,只是刷入到文件系统缓存(page cache)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正写入会交给系统自己来决定。
      如果page cache足够大,那么对于Innodb来说,就存在一个问题,如果系统宕机,那么数据依然会丢失。
      另外,Innodb存储引擎有一个后台线程,每隔1s,就会把redo log buffer中的内容写到文件系统缓存(page cache),然后调用刷盘操作。也就是说,一个没有提交事务的redo log记录,也可能会刷盘,因为在事务执行过程中redo log记录是会写入redo log buffer中,这些redo log记录会被后台线程刷盘。

    Innodb给出Innodb_flush_log_at_trx_commit参数:
    设置为0:表示每次事务提交时只是写到redo log buffer里(系统默认master thread每隔1s进行一次重做日志的同步)。
    事务提交成功,数据也仅仅只是写到redo log buffer里,这时如果Mysql挂了,会丢失1s的数据。

    设置为1:表示每次事务提交时都将进行同步,并立即刷盘操作(默认)。
    因此,只要事务提交成功,redo log记录一定在磁盘里,不会有数据丢失,但是效率最差。

    设置为2:表示每次事务提交时都只把redo log buffer内容写入page cache,由系统默认master thread每隔1s进行一次重做日志的同步。
    因此,只要事务提交成功,redo log记录一定写到文件系统缓存中,这时Mysql挂了不会有数据丢失,这时操作系统挂了可能会丢失1s的数据,但是效率高。

    效率对比:

    三、UNDO日志
    1.为什么需要UNDO日志?
      事务需要保证原子性,要么都成功,要么都失败。当事务失败时,就需要把数据改回原先的样子,这个过程叫“回滚”。
      当你插入一条数据时,至少要把数据记下来,方便回滚时删除。
      当你删除一条记录时,至少要把数据记下来,方便回滚时插入。
      当你更新一条记录时,至少把旧值记下来,方便回滚是恢复。
      这些为了回滚而记录的内容,就称为“回滚日志”或“UNDO LOG”。
    注意:
    (1)查询是不会修改记录,所有不会记录UNDO LOG。
    (2)undo log也会产生redo log,这是因为undo log也需要持久性的保护。

    2.UNDO LOG的作用
    回滚数据:只是将数据库逻辑地恢复原来的样子,对物理层面的数据结构和页本身的变化是无法恢复的。
    MVCC:Innodb存储引擎中MVCC的实现是通过undo来完成的。当用户读一条已经被其他事务占用的数据时,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读取。

    3.UNDO LOG的组成
    3.1.回滚段与undo页
      Innodb对undo log的管理采用段的方式,也就是回滚段(rollback segment),每个回滚段记录了1024个undo log segment,而在每个undo log segment段中进行undo页的申请。
      在Innodb1.1版本之前,只有一个rollback segment,因此最大同时只支持1024个事务。
      在Innodb1.1版本开始,有128个rollback segment,因此最大同时只支持128*1024个事务。
      可以通过SHOW VARIABLES like '%undo%'查看,虽然支持128个rollback segment,但是这些rollback segment都存储在共享表空间ibdata中。
      在Innodb1.2版本开始,可以通过参数对rollback segment进行设置:

    innodb_undo_tablespaces=3 #设置为3个
    innodb_undo_logs=128 #默认128个
    innodb_undo_directory =/dbfiles/mysql_home/undologs
    1
    2
    3
    MySQL设置undo为独立表空间

    Undo页的重用
      我们知道,Mysql默认一页大小是16k,为每一个事务分配页,是非常浪费的。
      举个例子:假设一个场景,一秒处理的事务数是1000,一秒需要16M。一分钟大概需要1G的存储。要求Mysql必须非常快速清理,否则,磁盘占用会越来越大。
      因此,undo页设计的也是可以重用的。Undo log提交后,并不会删除undo页,会被放到一个链表中,然后判断undo页的使用空间是否小于四分之三,是的话,undo页会被重用。

    3.2.回滚段与事务
      每一个事务只使用一个回滚段,一个回滚段在同一时刻可能服务于多个事务。
      事务进行过程中,当数据修改时,原始的数据会被复制到回滚段。
      当事务提交时,Innodb存储引擎会做以下两件事情:
      (1)将undo log放入列表中,以供之后的purge操作;
      (2)判断undo log所在的页是否可以重用,若可以分配给下一个事务使用。

    3.3.回滚段中的数据分类
    (1)未提交的回滚数据;
    (2)已提交未过期的回滚数据。
    (3)已提交已过期的回滚数据。
      事务提交之后并不能立即删除undo log和所在的页,因为可能有其他事务需要通过undo log来得到行记录之前的版本。因此事务提交后会将undo log放入一个链表中,是否可以最终删除undo log和所在的页,由purge线程来判断。

    3.4.undo的类型
    在Innodb存储引擎中,undo log分为:
    (1)insert undo log
    插入的undo log,因为对其他事务不可见,所以commit提交后直接删除,不需要purge。
    (2)update undo log
    修改和删除的undo log,因为undo log可能需要提供MVCC机制,所以commit提交后不能直接删除,需要purge。

    3.5.undo log的生命周期

    相关文章

      网友评论

        本文标题:3.1、事务日志

        本文链接:https://www.haomeiwen.com/subject/uumaurtx.html