美文网首页
MySQL redo log专题

MySQL redo log专题

作者: 这货不是王马勺 | 来源:发表于2024-07-03 16:46 被阅读0次

    WAL机制

    WAL预写式日志(Write-Ahead Logging,先行日志),就是先写日志,再写磁盘数据。既提高了性能,又保证数据的安全性。
    MySQL中redo log就是采用WAL机制。
    为什么WAL机制可以提高效率和安全性?
    磁盘文件写操作是随机io,比较消耗性能。而写日志是顺序io,实际更新数据库文件的操作由后台线程根据log异步写入;此外存储表空间ID、页号、偏移量以及需要更新的值所需的存储空间也是很小的。WAL核心就是将随机写转换为顺序写,降低客户端的延时,提高了性能。
    而redo log作为一个事务的原子性和持久性保障机制,提高了数据库安全性。

    redo log基本概念

    redo log(重做日志):是innodb引擎特有的事务日志,用来保证事务的原子性和持久性。
    redo log是物理日志,记录的是对磁盘上数据进行修改的相关信息,如对某个表空间的某个页的某个偏移量位置的某个值做了什么修改,修改值是多少。

    redo log包含两部分:

    • 内存中的日志缓冲区:redo log buffer,就在log buffer区域中。
    • 磁盘上的日志文件:redo log file。

    redo log有什么作用?
    MySQL每执行一条DML语句,就会将记录写入到redolog buffer中。后续某个时间点再一次性将多个操作记录到redolog file。当故障发生导致内存数据丢失后,innodb会在重启时,经过重放redo将数据恢复到崩溃之前的状态。

    redo log的格式

    物理日志与逻辑日志的区别
    1)物理日志:记录的是每个page页中具体存储的值是多少,在数据页上做了什么修改。比如某个事务将系统表空间中第100个页中偏移量1000处那个字节的值由1改为2。
    2)逻辑日志:记录每一个page页中具体数据是怎么变动的,记录的是一个变动的过程,或者记录的就是SQL语句的逻辑。

    redolog属于物理日志,由“表空间号+数据页号+偏移量+修改数据的长度+具体修改的数据“这几部分组成的。

    redo log通用结构如图:


    • type :该条 redo 日志的类型。如果是1则是写入1字节,8则是写入8字节,按写入数据修改的长度(多少)划分。
    • space ID :表空间 ID。
    • page number :页号。
    • data :该条 redo 日志的具体内容。

    根据在页面中写入数据的多少,把redo log类型做了划分,在5.7版本中就有50多种。
    如MLOG_1BYTE类型,表示在页面的某个偏移量处写入1字节的redo日志。
    这里以MLOG_8BYTE举个例子:

    再以MLOG_WRITE_STRING举例子,表示在某个页面某个偏移量出写入一串数据,但是不能够确定具体占多少字节,需要在日志结构中添加len字段。

    redo log的持久化

    缓冲区的数据一般情况下无法直接写入磁盘,中间必须经过操作系统的缓冲区OS buffer,再通过系统调用fsync()函数将其刷到磁盘。
    流程:日志数据---redolog buffer---OS buffer---redolog file
    真正的落盘操作是需要执行fsync()才能完成的。

    redolog buffer持久化到redo log可选的策略,有三种,通过innodb_flush_log_at_trx_commit设置

    • 0:延迟写,速度最快,但不安全,一旦MySQL进程崩溃会导致上1秒的事务数据全部丢失。
    • 1:实时写,实时刷(默认),最安全,不会丢失数据(一旦commit必在redolog文件中记录),但也是最慢的。
    • 2:实时写,延时刷,速度较快,与0相比相对安全。只有在OS崩溃时,上1秒的事务会丢失。

    事务还没提交的时候,redo log能不能被持久化到磁盘?
    redo log数据存在三种状态

    • 存在redolog buffer中
    • 向磁盘写入,但还没真正落地到磁盘,而是保存在os buffer中
    • 持久化到了磁盘redolog文件

    触发真正的fsync()的场景:

    • redolog buffer占用的空间即将达到innodb_log_buffer_size(默认8M)的50%时,后台线程会主动写盘。如果这个事务并没有提交,这个写盘动作只是写到了os buffer,并没有fsync()到磁盘redolog文件。
    • 当innodb_flush_log_at_trx_commit设置为1时,并行的事务提交的时候,顺带会将某个未提交的事务redolog buffer持久到磁盘redolog文件。因为redo log buffer是共享的。

    因此事务未提交时,redolog也是有可能被持久化到磁盘的,参考fsync()场景2。

    redolog两阶段提交

    redo log提交分为两步(两阶段提交),如下图所示

    两阶段提交的具体过程包括:prepare阶段写redolog,binlog落盘,coomit阶段更新redolog(打标记)。

    为什么要有两阶段提交?
    主要是为了解决binlog和redolog一致性的问题。
    使用两阶段提交的方式,无论数据库在哪个环节发生崩溃,都可以正确地恢复,因为redolog和binlog都会有一个唯一的XID来标记更新的事务,从而二者可以对齐。在崩溃恢复时,会顺序扫描redo log:
    1)如果碰到既有prepare又有commit的redolog则直接提交(即阶段2),
    2)如果redolog处于prepare状态,就会拿着xid去binlog中找对应的事务,判断事务所对应的binlog是否完整(即上图第4步binlog落盘是否完整),如果完整则事务提交,如果不完整则事务回滚。

    网络上其他对崩溃恢复的描述:

    • 情况一,在prepare阶段完成之后崩溃,由于binlog没有记录,因此直接回滚。
    • 情况二,在binlog落盘后崩溃(上图第4步),检查事务是否完整无误,若是,直接提交即可,否则直接回滚。
    • 情况三,在commit阶段完成后崩溃,同情况二。

    整体看一个数据修改的事务流程:


    参考:

    https://www.cnblogs.com/kuangtf/articles/16353184.html
    

    相关文章

      网友评论

          本文标题:MySQL redo log专题

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