redo日志、undo日志、binlog日志与doublewrite分析

binlog日志 (二进制日志)

二进制日志记录了对MySQL数据库执行更改的所有操作,它是一种逻辑操作,其记录的是对应的SQL语句。但是,不会记录SELECT和SHOW这类操作,因为这类操作对数据本身并没有修改。

二进制文件格式

MySQL通过binlog_format参数来设置二进制文件格式。

  • STATEMENT格式。 最基础的版本。它记录的是日志的逻辑SQL语句。
  • ROW格式。记录的不是简单的逻辑SQL语句,而是记录表的行更改情况,记录的是表中每个字段的值。
  • MIXED格式。MySQL默认采用STATEMENT格式进行记录,但是一旦判断可能会有数据不一致的情况,则会有ROW格式来记录。

二进制文件的用途

  • 恢复。某些数据的恢复需要二进制文件。
  • 复制。通过复制和执行二进制文件进行两个数据库之间的实时同步。
  • 审计。判断是否有对数据库进行注入的攻击。

在默认情况下,二进制文件并不是在每次写的时候同步到磁盘中。因此,当数据库所在操作系统发生宕机时,可能会有最后一部分数据没有写入到二进制日志文件中,这会给恢复和复制带来问题。
所有未提交的二进制日志会被记录到一个缓存中,等该事务提交时直接将缓存的二进制日志写入二进制日志文件,而该缓存的大小由binlog_cache_size决定。

Redo日志

binlog主要用来做数据归档,但它不具备崩溃恢复的能力,如果你的系统突然崩溃宕机,重启后可能会有部分数据丢失,而Redo日志能够有效解决这个问题。可以把它看做一种恢复操作,它恢复提交事务修改的页操作。大部分情况下,Redo是物理日志,记录的是数据页的物理操作。
它主要有两部分:(1)重做日志缓冲,其是丢失的;(2)重做日志文件,其是持久的。

Redo的整体流程

  1. 先将原始数据从磁盘中读入内存中,修改数据的内存拷贝
  2. 生成一条重做日志并写入重做日志缓存中,记录的是数据被修改后的值
  3. 当事务提交时,将重做日志缓存中的内容刷新追加到重做日志文件中。
  4. 定期将内存中修改的数据刷新到磁盘中。

何时写入到Redo(重做日志文件)中

  • master thread 每一秒将重做日志缓存刷新到重做日志文件中。
  • 每次事务提交时。
  • 当重做日志缓存池剩余空间小于1/2时。

Redo日志与二进制日志的不同

从表面上看,它们非常相似,都是记录了数据库操作的日志,但从本质上看,两者有非常大的不同。

  1. 产生位置不同。重做日志是在InnoDB存储引擎层中产生,而二进制日志是在MySQL数据库的上层产生。
  2. 记录的内容形式不同。二进制日志是一种逻辑日志,其记录的是对应的SQL语句,但是在ROW格式下,它记录的是物理文件;而重做日志是物理格式日志,其记录的是对于每个页的修改。
  3. 写入磁盘的时间点不同。二进制日志只是在事务提交完成后进行一次写入,而InnoDB存储引擎的重做日志在事务进行中不断被写入,

Undo日志

当用户执行的事务或语句由于某种原因失败时,又或者用户用一条ROLLBACK语句请求回滚,就可以利用这些undo信息将数据回滚到修改之前的样子。还有一个作用是MVCC。

undo存放在数据库内部的一个特殊段中,成为undo端(undo segment)。undo是逻辑日志,因此只是将数据库逻辑地恢复到原来的样子。所有修改都被逻辑地取消了,但是数据结构和页本身在回滚之后可能大不相同。
在MVCC中,当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读。

undo log格式

  • insert undo log
    是指在insert操作中产生的undo log。因为insert操作的记录,只对事务本身可见,对其他事务不可见,故该undo log可以在事务提交后直接删除,不需要进行purge操作。

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

purge

例如语句:

delete from t where a = 1;

其中,表t上列a有聚集索引,列b上有辅助索引。当执行delete删除操作时,仅是将主键列等于1的记录delete flag设置为1,记录并没有被删除,即记录还是存在于B+树中,其次,对于辅助索引上列a等于1,b等于1的记录同样没有做任何处理,甚至没有产生undo log。而真正删除这行记录的操作其实被“延迟”了,在purge操作中完成。
在MVCC下,有可能其他事务也在引用该行记录,故InnoDB需要保存记录之前的版本,当该条记录不被任何事务所引用时,那么可以执行真正的delete操作。

doublewrite(两次写)

doublewrite能够确保InnoDB存储引擎的数据页的可靠性。
如果InnnoDB存储引擎正在写入某个页到表中,可能只写了页中的一部分就发生了宕机等故障,造成部分写失效。需要对数据进行恢复。
可能首先想到实现数据恢复的做法是利用Redo log(重做日志),但是重做日志记录的是对页的物理操作,但是如果这个页已经发生了损坏,再对其页页进行重做就没有意义了。这时就用到了doublewrite操作。
简单的说,在应用重做日志之前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做。

redo日志、undo日志、binlog日志与doublewrite分析_第1张图片
doublewrite流程

doublewrite由两部分组成,一部分是内存中的doublewrite,大小为2MB;另一部分是物理磁盘上共享表空间中连续的128个页,即两个区,大小同样我2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先复制到内存中的doublewrite buffer,之后通过double write再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。
如果操作系统在将页写入磁盘的过程中发生了崩溃,在恢复过程中,InnoDB存储引擎可以从共享表空间中的doublewrite中找到该页的一个副本,将其复制到表空间文件中,再应用重做日志。

你可能感兴趣的:(redo日志、undo日志、binlog日志与doublewrite分析)