MySQL之7---InnoDB 和 事务流程、Crash Recovery、ACID

时间:2021-01-08 11:24:46   收藏:0   阅读:0

MySQL之7---InnoDB 和 事务流程、Crash Recovery、ACID

InnoDB术语和概念

InnoDB概述图

技术图片


表数据


重做日志 (Redo Log)


撤消日志(Undo Log)


日志序列号(LSN)


检查点(Checkpoint)


回滚指针(ROLL_PTR)


事务ID号(TRX_ID)


事务的工作流程原理

技术图片

① 事务start(事务首次开启)

② Update(每次只修改一行记录)

此时其他事务:

  • 一旦记录被修改,即使没有提交,其他事务也可能会看到被修改后的记录,这依赖于他们的事务隔离级别而定
    • 如果是RU隔离级别,则使用索引页读取最新版本记录
    • 如果是RU隔离级别,则查找记录的最新提交版本
    • 如果是RR隔离级别,则查找与其read view相对应的记录版本
  • 任何需要使用索引页来读取比最新的版本记录旧的版本记录时,都必须使用Undo Log来重建之前的版本记录

③ 事务提交(显式或隐式)

④ 后台线程刷脏

触发方式:

执行流程:

PS:对于后台线程刷脏部分,执行刷新脏页时,与该脏页的事务是否提交无关,只需要确保该页对应LSN号的Redo Log记录落盘,而不会去判断事务的状态是否是提交还是未提交状态,因为,数据页结构中并没有地方单独记录事务的状态(即,无法判断事务是否提交),只是在每行数据中有记录事务号、回滚段指针(所以一个页中也可能包含多个事务的修改记录)。当需要对某个事务进行回滚时,重新从表空间中读取这个未提交的脏页,使用undo log中的反向数据进行反向修改,然后再重新刷脏。

Creash Recovery

触发条件

① 检测实例是不是干净地关闭的

  1. 打开Redo Logs和系统表空间文件(ibdataN)
  2. 读取并从中找到最大的Checkpoint LSN
  3. 从最近的Checkpoint 开始往后扫描Redo Log
  4. 如果能够找到Redo Log记录,说明还有数据页的更改没有刷新到数据文件上,启动Crash Recovery,使用Redo Log来恢复数据的一致性

② 前滚恢复实例

原理:使用所有独立表空间的表名和表空间ID创建一个名称到ID的映射

  1. 打开datadir下的所有.ibd文件
  2. 在这些表空间文件的offset 0的页(FSP_HDR页)头读取其表空间ID(FSP_HDR页中FSP Header的前四个字节记录着表空间ID)
  3. 将表空间ID与表名建立映射

PS:

③ 损坏页修复

④ 回滚未提交事务


InnoDB和ACID模型

原子性 A

ACID模型 的原子性方面主要涉及InnoDB 事务。相关的MySQL功能包括:


一致性 C

ACID模型 的一致性方面主要涉及内部InnoDB处理,以防止数据崩溃。相关的MySQL功能包括:


隔离性 I

ACID模型 的隔离性方面主要涉及InnoDB事务,尤其是适用于每个事务的隔离级别。相关的MySQL功能包括:


持久性 D

ACID模型 的持久性方面涉及与特定硬件配置交互的MySQL软件功能。相关的MySQL功能包括:


前滚(redo log)和回滚(undo log)

InnoDB核心特性:自动故障恢复。先前滚再回滚,先应用redo再应用undo。

Redo Log 应用在事务ACID过程中,实现的是“D”持久化的作用,对于AC也有相应的作用。

Undo Log 应用在事务ACID过程中,实现的是“A” 原子性的作用,对于CI也有相应的作用。


  1. 用户发起事务语句(begin;DML;commit;

  2. begin;,立即分配一个TXID=tx_01

  3. DML;,将需要修改的磁盘数据页(PageNo=10,数据,LSN=3515),加载到内存(buffer_pool)缓冲区。

  4. 申请 undo log 日志空间,保存数据到回滚日志(逆向操作的逻辑日志)

  5. 记录 undo log 操作到redo log

  6. DBWR线程,在内存中,修改数据页头部(记录TRX_ID+ROLL_PTR),更新数据页(PageNo=10,变化的数据,LSN=3515+变化的字节)形成脏页。

  7. LOGBWR日志写线程,将 数据页的变化 + LSN=3515+变化的字节 + TXID 存储到 redo buffer

    如果此时系统宕机,内存数据会全部丢失:

    1. MySQL再次启动时,触发CR(自动故障恢复),检测buffer_pool和磁盘数据页的LSN是否一致。
    2. log buffer LSN = 数据页 LSN :不需要进行前滚和回滚。undolog直接被标记为可覆盖状态。MySQL正常启动。
  8. commit;,LOGBWR线程,将redo buffer写入磁盘中的redolog日志文件(ib_logfileN)。

    基于批量刷写redo机制:在事务commit时,会顺便将redo buffer中其他未提交的redolog也一并刷到磁盘。日志记录时,使用COMMIT标记区分状态。

    基于WAL(日志先行)机制:在日志完全写入磁盘后,给此日志打上commit标记,commit命令才算执行成功。

  9. 此时 binlog 完全写入磁盘,但脏页没有写入磁盘,由其他后台线程检测刷脏(CheckPoint

    如果此时系统宕机,内存数据会全部丢失:

    1. MySQL再次启动时,触发CR(自动故障恢复),检测buffer_pool和磁盘数据页的LSN是否一致。
    2. log buffer LSN > 数据页 LSN :加载ib_logfileN到log buffer,磁盘数据页到buffer_pool。使用redolog重构脏页(前滚)。
      1. 如果确认此次事务已提交(有commit标签),立即触发CKPT,将脏页刷写到磁盘上。
      2. 如果确认此次事务未提交(没有commit标签),立即触发回滚操作(等同执行rollback;),根据DB_TRX_ID + DB_ROLL_PTR,找到undolog,实现回滚。
    3. 此时磁盘数据页LSN和redolog LSN 一至。MySQL正常启动。

Flush磁盘参数

innodb_flush_log_at_trx_commit(双一标准之一)

innodb_flush_log_at_trx_commit 作用:控制innodb将log buffer中的数据,写入日志文件并flush磁盘的时间点。

select @@innodb_flush_log_at_trx_commit;

参数说明

0:每秒写入一次日志并将其刷新到磁盘。未刷新日志的事务可能会在崩溃中丢失。
1:每次事务提交时,日志都会写入并刷新到磁盘。完全符合ACID,默认设置。
2:在每次事务提交后写入日志,并每秒刷新一次到磁盘。未刷新日志的事务可能会在崩溃中丢失。

Innodb_flush_method

技术图片

Innodb_flush_method 作用:控制的是,log buffer 和data buffer,刷写磁盘的时候是否经过文件系统缓存。

select @@innodb_flush_method;

参数说明

fsync或0: 刷新日志和数据缓冲区到磁盘,都走OS buffer
O_DSYNC或1: 刷新日志缓冲区到磁盘,不走OS buffer
O_DIRECT或4: 刷新数据缓冲区到磁盘,不走OS buffer

官方参数说明

fsync或0: InnoDB使用fsync()数据和日志文件。默认设置。
O_DSYNC或1: InnoDB使用O_SYNC打开和刷新日志文件,使用fsync()刷新数据文件。
O_DIRECT或4: InnoDB使用O_DIRECT打开数据文件,使用fsync()刷新数据和日志文件。
O_DIRECT_NO_FSYNC: InnoDB在刷新I/O期间使用O_DIRECT,但在每次写操作后跳过fsync()。

使用建议

# 最高安全模式
innodb_flush_log_at_trx_commit=1
Innodb_flush_method=O_DIRECT
# 最高性能模式
innodb_flush_log_at_trx_commit=0
Innodb_flush_method=fsync

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!