Mysql-日志

by shihang.mai

1. 日志概述

日志 发生的区域 保证事务 日志类型
redolog 存储引擎 持久性 物理日志
undolog 存储引擎 原子性、隔离性 逻辑日志
binlog server端 持久性 逻辑日志

2. binlog

2.1 binlog存储方式

binlog是二进制日志文件,它记录了引起数据库改变的事件。那当然select、show是不会记录到binlog的。

  • 对于事务操作,在事务提交时,一次性写入binlog
  • 对于非事务操纵,每执行一次,就写一次binlog

2.2 binlog备份模式-STATEMENT模式

这是mysql的binlog 的默认格式。在这个模式下,binlog 只会记录可能引起数据变更的sql语句

2.2.1 优点

因为没有记录实际的数据,所以日志量和 IO 都消耗很低,性能是最优的

2.2.2 缺点

比如 uuid() 函数会随机产生唯一标识,当依赖 binlog 回放时,该操作生成的数据与原数据必然是不同的,此时可能造成无法预料的后果。
由于所有的操作都依赖于先后顺序,所以像使用 AUTO_INCREMENT 生成主键 id 的 insert 方法、数据的恢复等都必须串行执行

2.3 binlog备份模式-ROW模式

binlog 会记录每次操作的源数据与修改后的目标数据,而不会记录 sql 语句

2.3.1 优点

可以绝对精准的还原,从而保证了数据的安全与可靠
并且复制和数据恢复过程可以是并发进行的

2.3.2 缺点

binlog 体积会非常大,同时,对于修改记录多、字段长度大的操作来说性能消耗很大

2.4 binlog备份模式-MIXED模式

MIXED 模式是对上述两种模式的混合使用,对于绝大部分操作,都使用 STATEMENT 来进行 binlog 的记录,只有以下操作使用 ROW 来实现:

  1. 表的存储引擎为 NDB
  2. 使用了uuid()、user()、current_user()、found_rows()、row_count()、sysdate() 等不确定函数(now() 函数仍然会以 SBR 方式记录)
  3. 使用了 insert delay 语句
  4. 使用了临时表

3. redolog

3.1 redolog与binlog对比

依靠 binlog 是无法保证 crash safe 的,因为 binlog 是事务提交时写入的,如果在 binlog 缓存中的数据持久化到硬盘之前宕机或断电。在服务器恢复工作后,这样会导致缺失已提交的操作数据

先来看看mysql的架构图


mysql架构图.png

innodb 作为具体的一个存储引擎,它通过 redolog 实现了 crash safe 的支持

mysql 有一个基本的技术理念,Write-Ahead Logging,先写日志,再写磁盘,innodb的redolog、undolog都是这样的

redolog 与 binlog 的区别:

  1. redolog只占用预先分配的一块固定大小的磁盘空间,在这片空间中,redolog 采用循环写入的方式写入新的数据
  2. binlog 是以每条操作语句为单位进行记录的,而 redolog 则是以数据页来进行记录的。redolog记录了每个页上的修改
  3. 所以一个事务中可能分多次多条写入 redolog
redolog循环写.png

3.2 redolog的两阶段提交

以更新一条数据为例说明:

  1. 执行器先在存储引擎中找到数据.如果数据在内存中直接返回,否则查询后返回
  2. 执行器拿到数据后,修改数据,调用存储引擎接口,存储引擎重新吸入数据
  3. 存储引擎将数据更新到内存,同时写redolog,此时处于prepare状态,通知执行器已经完成
  4. 执行器生成这个操作的binlog
  5. 执行器调用存储引擎的事务提交接口,存储引擎将redolog的prepare状态变为commit,更新完成
mysql-更新数据日志流程

正因为有redolog的两阶段提交,这样在异常发生时,就可以按照下面两条策略来处理

binlog状态 redo log 状态 对策
有记录 commit 事务已经正常完成
有记录 prepare 在binlog写完、提交事务之前发生故障。此时数据完整。恢复策略:提交事务
无记录 prepare 在binglog写完之前发生故障。恢复策略:回滚
无记录 无记录 在写redo log之前发生故障。恢复策略:回滚
  1. 整个过程是一个典型的两阶段提交过程,由 binlog 充当了协调者的角色,针对每一次日志写入binlog,innodb 都会随之记录一个 8 字节序列号 – LSN(日志逻辑序列号 log sequence number),他会随着日志写入不断单调递增。

  2. binlog、DB 中的数据、redolog 三者就是通过 LSN 关联到一起的

  • DB 中的数据: 数据页上记录了 LSN、
  • binlog: 日志开始与结束均记录了 LSN
  • redolog: 刷盘节点 checkpoint 也记录了 LSN
    因此 LSN 成为了整套系统中的全局版本信息
  1. 当异常发生并重新启动后,innodb 会根据出在 prepare 状态的 redo log 记录去查找相同 LSN 的 binlog、数据记录,从而实现异常后的恢复。

3.3 redolog刷盘策略

redolog刷盘策略.png
  • 当设置为0的时候,事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。
  • 当设置为1的时候,事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。
  • 当设置为2的时候,每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。

4. undolog

undo log 主要用于数据修改的回滚,一旦数据成功修改就没用了,所以并不需要刷盘。

undolog可以理解为:

操作 undo log文件记录
Detete 记录一条对应的insert记录
Insert 记录一条对应的delete记录
update 记录一条对应相反的update记录。如果 update 的是主键,则是对先删除后插入的两个事件的反向逻辑操作的记录
  1. 在事务回滚时,我们就可以从 undo log 中反向读取相应的内容,并进行回滚
  2. 同时,我们也可以根据 undo log 中记录的日志读取到一条被修改后数据的原值(实现mvcc的关键)

4.1 undolog存储方式

innodb 通过段的方式来管理 undo log.

每一条记录占用一个 undo log segment,每 1024 个 undo log segment 被组织为一个回滚段(rollback segment)

mysql 5.6 版本以后可以通过 innodb_undo_logs 配置项设置系统支持的最大回滚段个数,默认为 128。

mysql-undolog存储方式

4.2 MVCC实现原理

  1. MVCC指的就是在使用 READ COMMITTD 、REPEATABLE READ 这两种隔离级别的事务在执行普通的 SEELCT 操作时访问记录的版本链的过程,这样子可以使不同事务的 读-写 、 写-读 操作并发执行,从而提升系统性能
  2. 核心在于生成一致性读视图(ReadView)的时机,而视图基于undolog获取历史版本信息,而这个一致性读视图保存的是当前活跃的事务id列表
  • 对于读已提交隔离级别,在每次查询时,均生成一个ReadView
  • 对于可重复读隔离级别,在事务开启时,生成一个ReadView,并且这个ReadView是对整个库而言的,每次查询都用这个ReadView

4.2.1 加入隐藏字段

innodb会在每行数据后加入3列隐藏字段

字段 解析
DB_ROW_ID 单调递增的行 ID
DB_TRX_ID 记录插入或更新该行的最后一个事务的事务 ID
DB_ROW_PTR 指向该行对应的 undolog 的指针

4.2.2 事务ID

  1. 在InnoDB 中每一个事务都有一个自己的事务id,并且是唯一的。没开启一个事务,这个事务id递增
  2. 在开启事务时,事务系统会将ReadView传递给这个新事务
  3. 在每次事务更新数据的时候,都会生成一个新的数据版本,并且隐藏字段DB_TRX_ID = 自己的事务id

MVCC的某记录ReadView.png

获取历史版本信息时,通过隐藏字段DB_ROW_PTR保存的undolog指针,找到对应的undolog获取信息

4.2.3 判断一条数据是否在当前事务可见的依据

MVCC版本链读取的判断.png

读取的这一行数据的 DB_TRX_ID 在 DB_TRX_ID array 中或大于当前事务的事务 ID,那么就说明这行数据是在当前事务开启后提交的,否则说明这行数据是在当前事务开启前提交的

  • 对于当前事务开启后提交的数据,进行快照读,当前事务需要通过隐藏的 DB_ROLL_PTR 字段找到 undo log,然后进行逻辑上的回溯才能拿到事务开启时的原数据
  • 对于当前事务开启前提交的数据,进行当前读,直接查就可以了

4.3 undo log 的清理

在回滚段中,每个 undo log 段都有一个类型字段,共有两种类型:

  1. insert undo logs 。insert语句的反向逻辑
  2. update undo logs。delete、update语句反向逻辑
  • 如果事务 rollback,随后就会删除该事务关联的所有 undo log 段。
  • 如果事务 commit,对于 insert undo logs,innodb 会直接清除。但对于 update undo logs,为了提供 MVCC机制,只有当前没有任何事务存在时,innodb 的 purge 线程才会清理这些 undo log 段。

参考博客:

https://blog.csdn.net/diligent203/category_9339993.html
https://zhuanlan.zhihu.com/p/148035779

你可能感兴趣的:(Mysql-日志)