innodb的logs:生成过程

  这篇是25号参加互动出版和北京GDG举办的数据库分享会的个人总结。Qunaer的王竹峰先生分享了他对innodb的log的认识和总结,主要包括了下面部分:innodb日志生成,日志文件/格式,redo、undo、doublewrite。

innodb的日志

  mysql server的日志包括:bin-log(二进制日志),relay-log(中继日志),slow-log(慢查询日志),log(查询日志),error-log(错误日志)。

  innodb的日志除了上面五种类型,为了实现事务,提高io性能,增强数据安全,其他原因,增加了下面日志机制:log_buffer,log_file,redo log,undo_log,重点是这一部分。

innodb的日志生成

名词解释:

(1)checkpoint,最近一次被修改的page成功flush磁盘时候的lsn,需要了解:

  1)每次数据页有变化并被flush进磁盘的时候,都会产生一个checkpoint。

  2)innodb将修改页从buffer pool刷进data file的时候,是一批操作,而不是一次写入。

  3)checkpoint采用Fuzzy Checkpoint,即每次取最早的dirty page,确认此page之前的page都已经刷入磁盘,以此page的lsn为checkpoint的点。

  4)checkpoint被记录在logfile开始的固定偏移位置上,并覆盖之前的checkpoint点。

(2)lsn,在mysql中是log sequence number的缩写。

  1)lsn在mysql 5.6.3以前是一个4字节的无符号整数,最大值是2^32,5.6.3及以后为8字节无符号整数,最大值为2^64。

  2)实例初始化时刚创建时lsn为0(当时还没有ib_logfile),以后就按照写入的内容大小来增长,lsn=前1个lsn值+增量;

  3)ib_logfile每次增长512字节。

  4)操作写入log buffer时,产生新的lsn。

  5)每次写入log buffer时,确认log buffer剩余空间是否够存放,不够,则把buffer里的内容刷入logfile。并更新log buffer的lsn,logfile的lsn。

(3)undo_log是待修改的原数据的一个备份,存放在共享空间ibdata中中的。当事务执行失败或rollback的时候,用undo_log将数据恢复到执行之前。

    undo_log记录的是完整的page还是待修改的数据行?是完整的page。

(4)redo_log事务日志,是对数据修改操作的备份,存放在ib_logfile*文件中,由innodb_log_file_size,innodb_log_files_in_group,innodb_log_group_home_dir三个参数定义,当然还有其他的参数。假设如下设置:

    innodb_log_file_size=256M

    innodb_log_files_in_group=3

定义了三个ib_logfile文件,logfile编号从0开始,每个大小256M,那么redo_log会按照下面顺序来日志:

 

先写入log_file0,之后logfile1,再满logfile2,再慢覆盖写logfile0,如此循环。

  logfile的每次操作以512字节对齐。

  redo_log记录的是什么?不是page,不是操作,是一种称作“生理”日志的记录,它的结构如下:

Type spaceid offset data

  Type:日志记录类型,1字节。最高位!
  Space:表空间,compressed整形,1-5字节!
  Offset:页号,compressed整形,1-5字节
  Data: 根据不同的TYPE有不同的格式!

(5)undo的redo_log

innodb在修改page之前,会将数据行存放进undo_log空间,并且将这个操作记录进log_buffer,被存入redo_log,这个操作就是undo的redo_log。此操作被计入mtr中。在logfile中记录如下:

记录1: <trx1, Undo log insert <undo_insert …>>
记录2: <trx1, insert …>
记录3: <trx2, Undo log insert <undo_update …>>
记录4: <trx2, update …>
记录5: <trx3, Undo log insert <undo_delete …>>
记录6: <trx3, delete …>

(6)Miti-Transcation(MTR)

  mysql操作的最小单元是数据页,每个操作可能是一个page或者n个page的连续操作,这些操作被包含在mtr中。mtr是在1或n个page上操作的集合,具有不可分割性,一致性。

  1)一致性。在n个page上的操作不可分割时,这些page的操作记录被包含在同一个mtr中,一起被提交到redo log buffer。InnoDB在redo log的层面,将一个MTR中的所有日志作为Redo log的最小单元。在恢复时,一个MTR完整才能进行操作。

  2)mtr的封装。如果一个mtr只对一个page操作,并且只有1行记录,那么在mtr开始添加MLOG_SINGLE_REC_FLAG;如果一个mtr有n行记录,则在mtr结尾添加MLOG_MULTI_REC_END。

  3)一个mtr被提交到log_buffer后,mtr相关的page获取同一个lsn,并且这些page被加入buffer_pool的flush_list。

    4)mtr加的page_lock确保同一个page同时只能被一个mtr访问。mtr提交之后(被计入log buffer),page锁被释放,锁类型包括mtr_s_lock或mtr_x_lock。

  5)mtr不能回滚,只能提前预判执行会不会失败。

redo-log生成的流程,请看下图:

 注:图是我自己查资料画的,肯定有很多不对的地方,尤其红色部分,自己没有确认过。

这个过程有4个lsn

lsn1:mtr计入log_buffer的时候,对log_buffer的lsn进行更新。这个lsn也是mtr对应脏页上的lsn

lsn2:log_buffer刷进redo_log的时候,对redo_log的lsn进行更新。

lsn3:Dirty page被flush进datafile的时候,更新对应data page的lsn。

lsn4:在log_file中产生的CKP(checkpoint)的lsn。

同一时间点的这四个lsn有下面大小关系:lsn1 >= lsn2 >= lsn3 >= lsn4(ckp)

查看show engine innodb statusG;

---
LOG
---
Log sequence number 1632169
Log flushed up to   1632169
Pages flushed up to 1632169
Last checkpoint at  1632169
0 pending log writes, 0 pending chkp writes
8 log i/o's done, 0.00 log i/o's/second

lsn1~4分别对应这4行状态。看到这四个值相等,表示所有数据均已写入datafile,buffer_pool中没有脏页。

在mysql5.1中,没有data page刷新 Pages flushed up to 这一行。

Log flushed up在什么时候执行

1)log_buffer剩余空间不足

2)master线程控制刷新

3)执行修改语句时检查,需要则刷新

4)生成CKP时

5)事务提交(由flush_log_at_trx_commit参数控制)

double_write

double_write,通过innodb_doublewrite参数控制,是在修改的page被刷入磁盘的时候,先将page写入存入一块预先分配好的连续的磁盘区,这块磁盘区大小为100个page,再从这个区域里将文件刷入硬盘。

这样有什么好处?防止page刷新进行到一半的时候,因为断电,机器故障等情况导致的partial-page-writes

参考:http://dinglin.iteye.com/blog/906761

     http://blog.csdn.net/yunhua_lee/article/details/6567869

     http://dev.mysql.com/doc/refman/5.6/en/glossary.html

   http://www.mysqlperformanceblog.com/2006/08/04/innodb-double-write/

原文地址:https://www.cnblogs.com/wyett/p/mysql_innodb_logs1.html