MySQL的InnoDB存储引引擎的物理文件存储体系中,除了实际的数据文件(ibd, ibdata)以外,还有两个很是重要的日志系统,分别是redo日志和undo日志。 跟Oracle相似, redo log记录了对实际数据文件的物理变动(数据文件的什么位置数据作了如何的变动)。InnoDB也是采用了WAL(日志优先落盘),也就是说在实际数据文件的修改落盘以前redo日志已经落盘,从而来保证事务的持久性。Undo日志用来保证事务的原子性和MVCC,全部的undo操做产身的数据文件的变动也会记录到redo日志中。
在原生的MySQL中,redo日志不会用来作物理主从复制,其主要的应用场景是用来进行MySQL的Crash Recovey(崩溃恢复)。关于MySQL InnoDB的崩溃恢复会在后续的文章中进行介绍。
本文主要基于MySQL 8.0介绍redo Log的基本构成。
1. redo 日志文件
从MySQL 5.6开始,已经废弃了日志组的特性(redo日志能够写多份),网上有观点认为多是InnoDB的开发团队认为用外层的存储硬件来保证日志组的完整性可能更好一些。同时从5.7开始InnoDB的归档日志Archive也被放弃(归档日志用来归档存放全部的redo日志,redo日志系统内是采用固定尺寸的多个log文件循环写的方式来存放redo日志,若是写满了会循环到开始的位置开始写入)。
不过MySQL 8.0引入一个称之为克隆的机制,从代码的角度来看,彷佛是用来实现远程克隆一个当前数据库的副本,在这个机制中又引入的新的Archive归档机制。若是读者有兴趣能够阅读一下MySQL8.0新版本源码的storage\innobase\arch和 storage\innobase\clone目录下的代码。
1.1. redo Log相关参数
innodb_log_group_home_dir
该参数用来指定redo日志存放的路径,日志文件以ib_logfile[number]来命名。
innodb_log_files_in_group
虽然MySQL已经放弃了日志组的概念,但参数名依旧保留了下来以兼容之前的配置。该参数的含义为有多少个log文件(最少为2个)。
innodb_log_file_size
表示每一个文件的大小。
因此,总的redo Log的大小为 innodb_log_files_in_group * innodb_log_file_size.数据库
1.2. redo Log循环写
redo Log以顺序的方式写入文件,当所有文件写满的时候则回到第一个文件相应的起始位置进行覆盖写(但在作redo checkpoint时,也会更新第一个日志文件的头部checkpoint标记,因此严格来说也不算顺序写),在InnoDB内部,逻辑上Redo Log被看做一个文件,对应一个space id (InnoDB经过space的概念来组织物理存储,包括不一样的表,数据字典,redo,undo等)。安全
上图是以指定innodb_log_files_in_group为3的循环写的状况。app
2. Redo Log存储格式简介
尽管Redo Log有多个文件,但每一个文件的组成结构是同样的,只是有一些数据只会存在的第一个Log文件(ib_logfile0)的文件头中, 例如Buffer Pool flush checkpoint信息只会写在第一个log文件的文件头中。
2.1. 日志文件存储结构概览
(ib_logfile0 存储概览图)ide
(ib_logfile0 以外其它redo log文件的存储概览)
InnoDB也是采用WAL的机制来保证事务的持久性,从必定的意义上来讲,redo日志是顺序写,写入速度很快。数据库事务致使的数据修改进入到InnoDB存储层以后会将这些修改变动的记录存入redo log中,而后将数据的变动写入内存中的Page Pool中。InnoDB的后台线程会按照必定的规则(例如定时或者脏页的数量达到必定的比例)将脏页落盘,落盘后会记录下来当前redo Log中有多少变动日志已经实际存储到了实际的数据space文件中。redo log的总的写入量叫LSN(Log Secquence Numer)日志序列号,这个redo log变动实际写入到实际数据文件中的数量叫checkpoint LSN,表示的是有多少变动已经实际写入到了相应的数据文件中。 一旦数据库崩溃InnoDB开始恢复数据的时候,先读取checkpoint,而后从checkpoint所指示的LSN读取其以后的Redo日志进行数据恢复,从而减小Crash Recovery的时间。
比较前面两个概览图能够看到,checkpoint信息只是存储在第一个log文件头中。同时咱们看到日志头中有2个checkpoint block域。InnoDB是采用2个checkpoint了轮流写的方式来保证checkpoint的安全(并非一次写2份checkpoint, 而是轮流写)。 也因为Redo log是幂等的,应用一次和与应用两次都是同样的(在实际的应用Redo中,若是当前这一条log的lsn大于当前page的lsn,说明这一条log尚未被应用到当前page中去)。因此,即便某次checkpoint block写失败了,那么崩溃恢复的时候从上一次记录的checkpoint点开始恢复也能正确的恢复数据库事务。
2.2. Log File Header
(Log File Header存储结构)
Log Header Format:
这个字段之前用来标识当前Log文件属于哪一个日志组,如今新的意义是用来标识当前Log为文件的格式版本。例如若是为0则表示这个redo log是有5.7.9之前的MySQL生成的。
PAD:
没有任何含义,目前仅仅用来作一些对齐处理。
Start LSN:
这个字段用在Clone和Archive场景,与通常的持久性、崩溃恢复无关,这里不作讨论。
Creator:
存储的是建立这个log文件建立者的名称的字符串。
Left Bytes:
目前没有任何含义,仅仅是用来填充占位,以便让这个block达到512字节大小。
2.3. Log Checkpoint
(Checkpoint block储存概览)
checkpoint number:
checkpoint number能够理解为checkpoint域写盘的次数,每次写盘递增1,同时这个值取模2能够实现2个checkpoint域轮流写。
checkpoint LSN:
该字段标示小于这个Checkpoint LSN的日志记录都已经写入到了实际的数据文件中,Crash Recovery系统从Checkpoint LSN以后的第一个MTR记录开始进行数据恢复。
checkpoint offset:
Checkpoint LSN对应在Log files中的文件偏移量,这个用来对LSN和Offset之间转换进行校准。
Buf size:
MySQL系统内只对该字段执行了写入,并为进行读取而后进行相应的处理。它标识的是系统当前Log buffer的大小。
Left bytes:
目前没有任何含义,仅仅是用来填充占位,以便让这个block达到512字节大小。但在这里最后4个字节用来存放该checkpoint域的Checksum。spa
2.4. Log Block的存储格式
(Log Block的存储格式)
Log Block Number:
Log Block的编号,从1开始递增,达到最大值(0x3FFFFFFF+1)后再继续从1开始。
Data length:
写入到当前block的字节数,包含头部12字节的大小
Firsrt Record offset
本Block内第一个mtr记录的起始偏移量
log Block Checkpoint number
该block所处在的checkpoint no
Log Records:
一个block内能够存储多条mtr记录,一样一个mtr记录能够跨越多个block.
2.5. redo日志逻辑格式到物理格式的映射
上图是以指定innodb_log_files_in_group为2逻辑结构到物理结构的映射线程
上图中上层的为Redolog的逻辑结构,能够看做是内存中的log buffer, 下层的为redo Log的实际物理文件存储,因为版面的关系,咱们以innodb_log_files_in_group为2来作示例,每一个log文件中仅仅包含了2个log block(Log block的多少取决与设定的innodb_log_file_size)。
每产生一个mtr记录就将其append到log buffer中去,当log buffer落盘的时候会获取固定大小的数据写入到block的数据域。固然,若是buffer中剩余的数据不足以填满一个block的数据域,也会将其写入到一个新的block中,不足的数据自动不齐,block header中的data length字段会指出有效数据的数量。3d
2.6. MTR简介
MTR即Mini-transaction的缩写,字面意思小事物,相对逻辑事物而言,咱们把它称做物理事物。属于Innodb存储引擎的底层模块。主要用于锁和日志信息。InnoDB内部的上层模块会将事务操做转换成若干的MTR物理事务。至于上层的事务操做如何转换的MTR此操做,后续再另外单独介绍,本文只介绍一下MTR记录的格式。
每个MTR操做会产身一条MTR Record, 下一小节咱们会介绍一下MTR记录的格式。
2.7. MTR记录格式
用一句通俗的话来说,一条MTR记录表示的是对哪一个数据文件(space id)的哪一页(page)的页内某个偏移量(offset)位置作了什么改变(value).日志
(一条MTR记录的通用格式)
Type:
MTR记录的类型
Space ID:
该MTR记录修改了哪一个数据文件
Page Number
该MTR记录修改了哪一页
Record Payload:
根据Type的不一样,Payload内容格式也不相同,大小也不相同。后面会给出一个Type为MLOG_COMP_REC_INSERT大体的存储结构。
(MTR Type - MLOG_COMP_REC_INSERT)
最后列出一些MTR Record Type, 读者从名字应该就能看出这个Type的含义
/ one byte is written */
MLOG_1BYTE = 1,
/* 2 bytes ... /
MLOG_2BYTES = 2,
/ 4 bytes ... */
MLOG_4BYTES = 4,
/ 8 bytes ... */
MLOG_8BYTES = 8,
/* Record insert /
MLOG_REC_INSERT = 9,
/ Mark clustered index record deleted */
MLOG_REC_CLUST_DELETE_MARK = 10,
/ Mark secondary index record deleted */
MLOG_REC_SEC_DELETE_MARK = 11,
/* update of a record, preserves record field sizes /
MLOG_REC_UPDATE_IN_PLACE = 13,
/!< Delete a record from a page /
MLOG_REC_DELETE = 14,
/ Delete record list end on index page */
MLOG_LIST_END_DELETE = 15,
/ Delete record list start on index page */
MLOG_LIST_START_DELETE = 16,
/* Copy record list end to a new created index page /
MLOG_LIST_END_COPY_CREATED = 17,
/ Reorganize an index page in ROW_FORMAT=REDUNDANT */
MLOG_PAGE_REORGANIZE = 18,
/ Create an index page */
MLOG_PAGE_CREATE = 19,
/* mark a compact index record as the predefined minimum record /
MLOG_COMP_REC_MIN_MARK = 36,
/ create a compact index page */
MLOG_COMP_PAGE_CREATE = 37,
/* compact record insert /
MLOG_COMP_REC_INSERT = 38,
/* mark compact clustered index record deleted /
MLOG_COMP_REC_CLUST_DELETE_MARK = 39,orm
本文由京东商城数据库技术部王治提供。blog