一、事务日志介绍
参照mysql5.5的中文说明;
Innodb的事务日志是指Redo log,简称Log,保存在日志文件ib_logfile*里面。Innodb还有另一个日志Undo log,但Undo log是存放在共享表空间里面的(ibdata*文件)。mysql
因为Log和Checkpoint紧密相关,所以将这两部分合在一块儿分析。linux
名词解释:LSN(log serial number),日志序列号,Innodb的日志序列号是一个64位的整型
1.1log的写入机制:sql
LSN实际上对应日志文件的偏移量,新的LSN=旧的LSN + 写入的日志大小。举例以下:安全
LSN=1G,日志文件大小总共为600M,本次写入512字节,则实际写入操做为:async
l 求出偏移量:因为LSN数值远大于日志文件大小,所以经过取余方式,获得偏移量为400M;日志
l 写入日志:找到偏移400M的位置,写入512字节日志内容,下一个事务的LSN就是1000000512;
1.2Checkpoint写入
Innodb实现了Fuzzy Checkpoint的机制,每次取到最老的脏页,而后确保此脏页对应的LSN以前的LSN都已经写入日志文件,再将此脏页的LSN做为Checkpoint点记录到日志文件,意思就是“此LSN以前的LSN对应的日志和数据都已经写入磁盘文件”。恢复数据文件的时候,Innodb扫描日志文件,当发现LSN小于Checkpoint对应的LSN,就认为恢复已经完成。
Checkpoint写入的位置在日志文件开头固定的偏移量处,即每次写Checkpoint都覆盖以前的Checkpoint信息。
1.3管理机制
因为Checkpoint和日志紧密相关,将日志和Checkpoint一块儿说明,详细的实现机制以下
如上图所示,Innodb的一条事务日志共经历4个阶段:事务
l 建立阶段:事务建立一条日志;it
l 日志刷盘:日志写入到磁盘上的日志文件;innodb
l 数据刷盘:日志对应的脏页数据写入到磁盘上的数据文件;ast
l 写CKP:日志被看成Checkpoint写入日志文件;
对应这4个阶段,系统记录了4个日志相关的信息,用于其它各类处理使用:
l Log sequence number(LSN1):当前系统LSN最大值,新的事务日志LSN将在此基础上生成(LSN1+新日志的大小);
l Log flushed up to(LSN2):当前已经写入日志文件的LSN;
l Oldest modified data log(LSN3):当前最旧的脏页数据对应的LSN,写Checkpoint的时候直接将此LSN写入到日志文件;
l Last checkpoint at(LSN4):当前已经写入Checkpoint的LSN;
对于系统来讲,以上4个LSN是递减的,即: LSN1>=LSN2>=LSN3>=LSN4.建立日志的LSN最大,写入checkpoint的lsn是最小的;
show engine innodb status \G;
---
LOG
---
Log sequence number 16953660229
Log flushed up to 16953660229
Last checkpoint at 16953652205
1.4保护机制
Innodb的数据并非实时写盘的,为了不宕机时数据丢失,保证数据的ACID属性,Innodb至少要保证数据对应的日志不能丢失。对于不一样的状况,Innodb采起不一样的对策:
宕机致使日志丢失
Innodb有日志刷盘机制,能够经过innodb_flush_log_at_trx_commit参数进行控制;
日志覆盖致使日志丢失
Innodb日志文件大小是固定的,写入的时候经过取余来计算偏移量,这样存在两个LSN写入到同一位置的可能,后面写的把前面写得就覆盖了,以“写入机制”章节的样例为例,LSN=100000000和LSN=1600000000两个日志的偏移量是相同的了。这种状况下,为了保证数据一致性,必需要求LSN=1000000000对应的脏页数据都已经刷到磁盘中,也就是要求Last checkpoint对应的LSN必定要大于1000000000,不然覆盖后日志也没有了,数据也没有刷盘,一旦宕机,数据就丢失了。
为了解决第二种状况致使数据丢失的问题,Innodb实现了一套日志保护机制,详细实现以下:
上图中,直线表明日志空间(Log cap,约等于日志文件总大小*0.8,0.8是一个安全系数),Ckp age和Buf age是两个浮动的点,Buf async、Buf sync、Ckp async、Ckp sync是几个固定的点。各个概念的含义以下:
当事务执行速度大于脏页刷盘速度时,Ckp age和Buf age会逐步增加,当达到async点的时候,强制进行脏页刷盘或者写Checkpoint,若是这样作仍是赶不上事务执行的速度,则为了不数据丢失,到达sync点的时候,会阻塞其它全部的事务,专门进行脏页刷盘或者写Checkpoint。 所以从理论上来讲,只要事务执行速度大于脏页刷盘速度,最终都会触发日志保护机制,进而将事务阻塞,致使MySQL操做挂起。 因为写Checkpoint自己的操做相比写脏页要简单,耗费时间也要少得多,且Ckp sync点在Buf sync点以后,所以绝大部分的阻塞都是阻塞在了Buf sync点,这也是当事务阻塞的时候,IO很高的缘由,由于这个时候在不断的刷脏页数据到磁盘。例如以下截图的日志显示了不少事务阻塞在了Buf sync点: 参考资料:linux公社谋篇文章