mysql-事物实现原理

MySQL-事务的实现-redo


MySQL中事务:html

  1. 事务的实现:

     ACID:sql

    • 原子性(A : Atomicity)
    • 一致性(C : consistency )
    • 隔离性(I : isolation)
    • 持久性(D : durability )
  1. 实现方式:
    • 隔离性:经过锁来实现
    • 原子性和持久性:经过redo log 来实现
    • 一致性:经过undo来实现
  1. redo 和 undo 比较:

        都是恢复操做:数据库

    1. redo:恢复提交事务修改的页操做
    2. undo: 回滚行记录到某个特定版本

       记录内容不一样:数组

    1. redo: 是物理日志,记录的是物理的修改操做
    2. undo: 是逻辑日志,根据每行记录进行记录

       读取方式不一样:缓存

    1. redo : 在数据库运行时,不须要读取操做(注:数据库恢复时,才用redo)
    2. undo : 在数据库运行时,须要随机读取(注:回滚时用)

 

 

redo-在事务中的应用安全

1.基本概念性能

【事务持久性:D】-- 【重作日志来实现】ui

【持久性构成】:1.重作日志缓冲(redo log buffer) ,是易失的 2.重作日志文件(redo log file),是持久的spa

【持久性原理】:InnoDB是事务的存储引擎,经过Flush Log at Commit机制实现事务的持久性。即:当事务提交(Commit)时,必须先将事务的全部日志(这里只重作日志)写入到重作日志文件中,进行持久化,待事务的commit完成才算完成。操作系统

【事务的全部日志】:在InnoDB中,事务的全部日志有两部分:redo log 和 undo log 

 

【fsync操做】:为了确保每次重作日志都写入重作日志文件,在将重作日志缓冲写入重作日志文件后,InnoDB存储引擎都须要调用一次fsync操做。

【innodb_flush_method = O_DIRECT/NULL】: 控制InnoDB数据文件和redo log 文件打开,刷写模式。

     1.设置为NULL时,默认是:fsync选项。过程:重作日志缓冲先写入文件系统缓存,再进行fsync(将日志刷新到重作日志文件 )操做。依赖磁盘的性能。

     2.设置为O_DIRECT,过程:调用用O_DIRECT打开数据文件, 而后调用:fsync(),将全部刷新到数据和log文件中。不通过操做系统缓存,避免两次写操做

【非持久性】:经过手工设置非持久性来提升数据库性能。

     原理:事务提交时,日志不写入重作日志文件,而是等待一个周期后,再执行fsync操做。不是强制每次提交都fsync,能够显著提升性能。

      弊端:若是数据库发生宕机,因为部分日志未刷新到磁盘,会丢失最后一段的事务。

【innodb_flush_log_at_trx_commit = 0/1/2】:该参数控制重作日志刷新到磁盘的策略。

     1 : 默认是1,表示事务提交时必须调用一次fsync,<redo log刷新条件之一:事务提交前必刷新到日志文件>。遵循ACID的持久性

     0 : 事务提交时,不进行写重作日志操做.写的操做仅在master Thread中完<redo log 刷新条件之二>,大概每隔1秒执行一次fsync操做.在1秒内有数据库宕机丢数据的风险.

     2 : 写重作日志文件,但仅仅写入文件系统缓存中,不进行fsync操做。仅数据库宕机系统正常,不会丢数据。 系统宕机,缓存中未刷新到重作日志文件的那部分事务会丢失.

总结:0和2能提升事务提交性能,可是这种状况丧失了事务的ACID特性,所以在大量执行insert操做时,在最后执行一次commit操做。这样回滚时能够回滚到事务最开始的状态.

 

Innodb存储引擎使用中,为了遵循持久性和一致性,关于复制的设置:

     1.若是启用二进制日志(binlog),设置: sync_binlog=1;

     2.同时也设置: innodb_flush_log_at_trx_commit=1.

 

【sync_binlog = N】:

     N=0,事务提交后,不作fsync之类的磁盘同步指令,刷新binlog_cache到磁盘文件,而是让文件系统自行决定什么时间同步。性能高,可是有丢失数据的风险.

     N=1,1次事务提交后,执行fsync操做,将binlog chace同步到磁盘文件。这种选择是最安全的,可是是最慢的.

【binlog和redo log比较】:

     1.产生层面不一样

     redo log: 是在存储引擎层产生,只针对InnoDB存储引擎

     binlog:在数据库上层产生的.MySQL中任何存储引擎对数据库的更改都会产生二进制日志.

     2.记录内容形式不一样

     redo log: 是物理格式的日志,记录的是对于每一个页的修改.

     binlog: 是一种逻辑日志,记录的是sql语句.

     3.写入磁盘时间不一样

     redo log: 在事务进行中不断的写入.不随事务的提交而提交,不是顺序写入的.

     binlog: 在事务提交后进行写入.

 

2.日志块的结构

在InnoDB存储引擎中,重作日志都是以512字节进行存储的.也就是说重作日志缓冲,重作日志文件都是以块(block)的方式进行保存.称为:重作日志块(redo log block),大小:512字节.

若是一个页中产生的重作日志大于512字节,就分割成多个重作日志块就行存储.

重作日志块的大小和磁盘扇区的大小同样,512字节,所以重作日志的写入能够保证原子性不须要doublewrite技术.

 

日志块的组成:日志自己,日志块头(log block header),日志块尾(log block tailer)

 

 

Log Block Header 解析:

 

LOG_BLOCK_HDR_NO:4字节

log buffer由log block组成,在内部就像一个数组,而LOG_BLOCK_HDR_NO,用来标记这个数组中的位置。改制必须大于0,容许最大2G;若是在日志刷新写入段时,是第一个日志块,最高位就设置成1.

LOG_BLOCK_DATA_LEN:2字节

表示LOG_BLOCK所占用的大小,被写满时,该值为:0x200,表示所有block空间,即占用512字节。

LOG_BLOCK_FIRST_REC_GROUP:占用2字节

表示LOG_BLOCK中第一个日志所在的偏移量。若是LOG_BLOCK_FIRST_REC_GROUP=LOG_BLOCK_DATA_LEN 表示log block不包含新的日志。

LOG_BLOCK_CHECKPOINT_NO:4字节

表示:LOG_BLOCK最后被写入时的检查点。若是此时log block还没写满,只能等下次log flush 时,才会更新。

 

关于一个事务占用两个log block的图:

事务T1的重作日志占用:696字节

事务T2的重作日志占用:100字节

有图知道:事务T1 696字节,占用两个log block,左侧的log block中 LOG_BLOCK_FIRST_REC_GROUP=12,即第一个日志开始的位置。

在第二个block中,因为包含了T1的重作日志,所以事务T2的重作日志才是block中的第一个日志,即 LOG_BLOCK_FIRST_REC_GROUP=(12+200)=212

 

3.重作日志组(log group)

 

log group为重作日志组,里面有多个重作日志文件。源码中支持log group的镜像功能,但已禁用了,所以InnoDB存储引擎实际只有1个log group。

 

log group 是逻辑上的概念!!!

 

重作日志存储的就是以前在log buffer中保存的块,所以也是根据块的方式进行物理存储的管理。block=512bytes。

 

InnoDB存储引擎运行过程当中, log buffer根据必定的规则将log block刷新到磁盘:

     1.事务提交时

     2.当log buffer中一半的空间已经被使用

     3.log checkpoint时

 

redo log file的写入顺序:

     log block 写入追加到redo log file的最后部分,当一个redo log file写满时,会写入下一个redo log file。 这种方式:round-robin.

     看起来是顺序的,其实否则,除了保存log buffer刷新到磁盘的log block,还保存了一些其余信息,这些信息占:2KB,即redo log file 的前2KB不保存log block的信息。

 

2KB的信息:保存 4 * 512字节的 块。

 

名称

大小(字节)

log file header

512

checkpoint1

512

512

checkpoint2

512

 

 

 

 

 

 

上述信息只在log group的第一个redo log file里存储,其他file留空,这也就是说 写入不是顺序的!以下图:

 

 

4.重作日志的格式

 

 

5.LSN

LSN : Log Sequence Number的缩写,表明日志序列号,单位:字节。在innodb存储引擎中占有8字节,单调递增。

LSN : 表示的含义

  1. 重作日志写入的总量
  2. checkpoint的位置
  3. 页的版本

LSN 表示事务写入重作日志的字节总量。例如,当前重作日志的LSN是1000,事务T1写入了100字节的重作日志,LSN就变成1100,又有事务T2写入200字节的重作日志,那么LSN变成:1300.

 

LSN不只记录在重作日志中,还记录在页中。每一个页的开头部有一个FIL_PAGE_LNS,记录该页的LSN。

页中的LSN表示:该页最后刷新时LSN的大小。

重作日志记录的是每一个页的物理更改日志,所以页中的LSN用来判断是否须要进行恢复操做。例如:页的LSN为:10000,数据库启动时,写入重作日志的LSN:13000,代表该事务已经提交,数据库须要恢复;重作日志中的LSN小于页中的LSN,不须要进行重作,由于页中的LSN表示已经刷新到该位置。

 

经过:SHOW ENGINE INNODB STATUS\G来查看LSN的状况

---

LOG

---

Log sequence number 47324552     ----------------->表示当前的LSN

Log flushed up to   47324552     ----------------->表示刷新到重作日志的LSN

Pages flushed up to 47324552     ----------------->表示刷新到磁盘的LSN

Last checkpoint at  47324552

Max checkpoint age    80826164

Checkpoint age target 78300347

....

 

上述的3个值,生产环境中多是不一样的:由于一个事务从重作日志缓冲刷新到重作日志文件,并不仅是在事务提交时发生,每秒都会有重作日志缓冲刷新到重作日志文件的操做。

 

6.恢复

 

InnoDB存储引擎在启动时,无论上次数据库是否正常关闭,都会尝试进行恢复。重作日志是物理日志,恢复时比较快。

checkpoint 表示已经刷新到磁盘上的LSN。

 

例子:redo log file 记录的LSN:13000,刷新到磁盘上的LSN:10000,数据库在10000处宕机,恢复时,只需恢复10000~13000的部分。

 

 

--完结

相关文章
相关标签/搜索