0%

mysql的不同log类型

MySQL 更新语句的流程会涉及到 undo log(回滚日志)、redo log(重做日志) 、binlog (归档日志)这三种日志。

  • undo log(回滚日志):是 Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC。
  • redo log(重做日志):是 Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复。
  • binlog (归档日志):是 Server 层生成的日志(和存储引擎无关),主要用于数据备份和主从复制。

1. undo log

1.1 mvcc

undo log 实现 MVCC(多版本并发控制)关键因素之一。

MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。

参考:https://www.liuvv.com/p/a0f7945d.html

1.2 事务回滚

undo log(回滚日志),它保证了事务的 ACID 特性 (opens new window)中的原子性(Atomicity)。

实现事务回滚,保障事务的原子性。事务处理过程中,如果出现了错误或者用户执 行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态。

MySQL 会隐式开启事务来执行“增删改”语句的,执行完就自动提交事务的,执行一条语句是否自动提交事务,是由 autocommit 参数决定的,默认是开启。

每当 InnoDB 引擎对一条记录进行操作(修改、删除、新增)时,要把回滚时需要的信息都记录到 undo log 里,比如:

  • 在插入一条记录时,要把这条记录的主键值记下来,这样之后回滚时只需要把这个主键值对应的记录删掉就好了;
  • 在删除一条记录时,要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了;
  • 在更新一条记录时,要把被更新的列的旧值记下来,这样之后回滚时再把这些列更新为旧值就好了。

2. redo log

redo log 是物理日志,记录了某个数据页做了什么修改,在事务提交时,只要先将 redo log 持久化到磁盘即可,可以不需要等到将缓存在 Buffer Pool 里的脏页数据持久化到磁盘。

当系统崩溃时,虽然脏页数据没有持久化,但是 redo log 已经持久化,接着 MySQL 重启后,可以根据 redo log 的内容,将所有数据恢复到最新的状态。

redo log 保证了事务四大特性中的持久性。

2.1 顺序写磁盘

redo log 要写到磁盘,数据也要写磁盘,为什么要多此一举?

写入 redo log 的方式使用了追加操作, 所以磁盘操作是顺序写,而写入数据需要先找到写入位置,然后才写到磁盘,所以磁盘操作是随机写。磁盘的「顺序写 」比「随机写」 高效的多,因此 redo log 写入磁盘的开销更小。

可以说这是 WAL 技术的另外一个优点:MySQL 的写操作从磁盘的「随机写」变成了「顺序写」,提升语句的执行性能。这是因为 MySQL 的写操作并不是立刻更新到磁盘上,而是先记录在日志上,然后在合适的时间再更新到磁盘上 。

我们知道 redo log 是为了防止 Buffer Pool 中的脏页丢失而设计的,那么如果随着系统运行,Buffer Pool 的脏页刷新到了磁盘中,那么 redo log 对应的记录也就没用了。

如果redo log 文件满了,这时 MySQL 不能再执行新的更新操作,也就是说 MySQL 会被阻塞(因此所以针对并发量大的系统,适当设置 redo log 的文件大小非常重要),此时会停下来将 Buffer Pool 中的脏页刷新到磁盘中。

2.2 redo log 的 buffer

redo log 也不是直接写入磁盘的,因为这样会产生大量的 I/O 操作,而且磁盘的运行速度远慢于内存。

redo log 也有自己的缓存—— redo log buffer,每当产生一条 redo log 时,会先写入到 redo log buffer,后续在持久化到磁盘如下图:

redo log buffer 默认大小 16 MB,可以通过 innodb_log_Buffer_size 参数动态的调整大小,增大它的大小可以让 MySQL 处理「大事务」是不必写入磁盘,进而提升写 IO 性能。

主要有下面几个时机刷盘:

  • InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
  • MySQL 正常关闭时;
  • 当 redo log buffer 中记录的写入量大于 redo log buffer 内存空间的一半时,会触发落盘;
  • 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘。

2.3 和 undo log 关系

  1. undo log 会写入 Buffer Pool 中的 Undo 页面。在内存修改该 Undo 页面时,undo log也会产生redo log。
  2. redo log 记录了此次事务「完成后」的数据状态,记录的是更新之后的值;
  3. undo log 记录了此次事务「开始前」的数据状态,记录的是更新之前的值;

事务提交之前发生了崩溃,重启后会通过 undo log 回滚事务。事务提交之后发生了崩溃,重启后会通过 redo log 恢复事务。

3. bin log

binlog 是记录数据库中所有更改的日志文件。它主要记录了针对数据库执行的所有DDL(数据定义语言)和DML(数据操作语言)语句,例如插入(INSERT)、更新(UPDATE)和删除(DELETE)操作。

MySQL 在完成一条更新操作后,Server 层还会生成一条 binlog,等之后事务提交的时候,会将该事物执行过程中产生的所有 binlog 统一写入 binlog 文件。

3.1 语句组织方式

  1. 基于SQL语句的复制(statement-based replication)

Mysql 5.1.4 及之前的版本默认。只会修改数据的sql语句到binlog中,但是now()函数不一致行为。

  1. 基于行的复制(row-based replication)

记录哪条数据被修改了,修改成什么样。但是日志会非常多。

  1. 混合模式复制(mixed-based replication)

是以上两种模式的混合,对于一般的复制使用STATEMENT模式保存到binlog,对于STATEMENT模式无法复制的操作则使用ROW模式来保存,MySQL会根据执行的SQL语句选择日志保存方式。

3.2 恢复或同步全量数据

如果不小心整个数据库的数据被删除了,能使用 redo log 文件恢复数据吗?不可以使用 redo log 文件恢复,只能使用 binlog 文件恢复。

因为 redo log 文件是循环写,是会边写边擦除日志的,只记录未被刷入磁盘的数据的物理日志,已经刷入磁盘的数据都会从 redo log 文件里擦除。

binlog 文件保存的是全量的日志,也就是保存了所有数据变更的情况,理论上只要记录在 binlog 上的数据,都可以恢复,所以如果不小心整个数据库的数据被删除了,得用 binlog 文件恢复数据。

参考mysql的主从复制原理和操作:https://www.liuvv.com/p/2d45d411.html

3.3 和 redo log 的区别

  1. 适用对象不同

    binlog 是 MySQL 的 Server 层实现的日志,所有存储引擎都可以使用;
    redo log 是 Innodb 存储引擎实现的日志;

  2. 文件格式不同

    binlog 有 3 种格式类型,分别是 STATEMENT(默认格式)、ROW、 MIXED。

    redo log 是物理日志,记录的是在某个数据页做了什么修改,比如对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新;

  3. 写入方式不同

    binlog 是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量的日志。
    redo log 是循环写,日志空间大小是固定,全部写满就从头开始,保存未被刷入磁盘的脏页日志。

  4. 用途不同

    binlog 用于备份恢复、主从复制;
    redo log 用于掉电等故障恢复。

4. 头脑风暴

  • undo log 是为了实现 mvcc + 事务回滚
  • redo log 是物理日志,防止 Buffer Pool 中的脏页丢失而设计。保证数据持久性和数据恢复。
  • bin log 是用来主从复制,数据恢复和同步。

5. 参考资料

可以加首页作者微信,咨询相关问题!