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 来实现:
- 表的存储引擎为 NDB
- 使用了uuid()、user()、current_user()、found_rows()、row_count()、sysdate() 等不确定函数(now() 函数仍然会以 SBR 方式记录)
- 使用了 insert delay 语句
- 使用了临时表
3. redolog
3.1 redolog与binlog对比
依靠 binlog 是无法保证 crash safe 的,因为 binlog 是事务提交时写入的,如果在 binlog 缓存中的数据持久化到硬盘之前宕机或断电。在服务器恢复工作后,这样会导致缺失已提交的操作数据
先来看看mysql的架构图
innodb 作为具体的一个存储引擎,它通过 redolog 实现了 crash safe 的支持
mysql 有一个基本的技术理念,Write-Ahead Logging,先写日志,再写磁盘
,innodb的redolog、undolog都是这样的
redolog 与 binlog 的区别:
- redolog只占用预先分配的一块固定大小的磁盘空间,在这片空间中,redolog 采用循环写入的方式写入新的数据
- binlog 是以每条操作语句为单位进行记录的,而 redolog 则是以数据页来进行记录的。redolog记录了每个页上的修改
所以一个事务中可能分多次多条写入 redolog
3.2 redolog的两阶段提交
以更新一条数据为例说明:
- 执行器先在存储引擎中找到数据.如果数据在内存中直接返回,否则查询后返回
- 执行器拿到数据后,修改数据,调用存储引擎接口,存储引擎重新吸入数据
- 存储引擎将数据更新到内存,同时写redolog,此时处于prepare状态,通知执行器已经完成
- 执行器生成这个操作的binlog
- 执行器调用存储引擎的事务提交接口,存储引擎将redolog的prepare状态变为commit,更新完成
正因为有redolog的两阶段提交,这样在异常发生时,就可以按照下面两条策略来处理
binlog状态 | redo log 状态 | 对策 |
---|---|---|
有记录 | commit | 事务已经正常完成 |
有记录 | prepare | 在binlog写完、提交事务之前发生故障。此时数据完整。恢复策略:提交事务 |
无记录 | prepare | 在binglog写完之前发生故障。恢复策略:回滚 |
无记录 | 无记录 | 在写redo log之前发生故障。恢复策略:回滚 |
整个过程是一个典型的两阶段提交过程,由 binlog 充当了协调者的角色,针对每一次日志写入binlog,innodb 都会随之记录一个 8 字节序列号 – LSN(日志逻辑序列号 log sequence number),他会随着日志写入不断单调递增。
binlog、DB 中的数据、redolog 三者就是通过 LSN 关联到一起的
- DB 中的数据: 数据页上记录了 LSN、
- binlog: 日志开始与结束均记录了 LSN
- redolog: 刷盘节点 checkpoint 也记录了 LSN
因此 LSN 成为了整套系统中的全局版本信息
- 当异常发生并重新启动后,innodb 会根据出在 prepare 状态的 redo log 记录去查找相同 LSN 的 binlog、数据记录,从而实现异常后的恢复。
3.3 redolog刷盘策略
- 当设置为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 的是主键,则是对先删除后插入的两个事件的反向逻辑操作的记录 |
- 在事务回滚时,我们就可以从 undo log 中反向读取相应的内容,并进行回滚
- 同时,我们也可以根据 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。
4.2 MVCC实现原理
- MVCC指的就是在使用 READ COMMITTD 、REPEATABLE READ 这两种隔离级别的事务在执行普通的 SEELCT 操作时访问记录的版本链的过程,这样子可以使不同事务的 读-写 、 写-读 操作并发执行,从而提升系统性能
-
核心在于生成一致性读视图(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
- 在InnoDB 中每一个事务都有一个自己的事务id,并且是唯一的。没开启一个事务,这个事务id递增
- 在开启事务时,事务系统会将ReadView传递给这个新事务
- 在每次事务更新数据的时候,都会生成一个新的数据版本,并且隐藏字段DB_TRX_ID = 自己的事务id
获取历史版本信息时,通过隐藏字段DB_ROW_PTR保存的undolog指针,找到对应的undolog获取信息
4.2.3 判断一条数据是否在当前事务可见的依据
读取的这一行数据的 DB_TRX_ID 在 DB_TRX_ID array 中或大于当前事务的事务 ID,那么就说明这行数据是在当前事务开启后提交的,否则说明这行数据是在当前事务开启前提交的
- 对于当前事务开启后提交的数据,进行快照读,当前事务需要通过隐藏的 DB_ROLL_PTR 字段找到 undo log,然后进行逻辑上的回溯才能拿到事务开启时的原数据
- 对于当前事务开启前提交的数据,进行当前读,直接查就可以了
4.3 undo log 的清理
在回滚段中,每个 undo log 段都有一个类型字段,共有两种类型:
- insert undo logs 。insert语句的反向逻辑
- 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