标签:字节 存在 系统 row pre 重启 占用 做了 des
innoDB存储引擎中,需要在服务器故障重启后,能够准确的恢复所有已提交的数据,保证数据持久性;如某个事务在内存Buffer Pool中已被提交(脏页),但服务器突然故障,数据就丢失了;
为了解决这个问题,可以采用修改页面刷新到磁盘,但因为可能只修改了一条记录,没必要实时刷新浪费时间,而且修改的记录并不一定是连续的,随机IO刷新较慢。
可以将已提交事务修改的记录记录下来,即某个表空间中某页的某个偏移量的值更新为多少,这个记录的文件就称为redo log。相比刷新内存中的页面到磁盘,redo log刷新到磁盘的内容小了很多,而且是一个顺序写入磁盘的过程。
redo日志不止记录索引插入/更新记录等操作,还有执行这个操作影响到的其他动作,如页分裂新增目录项记录,修改页信息等对数据页做的任何修改等等。
和binlog区别:binlog记录的是页已经正式落盘的操作且是包含所有存储引擎,redo日志记录InnoDB引擎下仍然在buffer pool中的操作,用于系统奔溃时恢复脏页。
type:类型
redo
日志类型。redo
日志类型space id:表空间
page number:页号
data:真实数据(以MLOG_COMP_REC_INSERT为例)
offset:记录前一条记录在页面中的位置,方便修改页面中的记录链表,前一条记录维护的next_record属性
len:类型为MLOG_WRITE_STRING时才有的,表示具体数据占用的字节数
Mini-Transaction(mtr)是对底层页面中的一次原子访问的过程(如MAX_ROW_ID
生成/索引记录插入)。一个事务可以包含多个mtr,一个mtr包含多条redo日志。
针对要保证原子性的操作必须以组的形式来记录redo日志,以插入一条记录为例,当出现页分裂时,会涉及到申请数据页,改动系统页,改各种段/区的统计信息,free等链表的信息,新增目录项记录等等操作,要么全都执行完成要么全都没执行。
划分日志组:通过为这一系列动作的日志的最后一条日志后添加一个特别的日志,类型为MLOG_MULTI_REC_END:31
作为结尾。
如果某个原子操作只有一条日志记录,那么给这条日志类型的第一个比特位设为1,不然就是产生了一系列日志。
MySQL使用512字节的页来记录redo日志,这种页被称为block
,block
由log block header
,log block trailer
和log block body
组成,header和trailer存储页的管理信息。
服务器启动时会先向系统申请一片连续的内存作为redo日志缓冲区log buffer,以两个事务为例,事务T1和T2是交替执行的,所以可能是交替存储到log buffer的。它们各自包含两个mtr,每个mtr在运行过程中,会先将redo log存在一个地方,等到这个mtr执行结束,就会将这个mtr产生的所有redo日志全部复制到log buffer,一定时间后才会冲刷到磁盘。
向log buffer
中写入日志是顺序的,所以block不会出现碎片空间,InnoDB提供一个全局变量buf_free
来指明后续写入的redo日志应该往block的哪个位置中写入,即从这个位置开始后面都是空闲的。
当修改buffer pool
中的页时,会将这个脏页的控制块插入到flush链表中,控制块存储了两个变量:oldest_modification
被加载到buffer pool
中第一次修改mtr开始时对应的lsn值,newest_modification
每次mtr修改结束时对应的lsn值;控制块按照oldest_modification
从大到小排序存储。
一个mtr可能修改多个页,所以多个控制块的oldest_modification
/newest_modification
可能一样。
在MySQL的数据目录下,(由innodb_log_group_home_dir
确定存储位置,由名称可知存储形式是一个日志文件组)名为ib_logfile0
...n的文件,文件个数决定文件名称后缀,由系统参数innodb_log_files_in_group
确定文件个数,每个文件的大小由innodb_log_file_size
指定。
每个ib_logfile
顺序循环写入log buffer
中的block,会出现文件被覆盖的现象。
前2048个字节(4个block):存储管理信息
log file header:存储当前文件的redo日志版本,文件开始的LSN值等等
checkpoint1:标记日志文件可覆盖信息
没用
checkpoint2
后面的字节:存储block内容,会被循环使用
Log Sequeue Number(lsn):InnoDB记录已写入的redo log量的全局变量,包括log buffer写入的日志,初始值为8704,此时日志文件的偏移量为2048字节。
flushed_to_disk_lsn:刷新到磁盘中的redo日志量的全局变量
buf_next_to_write:标记已有哪些log buffer中的日志被刷盘的全局变量
innodb_flush_log_at_trx_commit=?:表示用户线程提交时需要将该事务执行过程中产生的所有redo日志刷盘到磁盘(1)还是交给后台线程操作(0),或者先写入到缓冲区中(2)。
判断某些redo日志占用的磁盘空间是否可以被覆盖,即它对应的脏页是否已经刷新到磁盘
checkpoint_lsn
:代表当前系统中可以被覆盖(脏页已经被刷盘)的redo日志总量,初始值为8074。
checkpoint步骤:
oldest_modification
值对应的lsn之前的日志都是可以被覆盖掉的,因为flush链表不存储已经被刷盘的脏页),赋值给checkpoint_lsn
;checkpoint_lsn
对应的redo日志文件组偏移量checkpoint_offset
及此次checkpoint
的编号(总共做了多少次checkpoint,递增)checkpoint_no
写到日志文件头部的checkpoint1/2
中恢复奔溃发生时,flush链表中还未写入磁盘的脏页更改。
确定恢复的起点:比较日志中文件中checkpoint1
和checkpoint2
中最大的checkpoint_no,然后从对应的checkpoint_lsn
(之前的都是可覆盖的,说明已经被刷盘了)开始恢复
确定恢复的终点:比较每个日志文件log block header
的LOG_BLOCK_HDR_DATA_LEN
属性,如果不为512则说明是最后一个填充的日志文件
恢复方法
hash(表空间id+页号)
,相同值的放在一个slot中,并根据生成时间排序链表形式连接,这样可以一次修复一个页面,避免多余的随机IOnewest_modification
是否大于checkpoint_lsn
,如果是那么就不需要执行小于newest_modification
的FIL_PAGE_LSN
的redo日志了标签:字节 存在 系统 row pre 重启 占用 做了 des
原文地址:https://www.cnblogs.com/hangzhi/p/11427538.html